diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..ff0f39e73 --- /dev/null +++ b/.clang-format @@ -0,0 +1,18 @@ +Standard: Cpp11 +IndentWidth: 4 +AccessModifierOffset: -4 +UseTab: Never +BinPackParameters: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +AlwaysBreakTemplateDeclarations: true +NamespaceIndentation: None +PointerBindsToType: true +SpacesInParentheses: false +BreakBeforeBraces: Attach +ColumnLimit: 100 +Cpp11BracedListStyle: false +SpacesBeforeTrailingComments: 1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..3e46c0a0a --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +.DS_Store +*.xcodeproj +*.o +*.actual.png +*.diff.png +*.pyc +/android/debug +/android/sdk +/android/**/.classpath +/android/**/.project +/android/**/.settings/ +/mason_packages +/config/*.gypi +/build +/macosx/build +/linux/build +/ios/build +/ios/app/build +/test/build +/gyp/build +/gyp/java +/test/node_modules +/test/fixtures/*/*_actual.* +/test/fixtures/api/1.png +/test/fixtures/api/2.png +/test/fixtures/database/*.db +/include/mbgl/shader/shaders.hpp +/src/shader/shaders_gl.cpp +/src/shader/shaders_gles2.cpp +/bin/style.bin.js +*~ + +/ios/benchmark/assets/tiles/mapbox.mapbox-streets-v6/ +/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2/ +/ios/benchmark/assets/glyphs/DIN Offc Pro*/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..d84cfecbc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,23 @@ +[submodule "test/suite"] + path = test/suite + url = https://github.com/mapbox/mapbox-gl-test-suite.git + +[submodule ".mason"] + path = .mason + url = https://github.com/mapbox/mason.git + +[submodule "styles"] + path = styles + url = https://github.com/mapbox/mapbox-gl-styles.git + +[submodule "test/ios/KIF"] + path = test/ios/KIF + url = https://github.com/kif-framework/KIF.git + +[submodule "platform/ios/vendor/SMCalloutView"] + path = platform/ios/vendor/SMCalloutView + url = https://github.com/nfarina/calloutview.git + +[submodule "src/mbgl/util/geojsonvt"] + path = src/mbgl/util/geojsonvt + url = https://github.com/mapbox/geojson-vt-cpp diff --git a/.mason b/.mason new file mode 160000 index 000000000..d8597d944 --- /dev/null +++ b/.mason @@ -0,0 +1 @@ +Subproject commit d8597d944533dbb5e28d08dfdba22a82c93171b7 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..9c65614df --- /dev/null +++ b/.travis.yml @@ -0,0 +1,100 @@ +language: android + +sudo: false + +matrix: + exclude: + - os: linux + include: + - os: linux + env: FLAVOR=linux CXX=g++-4.9 BUILDTYPE=Release + addons: + apt: + sources: [ 'ubuntu-toolchain-r-test' ] + packages: [ 'gdb', 'g++-4.9', 'gcc-4.9', 'libllvm3.4', 'xutils-dev', 'libxxf86vm-dev', 'x11proto-xf86vidmode-dev', 'mesa-utils' ] + - os: linux + env: FLAVOR=linux CXX=clang++-3.5 BUILDTYPE=Debug + addons: + apt: + sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ] + packages: [ 'gdb', 'clang-3.5', 'libstdc++-4.9-dev', 'libstdc++6', 'libllvm3.4', 'xutils-dev', 'libxxf86vm-dev', 'x11proto-xf86vidmode-dev', 'mesa-utils' ] + - os: linux + env: FLAVOR=linux CXX=clang++-3.5 BUILDTYPE=Release + addons: + apt: + sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ] + packages: [ 'gdb', 'clang-3.5', 'libstdc++-4.9-dev', 'libstdc++6', 'libllvm3.4', 'xutils-dev', 'libxxf86vm-dev', 'x11proto-xf86vidmode-dev', 'mesa-utils' ] + - os: osx + osx_image: xcode6.4 + env: FLAVOR=osx BUILDTYPE=Debug + - os: osx + osx_image: xcode6.4 + env: FLAVOR=ios BUILDTYPE=Release + - os: linux + env: FLAVOR=android ANDROID_ABI=arm-v7 BUILDTYPE=Release + android: + components: [ 'build-tools-23', 'android-23', 'extra-android-m2repository' ] + addons: + apt: + packages: [ 'lib32stdc++6' ] + - os: linux + env: FLAVOR=android ANDROID_ABI=arm-v7 BUILDTYPE=Debug + android: + components: [ 'build-tools-23', 'android-23', 'extra-android-m2repository' ] + addons: + apt: + packages: [ 'lib32stdc++6' ] + - os: linux + env: FLAVOR=android ANDROID_ABI=arm-v8 BUILDTYPE=Release + android: + components: [ 'build-tools-23', 'android-23', 'extra-android-m2repository' ] + addons: + apt: + packages: [ 'lib32stdc++6' ] + - os: linux + env: FLAVOR=android ANDROID_ABI=x86 BUILDTYPE=Release + android: + components: [ 'build-tools-23', 'android-23', 'extra-android-m2repository' ] + addons: + apt: + packages: [ 'lib32stdc++6' ] + +env: + global: + - TERM: dumb + # AWS + - secure: "MZHblLZXG/jWf2w0ZFlxCLDwx2qtGgRDODQyg1BR7JIuMz6AtWv8XR/sUczWLbiABCL0a/NzJF1g4v2pI7X69IntcjOdIABBgTh7++6+1TJ0Kp8viEltb55nQG3lHy/R6fOaI7Pj9tuCX0PCRtGA5C/fGnodLGEjy3RVOJ09ln0=" + - secure: "KaSQbhgjtV7ZCkesHmvrNsbQVjk5SPfGKB1VkWenRGYhLF45HpSRNwSxMQddZ566Pg7qIFgF1iWl/B0QW3B6AWL5WmzQ5AOJgwS876pNIc/UT7ubMPtgAtjpvw1bQvQP3B8MrB+3OE5c6tD+a3LhR9krV//dOsfErR5Yy+3Mbkc=" + # Access Token + - secure: "RiBIBfVhhaMjU5ksuwJO3shdvG9FpinBjdSv4co9jg9171SR8edNriedHjVKSIeBhSGNmZmX+twS3dJS/By6tl/LKh9sTynA+ZAYYljkE7jn881B/gMrlYvdAA6og5KvkhV1/0iJWlhuZrMTkhpDR200iLgg3EWBhWjltzmDW/I=" + # Testmunk + - secure: "CHBiUM60TolDbQnn+4IRA/tvOKwKs3g9EDvv8YHSJMg3FuHmjKQkprBasvxf3hnTXg4WLZEubmeDcyJ6RRzPP5mMSr/hksYl0pSjj/6TUecE5fHPVVeN7txVqkpOBf9i45Y+iBUQMjBb1NnDK3pHXxpnAs1Q/pe7vReErj4GF1U=" + # iOS code signing + - secure: "I6Iu75X1E+js5tzijtKi1EGtIuBcA4/25nDYe0svV4HAtujY71ZJZ4eB6355CKhFXpLXrF3i7eKVX3v+zWS0QROPEWacgsqsvNg+Ba9cnznW/faUSOYekCfhzWd/6reYDM7KzKAQwSUHLk9JIWK/kkmi4r+vVJK7h+tjPllK5YA=" + - IOS_APP_NAME="Mapbox GL" + - 'IOS_DEVELOPER_NAME="iPhone Distribution: Mapbox, Inc."' + - IOS_PROFILE_NAME="ios-in-house" + - secure: "nQqSM8rd7OHtV4MqmNqVnkrVHqxKqQsaWRYk4/nPdhbeVWtTtkk0df711LrF1TUtbEPEewHxYUvTZ/UXmwJNeoKdzTHavI8hnatRkgjyxGERPn1il1Otelht9I+LQQHf+plrpRjVWBrNIW0Zox1B3cqn6d3NglpbXrEQ2EjYGNA=" + - KIF_SCREENSHOTS="${TRAVIS_BUILD_DIR}/screenshots" + +before_install: +- source ./scripts/travis_helper.sh + +install: +- ./scripts/${FLAVOR}/install.sh + +script: +- ./scripts/${FLAVOR}/run.sh + +after_failure: +- "[ -f ./scripts/${FLAVOR}/after_failure.sh ] && ./scripts/${FLAVOR}/after_failure.sh" + +after_script: +- "[ -f ./scripts/${FLAVOR}/after_script.sh ] && ./scripts/${FLAVOR}/after_script.sh" + +notifications: + slack: + secure: HHQYr7sF8M1SzoWSqgKVYtwAgGdLLCyTMsQjFhEEQNYO92ZwURE5s03qWTGH5k8+4Yqn26yrXt3NztLC4JIOpcGervN2mSZyq4dZgFTcWEd61igw0qwSenlwvFfbE1ASK/KYCzfyn9MIfHN+ovwLoRxXZkPwinKDvl3DXjBaFNg= + +git: + submodules: false diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py new file mode 100644 index 000000000..be5e3a5c1 --- /dev/null +++ b/.ycm_extra_conf.py @@ -0,0 +1,162 @@ +# Version of .ycm_extra_conf.py sample file adapted +# for the Mapbox GL Native project. +# +# This file is NOT licensed under the GPLv3, which is the license for the rest +# of YouCompleteMe. +# +# Here's the license text for this file: +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# For more information, please refer to + +import os +import subprocess +import sys +import ycm_core + + +def DirectoryOfThisScript(): + return os.path.dirname(os.path.abspath(__file__)) + + +default_flags = [ + '-std=c++14', + '-I%s' % (os.path.join(DirectoryOfThisScript(), 'src')), + '-I%s' % (os.path.join(DirectoryOfThisScript(), 'include')), +] + + +def MakeRelativePathsInFlagsAbsolute(flags, working_directory): + if not working_directory: + return list(flags) + + new_flags = [] + make_next_absolute = False + path_flags = ['-isystem', '-I', '-iquote', '--sysroot='] + + for flag in flags: + new_flag = flag + + if make_next_absolute: + make_next_absolute = False + if not flag.startswith('/'): + new_flag = os.path.join(working_directory, flag) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + + if flag.startswith(path_flag): + path = flag[len(path_flag):] + new_flag = path_flag + os.path.join(working_directory, path) + break + + if new_flag: + new_flags.append(new_flag) + + return new_flags + + +def FlagsForFileDefault(): + return { + 'flags': default_flags, + 'do_cache': False, + } + + +def FlagsForFileLinux(filename): + working_directory = os.path.join('build', 'linux') + + if not os.path.exists(os.path.join(DirectoryOfThisScript(), working_directory)): + return FlagsForFileDefault() + + relative_source_path = filename.replace(DirectoryOfThisScript() + '/', '') + relative_obj_path = os.path.splitext(relative_source_path)[0] + '.o' + + make_cmd = 'make -pn |grep %s: |grep GYP_CXXFLAGS |cut -d\' \' -f4-' % relative_obj_path + + p = subprocess.Popen([make_cmd], shell=True, stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + + if p.returncode: + return FlagsForFileDefault() + + flags = stdout.split(' ') + flags_relative = MakeRelativePathsInFlagsAbsolute(flags, os.path.join(DirectoryOfThisScript(), working_directory)) + flags_final = [flag for flag in flags_relative if flag.startswith("-")] + + return { + 'flags': flags_final, + 'do_cache': True, + } + + +def FlagsForFileDarwin(filename): + working_directory = os.path.join('build', 'osx') + + if not os.path.exists(os.path.join(DirectoryOfThisScript(), working_directory)): + return FlagsForFileDefault() + + relative_source_path = filename.replace(DirectoryOfThisScript() + '/', '') + relative_obj_path = os.path.splitext(relative_source_path)[0] + '.o' + + make_cmd = 'make -pn |grep "%s :=" |grep "NDEBUG" |tail -n 1 | cut -d\' \' -f4-' % relative_obj_path + + p = subprocess.Popen([make_cmd], shell=True, stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + + if p.returncode: + return FlagsForFileDefault() + + flags = stdout.split(' ') + flags_relative = MakeRelativePathsInFlagsAbsolute(flags, os.path.join(DirectoryOfThisScript(), working_directory)) + flags_final = [flag for flag in flags_relative if flag.startswith("-")] + + # Append OSX sysroot SDK path + xcrun_cmd = 'xcrun --show-sdk-path' + + p = subprocess.Popen([xcrun_cmd], shell=True, stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + + if p.returncode: + return FlagsForFileDefault() + + flags_final.append('-isysroot ' + stdout) + + return { + 'flags': flags_final, + 'do_cache': True, + } + + +def FlagsForFile(filename, **kwargs): + if sys.platform.startswith('linux'): + return FlagsForFileLinux(filename) + + if sys.platform.startswith('darwin'): + return FlagsForFileDarwin(filename) + + return FlagsForFileDefault() diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..45b1959a4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,72 @@ +# Changelog + +## 0.5.1 + +### iOS + +- Added support for CocoaPods 0.38.0. ([#1876](https://github.com/mapbox/mapbox-gl-native/pull/1876)) + +## 0.5.0 + +### Core + +- Support for runtime marker imagery. ([#941](https://github.com/mapbox/mapbox-gl-native/pull/941)) +- Added `Map::fitBounds()` for region-based viewport setting. ([#1092](https://github.com/mapbox/mapbox-gl-native/issues/1092)) +- Added a raster satellite bundled style and improved raster rendering. ([#963](https://github.com/mapbox/mapbox-gl-native/issues/963)) +- Improved round line joins for semi-transparent lines. ([#1839](https://github.com/mapbox/mapbox-gl-native/pull/1839)) +- Improved map render lifecycle notifications. ([#1026](https://github.com/mapbox/mapbox-gl-native/issues/1026)) +- Fixed a bug that caused annotations not to show at zoom level zero. ([#1279](https://github.com/mapbox/mapbox-gl-native/issues/1279)) +- Fixed a bug with the ordering of shape layers. ([#1866](https://github.com/mapbox/mapbox-gl-native/pull/1866)) +- Other bug fixes and performance improvements. + +### iOS + +- **Breaking:** Headers now make use of lightweight generics, eliminating many unnecessary casts when working with annotations in Swift 2.0 in Xcode 7. ([#1711](https://github.com/mapbox/mapbox-gl-native/pull/1711)) +- **Breaking:** `-mapView:symbolNameForAnnotation:` has been removed from the `MGLMapViewDelegate` protocol. Implement `-mapView:imageForAnnotation:` instead, which accepts images at runtime. ([#941](https://github.com/mapbox/mapbox-gl-native/pull/941)) +- **Breaking:** `MGLMapView.direction` is now expressed in terms of degrees clockwise from true north, as indicated in the documentation, rather than counterclockwise. ([#1789](https://github.com/mapbox/mapbox-gl-native/pull/1789)) +- A Satellite style showing Mapbox Satellite imagery is now bundled with Mapbox GL. ([#1845](https://github.com/mapbox/mapbox-gl-native/pull/1845)) +- Improved `UIView` tracking to the map. ([#1813](https://github.com/mapbox/mapbox-gl-native/pull/1813)) +- Delegate method `-[MGLMapViewDelegate mapView:didFailToLocateUserWithError:]` now works. ([#1608](https://github.com/mapbox/mapbox-gl-native/pull/1608)) +- It is now possible to fit the map’s viewport to a coordinate bounding box via `-[MGLMapView setVisibleCoordinateBounds:animated:]` or to a specific set of coordinates via `-[MGLMapView setVisibleCoordinates:count:edgePadding:animated:]`. ([#1783](https://github.com/mapbox/mapbox-gl-native/pull/1783), [#1795](https://github.com/mapbox/mapbox-gl-native/pull/1795)) +- The logo and ℹ️ no longer disappear or get distorted after embedding MGLMapView in a different view, and you can now access these subviews directly via properties on MGLMapView. ([#1779](https://github.com/mapbox/mapbox-gl-native/pull/1779), [#1815](https://github.com/mapbox/mapbox-gl-native/pull/1815)) +- Raster tiles now look sharper midway between two zoom levels. ([#1843](https://github.com/mapbox/mapbox-gl-native/pull/1843)) +- Resetting the map rotation to north no longer also resets the user location tracking mode. ([#1809](https://github.com/mapbox/mapbox-gl-native/pull/1809)) +- `-[MGLMapView convertPoint:toCoordinateFromView:]` now returns accurate coordinates on iPhone 6. ([#1827](https://github.com/mapbox/mapbox-gl-native/pull/1827)) +- Fixed an issue in which `-[MGLMapView direction]` would sometimes return 360 instead of 0. ([#1829](https://github.com/mapbox/mapbox-gl-native/pull/1829)) +- Build against iOS 8.4. ([#1868](https://github.com/mapbox/mapbox-gl-native/pull/1868)) + +## 0.4.0 + +### Core + +- Support for polyline and polygon shape annotations. ([#1655](https://github.com/mapbox/mapbox-gl-native/issues/1655)) +- Improved placement and density of labels. ([#1666](https://github.com/mapbox/mapbox-gl-native/issues/1666), [blog](https://www.mapbox.com/blog/better-label-placement-mapbox-mobile/)) +- Improved z-ordering appearance of point markers. ([#988](https://github.com/mapbox/mapbox-gl-native/issues/988)) +- Fixed an issue in which certain features, such as roundabouts, were not rendered completely. ([#1725](https://github.com/mapbox/mapbox-gl-native/issues/1725)) +- Many bug fixes and performance and stability improvements. +- Improved tests. + +### iOS + +- **Breaking:** `MGLMapView` no longer manages Mapbox access tokens directly; an access token cannot be passed in when initializing the map view. Instead, set `MGLMapboxAccessToken` to your access token in your app’s `Info.plist` file, or call `+[MGLAccountManager setAccessToken:]` before initializing the map view. If you were setting the access token inside an Interface Builder inspectable, also remove it from the User Defined Runtime Attributes section of the Identity inspector. ([#1553](https://github.com/mapbox/mapbox-gl-native/issues/1553)) +- **Breaking:** `MGLAccountManager`'s `-setMapboxMetricsEnabledSettingShownInApp:` has been removed. If you implement a Mapbox Metrics switch inside your app, instead of inside a Settings bundle, set `MGLMapboxMetricsEnabledSettingShownInApp` to `YES` in the `Info.plist` file. ([#1553](https://github.com/mapbox/mapbox-gl-native/issues/1553)) +- **Breaking:** `MGLMapView`'s `-mapID` has been renamed to `-styleID`. ([#1561](https://github.com/mapbox/mapbox-gl-native/issues/1561)) +- Headers have been audited for nullability, improving type safety in both Objective-C and Swift 1.2 when compiling with Xcode 6.3 or above. ([#1578](https://github.com/mapbox/mapbox-gl-native/issues/1578)) +- Fixed an issue in which the map would sometimes spin 180° while rotating the map with two fingers. ([#1453](https://github.com/mapbox/mapbox-gl-native/issues/1453)) +- Added a shortcut to the Mapbox Metrics switch in `MGLMapView`'s action sheet that is attached to the ℹ️ button. ([#1611](https://github.com/mapbox/mapbox-gl-native/issues/1611)) +- `MGLMapView` now supports Interface Builder designables. When you add an `MGLMapView` to a storyboard, it displays instructions for getting set up directly on the storyboard canvas. ([#1573](https://github.com/mapbox/mapbox-gl-native/issues/1573)) +- The default title for the user location annotation is now “You Are Here”. You can customize the title by setting `mapView.userAnnotation.title`. ([#1559](https://github.com/mapbox/mapbox-gl-native/issues/1559)) +- Internal use of the Reachability library has been cleaned up so that your app can include its own copy of Reachability. ([#1718](https://github.com/mapbox/mapbox-gl-native/issues/1718)) +- Now distribute a binary stripped of debugging symbols by default with an optional, secondary symbols build. ([#1650](https://github.com/mapbox/mapbox-gl-native/issues/1650)) + +## 0.3.1 + +- Temporarily removed `IBDesignable` support on iOS. + +## 0.3.0 + +- Initial iOS beta release. + +Known issues: + +- None. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..3348bf902 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,11 @@ +# Contributing + +If you have a usage question for a product built on Mapbox GL (such as Mapbox Mobile toolkits like our SDKs), please visit https://www.mapbox.com/help/. + +If you want to contribute code: + +1. Please familiarize yourself with the [install process](INSTALL.md). + +1. Ensure that the [existing issues](https://github.com/mapbox/mapbox-gl-native/issues?utf8=✓&q=) don't already cover your question or contribution. + +1. Pull requests gladly accepted. diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 000000000..ac5bb8667 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,347 @@ +# Install + +This document describes the process for setting up Mapbox GL for development _on the framework itself_. + +# Depends + + - Modern C++ compiler that supports `-std=c++14` (clang++ 3.5 or later or g++-4.9 or later) + - [Boost headers](http://boost.org/) + - [`zlib`](http://www.zlib.net/) + - [`libpng`](http://www.libpng.org/pub/png/libpng.html) + - [`libuv 0.10+`](https://github.com/joyent/libuv) + - [`glfw 3.1+`](http://www.glfw.org/) + - [`libcurl`](http://curl.haxx.se/libcurl/) (depends on OpenSSL; Linux only) + - Apple Command Line Tools (for build on OS X; available at [Apple Developer](https://developer.apple.com/downloads)) + - `pkg-config` (for build only) + - [Homebrew](http://brew.sh) (for building on OS X) + - [xcpretty](https://github.com/supermarin/xcpretty) (for building on OS X) + - [Cask](http://caskroom.io/) (for building Android on OS X) + - Python 2.x (for build only) + +# Build instructions + +We try to link to as many system-provided libraries as possible. When these are unavailable or too outdated, we run a thin build-script layer called [Mason](https://github.com/mapbox/mason) to automate builds, and load precompiled binary packages when possible. + +Be sure to pull down all submodules first: + + git submodule init + git submodule update + +## OS X + +This process gives you either a native OS X windowed app or a Linux desktop app with a map view for development purposes, built on an OS X host system. + +### Build + +ImageMagick is required for tests. It's recommended to install it with [Homebrew](http://brew.sh/) via `brew install imagemagick`. + +To create projects, you can run: + +- `make xproj`: Creates an Xcode project with OS X-specific handlers for HTTP downloads and settings storage. It uses [GLFW](http://www.glfw.org) for window handling. +- `make lproj`: Creates an Xcode project with platform-independent handlers for downloads and settings storage. This is what is also being built on Linux. +- `make osx run-osx`: Builds and runs the OS X application on the command line with `xcodebuild`. +- `make linux run-linux`: Builds and runs the Linux application with `make`. + +Note that you can't have more than one project in Xcode open at a time since the static library project is shared across the OS X, Linux and iOS project. + +### Test + +- `make test-*` Builds and runs all tests. You can specify individual tests by replacing * with their name. + +### Usage + +- Press `S` to cycle through bundled styles +- Press `X` to reset the transform +- Press `N` to reset north +- Press `Tab` to toggle debug information +- Press `C` to toggle symbol collision debug boxes +- Press `Esc` to quit +- Press `1` through `6` to add increasing numbers of point annotations for testing + +### Target + +OS X 10.9+ + + +## iOS (Test App) + +This process gives you a native iOS app for simulator or device which compiles the source to GL within it for fastest turnaround time during development. Normal, production use of the library is via a precompiled binary linked into the app target. + +Developing for iOS implies an OS X host system. + +### Build + +If you want to build from source and/or contribute to development of the project, run `make iproj`, which will create and open an Xcode project which can build the entire library from source as well as an Objective-C test app. If you don't have an Apple Developer account, change the destination from "My Mac" to a simulator such as "iPhone 6" before you run and build the app. + +### Test + +You can run `make itest` to run the included integration tests. Requires `gem install xcpretty`. If you want to run the tests in Xcode instead, first `make ipackage` to create a local static library version, then open `test/ios/ios-tests.xcodeproj`, and lastly `Command + U` on the `Mapbox GL Tests` application target. + +### Usage + +- Pan to move +- Pinch to zoom +- Use two fingers to rotate +- Double-tap to zoom in one level +- Two-finger single-tap to zoom out one level +- Double-tap, long-pressing the second, then pan up and down to "quick zoom" (iPhone only, meant for one-handed use) +- Use the debug menu to add test annotations, reset position, and toggle debug info. + +## iOS (Your App) + +**If you want a production version of this project, use [Mapbox Mobile](http://mapbox.com/mobile).** + +This section is for people contributing to Mapbox GL directly in the context of their own app. + +### Build + +1. Install [appledoc](http://appledoc.gentlebytes.com/appledoc/) 2.2v963 for API docs generation (only this exact version works right now ([#2117](https://github.com/mapbox/mapbox-gl-native/issues/2117)). + + ``` + curl -L -o appledoc.zip https://github.com/tomaz/appledoc/releases/download/v2.2-963/appledoc.zip + unzip appledoc.zip + cp appledoc /usr/local/bin + cp -Rf Templates/ ~/.appledoc + ``` + +1. Run `make ipackage`. The packaging script will produce the statically-linked `libMapbox.a`, `Mapbox.bundle` for resources, a `Headers` folder, and a `Docs` folder with HTML API documentation. + +### Test + +In the context of your own app, you can now either: + +#### CocoaPods + +Currently, until [#1437](https://github.com/mapbox/mapbox-gl-native/issues/1437) is completed, to install a _development version_ of Mapbox GL using CocoaPods you will need to build it from source manually per above. + +1. Zip up the build product. + + cd build/ios/pkg/static + ZIP=mapbox-ios-sdk.zip + rm -f ../${ZIP} + zip -r ../${ZIP} * + +1. Modify a custom `Mapbox-iOS-SDK.podspec` to download this zip file. + + {...} + + m.source = { + :http => "http://{...}/mapbox-ios-sdk.zip", + :flatten => true + } + + {...} + +1. Update your app's `Podfile` to point to the `Mapbox-iOS-SDK.podspec`. + + pod 'Mapbox-iOS-SDK', :podspec => 'http://{...}/Mapbox-iOS-SDK.podspec' + +1. Run `pod update` to grab the newly-built library. + +#### Binary + +1. Built from source manually per above. + +1. Copy the contents of `build/ios/pkg/static` into your project. It should happen automatically, but ensure that: + + - `Headers` is in your *Header Search Paths* (`HEADER_SEARCH_PATHS`) build setting. + - `Mapbox.bundle` is in your target's *Copy Bundle Resources* build phase. + - `libMapbox.a` is in your target's *Link Binary With Libraries* build phase. + +1. Add the following Cocoa framework dependencies to your target's *Link Binary With Libraries* build phase: + + - `CoreTelephony.framework` + - `GLKit.framework` + - `ImageIO.framework` + - `MobileCoreServices.framework` + - `QuartzCore.framework` + - `SystemConfiguration.framework` + - `libc++.dylib` + - `libsqlite3.dylib` + - `libz.dylib` + +1. Add `-ObjC` to your target's "Other Linker Flags" build setting (`OTHER_LDFLAGS`). + +### Target + +Devices: iPhone 4S and above (5, 5c, 5s, 6, 6 Plus), iPad 2 and above (3, 4, Mini, Air, Mini 2, Air 2), iPod touch 5th gen and above + +iOS: 7.0+ + + +## Linux + +We are using Ubuntu for development. While the software should work on other distributions as well, we are not providing explicit build instructions here. + +This process gives you a Linux desktop app built on a Linux host system. + +### Build + +Install GCC 4.9+ if you are running Ubuntu 14.04 or older. Alternatively, you can also use [Clang 3.5+](http://llvm.org/apt/). + + sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test + sudo apt-get update + sudo apt-get install gcc-4.9 g++-4.9 + export CXX=g++-4.9 + +Ensure you have git and other build essentials: + + sudo apt-get install curl git build-essential zlib1g-dev automake \ + libtool xutils-dev make cmake pkg-config python-pip \ + libcurl4-openssl-dev libpng-dev libsqlite3-dev \ + libllvm3.4 + +Install glfw3 dependencies: + + sudo apt-get install libxi-dev libglu1-mesa-dev x11proto-randr-dev \ + x11proto-xext-dev libxrandr-dev \ + x11proto-xf86vidmode-dev libxxf86vm-dev \ + libxcursor-dev libxinerama-dev + +Then, you can then proceed to build the library: + + git submodule update --init + make linux + +Set an access token as described below, and then run: + + make run-linux + +### Test + +- `make test-*` Builds and runs all tests. You can specify individual tests by replacing * with their name. + +### Usage + +- Press `S` to cycle through bundled styles +- Press `X` to reset the transform +- Press `N` to reset north +- Press `Tab` to toggle debug information +- Press `C` to toggle symbol collision debug boxes +- Press `Esc` to quit +- Press `1` through `6` to add increasing numbers of point annotations for testing + +### Target + +Ubuntu + + +## Android + +### Build (Linux Host) + +Install a few build dependencies: + + apt-get install -y make git build-essential automake \ + libtool make cmake pkg-config lib32stdc++6 lib32z1 + +Install Oracle JDK 7 (requires license agreement) from http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html + + export JAVA_HOME="/dir/to/jdk1.7.0_71" + +Install the [Android NDK Revision 10e](https://developer.android.com/tools/sdk/ndk/index.html). + + export ANDROID_NDK_PATH="/dir/to/android-ndk-r10e" + +Install the Android SDK. We recommend doing this by way of [Android Studio](https://developer.android.com/sdk/installing/studio.html). + + export ANDROID_HOME="/dir/to/android-sdk-linux" + +Run: + + make android + +You can then open `android/java` in Android Studio via "Import Non-Android Studio Project". + +### Build (OS X Host) + +Install Oracle JDK 7+: + + brew cask install java + +Install the [Android NDK Revision 10e](https://developer.android.com/tools/sdk/ndk/index.html) for 64-bit OS X: + + brew install android-ndk + +This will also install the dependency `android-sdk`. + +Install [Android Studio](https://developer.android.com/sdk/installing/studio.html): + + brew cask install android-studio + android + +By default, the SDK will be installed to `/usr/local/opt/android-sdk`. If you open Android Studio at this point, you may get an error message telling you that it can't find a JVM, it's because you installed a custom Java VM from Oracle. Follow [these instructions](http://tools.android.com/recent/androidstudio1rc3_releasecandidate3released) to start Android Studio. You'll wind up setting these environment variables in your .bash_profile or similar: + + echo "export ANDROID_HOME=`brew --prefix android-sdk`" >> .bash_profile + echo "export ANDROID_NDK_PATH=`brew --cellar android-ndk`/r10e" >> .bash_profile + # Replace with something like /Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk + echo "export JAVA_HOME=" >> .bash_profile + echo "export STUDIO_JDK=$JAVA_HOME" >> .bash_profile + +Run: + + make android + open -a Android\ Studio + +You can then open `android/java` in Android Studio via "Import Non-Android Studio Project". + +### Setting up Android emulator + +If you want to run the test app in the emulator, we recommend the x86 build because it will run a lot faster. + +First ensure you have an `MAPBOX_ACCESS_TOKEN` environment variable set, as described below. Then, create an x86 build: + + ANDROID_ABI=x86 make android + +In Android Studio, create an x86 AVD (Android Virtual Device): + +- Open AVD Manager via the Tools menu -> Android -> AVD Manager +- Click "Create Virtual Device" at the bottom on AVD Manager window +- Select one of the device profiles, for example the Nexus 4 +- Click "Next" +- Select a Lollipop or Kitkat release with ABI of x86. If the line is greyed out click Download to download the OS files. +- Click "Next" +- Under "Emulated Performance" check "Host GPU" and uncheck "Store a snapshot for faster startup" +- Click "Finish" +- Close the AVD Manager + +Now when you run or debug the Android project you will see a window "Choose Device". Select your new AVD from drop down under "Launch emulator". If you select "Use same device for future launches" Android Studio will remember the selection and not ask again. + +### Running on a hardware device + +First read the [Google documentation](http://developer.android.com/tools/device.html) to set up your device and your OS to connect to the device. + +When you plug your device in and then run or debug the Android project you will see a window "Choose Device". Choose your device from the "Choose a running device" list. + +If your device does not show up, you have not set it up properly. Double check the [Google documentation](http://developer.android.com/tools/device.html). + +### Target + +Devices running Android 4.0+ (API level 14+). + + +# Troubleshooting + +To trigger a complete rebuild, run `make clean` and then start over generating the Xcode projects or `Makefile` as described above. + +If you are having trouble getting the dependencies right, you can blow away the `mason_packages` directory, or run `make distclean`. This means the `Makefile` and configure script will automatically install the dependencies again on the next try. + +On OS X, you can also try clearing the Xcode cache with `make clear_xcode_cache`. + +# Mapbox API access tokens + +The demo applications use Mapbox vector tiles, which **require a Mapbox account and API access token**. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/account/apps/). + +For iOS and OS X use of the demo apps in Xcode, setup the access token by editing the scheme for the application target, then adding an environment variable with the name `MAPBOX_ACCESS_TOKEN`. + +![edit scheme](https://cloud.githubusercontent.com/assets/98601/5460702/c4610262-8519-11e4-873a-8597821da468.png) + +![setting access token in Xcode scheme](https://cloud.githubusercontent.com/assets/162976/5349358/0a086f00-7f8c-11e4-8433-bdbaccda2b58.png) + +For Linux, set the environment variable `MAPBOX_ACCESS_TOKEN` to your token. + +For Android, gradle will take the value of `MAPBOX_ACCESS_TOKEN` and save it to `android/java/MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt` where the app will read it from. + +# Style + +Default styles in the JSON-based [styling format](https://github.com/mapbox/mapbox-gl-style-spec) are included at `./styles` as a submodule. See the [styles project](https://github.com/mapbox/mapbox-gl-styles) to report problems or to contribute to these styles. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..6de1da495 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,65 @@ +mapbox-gl-native copyright (c) 2014, Mapbox. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== + +Mapbox GL uses portions of the Mapbox iOS SDK, which was derived from the +Route-Me open source project, including the Alpstein fork of it. + +The Route-Me license appears below. + +Copyright (c) 2008-2013, Route-Me Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== + +Mapbox GL uses portions of SVPulsingAnnotationView. + +Copyright (c) 2013, Sam Vermette + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..358b3c05c --- /dev/null +++ b/Makefile @@ -0,0 +1,134 @@ +export BUILDTYPE ?= Release +export BUILD_TEST ?= 1 +export BUILD_RENDER ?= 1 + +# Determine build platform +ifeq ($(shell uname -s), Darwin) +export BUILD = osx +export JOBS ?= $(shell sysctl -n hw.ncpu) +export XCPRETTY := $(shell ./scripts/xcpretty.sh) +else ifeq ($(shell uname -s), Linux) +export BUILD = linux +export JOBS ?= $(shell grep --count processor /proc/cpuinfo) +else +$(error Cannot determine build platform) +endif +export BUILD_VERSION = $(shell uname -m) + +RUN = +@$(MAKE) -f scripts/main.mk + +default: ; @printf "You must specify a valid target\n" + +#### OS X targets ############################################################## + +ifeq ($(BUILD),osx) +.PHONY: osx xosx run-osx run-xosx +osx: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Makefile/osxapp +xosx: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Xcode/osxapp +run-osx: osx ; @"build/osx-x86_64/$(BUILDTYPE)/Mapbox GL.app/Contents/MacOS/Mapbox GL" +run-xosx: xosx ; @"gyp/build/$(BUILDTYPE)/Mapbox GL.app/Contents/MacOS/Mapbox GL" + +.PHONY: Xcode/osx Xcode/ios +Xcode/ios: ; $(RUN) HOST=ios Xcode/__project__ +Xcode/osx: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Xcode/__project__ + +.PHONY: xproj iproj +xproj: Xcode/osx ; @open ./build/osx-x86_64/gyp/osx.xcodeproj +iproj: Xcode/ios ; @open ./build/ios-all/gyp/ios.xcodeproj + +.PHONY: ios ibench isim +ios ibench isim: export XCODEBUILD_ARGS += PROVISIONING_PROFILE="$$(PROVISIONING_PROFILE)" + +ios: export XCODEBUILD_ARGS += -sdk iphoneos ARCHS="arm64 armv7 armv7s" +ios: ; $(RUN) HOST=ios Xcode/iosapp + +isim: export XCODEBUILD_ARGS += -sdk iphonesimulator ARCHS="x86_64 i386" +isim: ; $(RUN) HOST=ios Xcode/iosapp + +ibench: export XCODEBUILD_ARGS += -sdk iphoneos ARCHS="arm64" +ibench: ; $(RUN) HOST=ios Xcode/ios-bench + +.PHONY: ipackage ipackage-strip ipackage-sim itest +ipackage: Xcode/ios ; @JOBS=$(JOBS) ./scripts/ios/package.sh +ipackage-strip: Xcode/ios ; @JOBS=$(JOBS) ./scripts/ios/package.sh strip +ipackage-sim: Xcode/ios ; @JOBS=$(JOBS) ./scripts/ios/package.sh sim +itest: ipackage-sim ; ./scripts/ios/test.sh +endif + +#### All platforms targets ##################################################### + +.PHONY: linux run-linux run-valgrind-linux +linux: ; $(RUN) Makefile/linuxapp +run-linux: linux ; (cd build/linux-x86_64/$(BUILDTYPE) && ./mapbox-gl) +run-valgrind-linux: linux + (cd build/linux-x86_64/$(BUILDTYPE) && valgrind --leak-check=full --suppressions=../../../scripts/valgrind.sup ./mapbox-gl) + +.PHONY: android android-lib +# Builds a particular android architecture. +android-lib-%: ; $(RUN) HOST=android HOST_VERSION=$* Makefile/androidapp + +# Builds the default Android library +android-lib: ; $(RUN) HOST=android Makefile/androidapp + +# Builds the selected/default Android library +android: android-lib + cd android/java && ./gradlew --parallel --max-workers=$(JOBS) assemble$(BUILDTYPE) + +# Builds all android architectures. +android-all: android-lib-arm-v5 android-lib-arm-v7 android-lib-arm-v8 +android-all: android-lib-x86 android-lib-x86-64 +android-all: android-lib-mips android-lib-mips-64 + cd android/java && ./gradlew --parallel-threads=$(JOBS) assemble$(BUILDTYPE) + +.PHONY: test +test: ; $(RUN) Makefile/test +test-%: ; $(RUN) test-$* +ifeq ($(BUILD),osx) +xtest: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Xcode/test +endif + +.PHONY: render xrender +render: ; $(RUN) Makefile/mbgl-render +ifeq ($(BUILD),osx) +xrender: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Xcode/mbgl-render +endif + + +##### Maintenace operations #################################################### + +.PHONY: clear_xcode_cache +clear_xcode_cache: +ifeq ($(BUILD), osx) + @CUSTOM_DD=`defaults read com.apple.dt.Xcode IDECustomDerivedDataLocation 2>/dev/null`; \ + if [ $$CUSTOM_DD ]; then \ + echo clearing files in $$CUSTOM_DD older than one day; \ + find $$CUSTOM_DD/mapboxgl-app-* -mtime +1 | xargs rm -rf; \ + fi; \ + if [ -d ~/Library/Developer/Xcode/DerivedData/ ] && [ ! $$CUSTOM_DD ]; then \ + echo 'clearing files in ~/Library/Developer/Xcode/DerivedData/mapboxgl-app-* older than one day'; \ + find ~/Library/Developer/Xcode/DerivedData/mapboxgl-app-* -mtime +1 | xargs rm -rf; \ + fi +endif + +.PHONY: clear_sqlite_cache +clear_sqlite_cache: +ifeq ($(BUILD), osx) + rm -f ~/Library/Application\ Support/Mapbox\ GL/cache.db +else + rm -f /tmp/mbgl-cache.db +endif + +clean: clear_sqlite_cache clear_xcode_cache + -find ./deps/gyp -name "*.pyc" -exec rm {} \; + -rm -rf ./build/ + -rm -rf ./macosx/build + -rm -rf ./linux/build + -rm -rf ./ios/build + -rm -rf ./test/build + -rm -rf ./config/*.gypi + -rm -rf ./android/java/build ./android/java/MapboxGLAndroidSDKTestApp/build ./android/java/MapboxGLAndroidSDKTestApp/build + -rm -rf ./android/java/MapboxGLAndroidSDK/src/main/jniLibs ./android/java/MapboxGLAndroidSDK/src/main/assets + -rm -f ./android/test/features.zip + +distclean: clean + -rm -rf ./mason_packages diff --git a/README.md b/README.md new file mode 100644 index 000000000..57928618a --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# Mapbox GL (Native) + +[![Travis](https://api.travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) + +An OpenGL ES-based renderer for [Mapbox Vector Tiles](https://www.mapbox.com/blog/vector-tiles), consisting of a C++ library for OS X and Linux and SDK bindings for iOS and Android. + +**This repository is for development on Mapbox GL itself.** + +If you want to use products _based on_ Mapbox GL, check out: + +- [Mapbox Mobile](http://mapbox.com/mobile) — iOS and Android native development libraries for vector maps in apps +- [`node-mapbox-gl-native`](https://github.com/mapbox/node-mapbox-gl-native) — Node.js library for vector map rendering +- [`react-native-mapbox-gl`](https://github.com/mapbox/react-native-mapbox-gl`) — React Native library for vector maps in apps +- [`qmapboxgl`](https://github.com/tmpsantos/qmapboxgl) — Qt library for vector map rendering + +-- + +See [`INSTALL.md`](./INSTALL.md) for development setup and install instructions, including dependencies. diff --git a/android/LICENSE_GESTURES.md b/android/LICENSE_GESTURES.md new file mode 100644 index 000000000..d2d488c6e --- /dev/null +++ b/android/LICENSE_GESTURES.md @@ -0,0 +1,13 @@ +Android Gesture Detectors Framework Licence +=================================== + +Copyright (c) 2012, Almer Thie + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/android/LICENSE_LOST.txt b/android/LICENSE_LOST.txt new file mode 100644 index 000000000..a0fba4cbc --- /dev/null +++ b/android/LICENSE_LOST.txt @@ -0,0 +1,13 @@ +Copyright (c) 2014 Mapzen + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp new file mode 100644 index 000000000..d1040d68e --- /dev/null +++ b/android/cpp/jni.cpp @@ -0,0 +1,1863 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma clang diagnostic ignored "-Wunused-parameter" + +namespace mbgl { +namespace android { + +JavaVM* theJVM; + +std::string cachePath; +std::string dataPath; +std::string apkPath; +std::string androidRelease; + +jmethodID onInvalidateId = nullptr; +jmethodID onMapChangedId = nullptr; +jmethodID onFpsChangedId = nullptr; + +jclass latLngClass = nullptr; +jmethodID latLngConstructorId = nullptr; +jfieldID latLngLatitudeId = nullptr; +jfieldID latLngLongitudeId = nullptr; + +jclass latLngZoomClass = nullptr; +jmethodID latLngZoomConstructorId = nullptr; +jfieldID latLngZoomLatitudeId = nullptr; +jfieldID latLngZoomLongitudeId = nullptr; +jfieldID latLngZoomZoomId = nullptr; + +jclass markerClass = nullptr; +jmethodID markerConstructorId = nullptr; +jfieldID markerPositionId = nullptr; +jfieldID markerSpriteId = nullptr; + +jclass polylineClass = nullptr; +jmethodID polylineConstructorId = nullptr; +jfieldID polylineAlphaId = nullptr; +jfieldID polylineVisibleId = nullptr; +jfieldID polylineColorId = nullptr; +jfieldID polylineWidthId = nullptr; +jfieldID polylinePointsId = nullptr; + +jclass polygonClass = nullptr; +jmethodID polygonConstructorId = nullptr; +jfieldID polygonAlphaId = nullptr; +jfieldID polygonVisibleId = nullptr; +jfieldID polygonFillColorId = nullptr; +jfieldID polygonStrokeColorId = nullptr; +jfieldID polygonStrokeWidthId = nullptr; +jfieldID polygonPointsId = nullptr; +jfieldID polygonHolesId = nullptr; + +jclass runtimeExceptionClass = nullptr; +jclass nullPointerExceptionClass = nullptr; + +jmethodID listToArrayId = nullptr; + +jclass arrayListClass = nullptr; +jmethodID arrayListConstructorId = nullptr; +jmethodID arrayListAddId = nullptr; + +jclass projectedMetersClass = nullptr; +jmethodID projectedMetersConstructorId = nullptr; +jfieldID projectedMetersNorthingId = nullptr; +jfieldID projectedMetersEastingId = nullptr; + +jclass pointFClass = nullptr; +jmethodID pointFConstructorId = nullptr; +jfieldID pointFXId = nullptr; +jfieldID pointFYId = nullptr; + +jclass httpContextClass = nullptr; +jmethodID httpContextGetInstanceId = nullptr; +jmethodID httpContextCreateRequestId = nullptr; + +jclass httpRequestClass = nullptr; +jmethodID httpRequestStartId = nullptr; +jmethodID httpRequestCancelId = nullptr; + +bool throw_jni_error(JNIEnv *env, const char *msg) { + if (env->ThrowNew(runtimeExceptionClass, msg) < 0) { + env->ExceptionDescribe(); + return false; + } + + return true; +} + +bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName) { + JavaVMAttachArgs args = {JNI_VERSION_1_2, threadName.c_str(), NULL}; + + jint ret; + *env = nullptr; + bool detach = false; + ret = vm->GetEnv(reinterpret_cast(env), JNI_VERSION_1_6); + if (ret != JNI_OK) { + if (ret != JNI_EDETACHED) { + mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret); + throw new std::runtime_error("GetEnv() failed"); + } else { + ret = vm->AttachCurrentThread(env, &args); + if (ret != JNI_OK) { + mbgl::Log::Error(mbgl::Event::JNI, "AttachCurrentThread() failed with %i", ret); + throw new std::runtime_error("AttachCurrentThread() failed"); + } + detach = true; + } + } + + return detach; +} + +void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) { + if (detach) { + jint ret; + if ((ret = vm->DetachCurrentThread()) != JNI_OK) { + mbgl::Log::Error(mbgl::Event::JNI, "DetachCurrentThread() failed with %i", ret); + throw new std::runtime_error("DetachCurrentThread() failed"); + } + } + *env = nullptr; +} + +std::string std_string_from_jstring(JNIEnv *env, jstring jstr) { + std::string str; + + if (jstr == nullptr) { + if (env->ThrowNew(nullPointerExceptionClass, "String cannot be null.") < 0) { + env->ExceptionDescribe(); + return str; + } + + return str; + } + + jsize len = env->GetStringLength(jstr); + if (len < 0) { + env->ExceptionDescribe(); + return str; + } + + const jchar *chars = env->GetStringChars(jstr, nullptr); + if (chars == nullptr) { + env->ExceptionDescribe(); + return str; + } + + std::u16string ustr(reinterpret_cast(chars), len); + env->ReleaseStringChars(jstr, chars); + chars = nullptr; + str = std::wstring_convert, char16_t>().to_bytes(ustr); + return str; +} + +jstring std_string_to_jstring(JNIEnv *env, std::string str) { + std::u16string ustr = + std::wstring_convert, char16_t>().from_bytes(str); + + jstring jstr = env->NewString(reinterpret_cast(ustr.c_str()), ustr.size()); + if (jstr == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return jstr; +} + +std::vector std_vector_string_from_jobject(JNIEnv *env, jobject jlist) { + std::vector vector; + + if (jlist == nullptr) { + if (env->ThrowNew(nullPointerExceptionClass, "List cannot be null.") < 0) { + env->ExceptionDescribe(); + return vector; + } + + return vector; + } + + jobjectArray jarray = + reinterpret_cast(env->CallObjectMethod(jlist, listToArrayId)); + if (env->ExceptionCheck() || (jarray == nullptr)) { + env->ExceptionDescribe(); + return vector; + } + + jsize len = env->GetArrayLength(jarray); + if (len < 0) { + env->ExceptionDescribe(); + return vector; + } + + for (jsize i = 0; i < len; i++) { + jstring jstr = reinterpret_cast(env->GetObjectArrayElement(jarray, i)); + if (jstr == nullptr) { + env->ExceptionDescribe(); + return vector; + } + + vector.push_back(std_string_from_jstring(env, jstr)); + } + + env->DeleteLocalRef(jarray); + jarray = nullptr; + + return vector; +} + +jobject std_vector_string_to_jobject(JNIEnv *env, std::vector vector) { + jobject jlist = env->NewObject(arrayListClass, arrayListConstructorId); + if (jlist == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + for (const auto& str : vector) { + env->CallBooleanMethod(jlist, arrayListAddId, std_string_to_jstring(env, str)); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + } + + return jlist; +} + +jlongArray std_vector_uint_to_jobject(JNIEnv *env, std::vector vector) { + jlongArray jarray = env->NewLongArray(vector.size()); + if (jarray == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + std::vector v; + for (const uint32_t& id : vector) { + v.push_back((jlong)id); + } + + env->SetLongArrayRegion(jarray, 0, v.size(), &(v[0])); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + return jarray; +} + +mbgl::AnnotationSegment annotation_segment_from_latlng_jlist(JNIEnv *env, jobject jlist) { + mbgl::AnnotationSegment segment; + + if (jlist == nullptr) { + if (env->ThrowNew(nullPointerExceptionClass, "List cannot be null.") < 0) { + env->ExceptionDescribe(); + return segment; + } + return segment; + } + + jobjectArray jarray = + reinterpret_cast(env->CallObjectMethod(jlist, listToArrayId)); + if (env->ExceptionCheck() || (jarray == nullptr)) { + env->ExceptionDescribe(); + return segment; + } + + jsize len = env->GetArrayLength(jarray); + if (len < 0) { + env->ExceptionDescribe(); + return segment; + } + + segment.reserve(len); + + for (jsize i = 0; i < len; i++) { + jobject latLng = reinterpret_cast(env->GetObjectArrayElement(jarray, i)); + if (latLng == nullptr) { + env->ExceptionDescribe(); + return segment; + } + + jdouble latitude = env->GetDoubleField(latLng, latLngLatitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return segment; + } + + jdouble longitude = env->GetDoubleField(latLng, latLngLongitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return segment; + } + + segment.push_back(mbgl::LatLng(latitude, longitude)); + env->DeleteLocalRef(latLng); + } + + env->DeleteLocalRef(jarray); + jarray = nullptr; + + return segment; +} + +std::pair annotation_std_pair_from_polygon_jobject(JNIEnv *env, jobject polygon) { + jfloat alpha = env->GetFloatField(polygon, polygonAlphaId); + //jboolean visible = env->GetBooleanField(polygon, polygonVisibleId); + jint fillColor = env->GetIntField(polygon, polygonFillColorId); + jint strokeColor = env->GetIntField(polygon, polygonStrokeColorId); + + int rF = (fillColor >> 16) & 0xFF; + int gF = (fillColor >> 8) & 0xFF; + int bF = (fillColor) & 0xFF; + int aF = (fillColor >> 24) & 0xFF; + + int rS = (strokeColor >> 16) & 0xFF; + int gS = (strokeColor >> 8) & 0xFF; + int bS = (strokeColor) & 0xFF; + int aS = (strokeColor >> 24) & 0xFF; + + mbgl::StyleProperties shapeProperties; + mbgl::FillProperties fillProperties; + fillProperties.opacity = alpha; + fillProperties.stroke_color = {{ static_cast(rS) / 255.0f, static_cast(gS) / 255.0f, static_cast(bS) / 255.0f, static_cast(aS) / 255.0f }}; + fillProperties.fill_color = {{ static_cast(rF) / 255.0f, static_cast(gF) / 255.0f, static_cast(bF) / 255.0f, static_cast(aF) / 255.0f }}; + shapeProperties.set(fillProperties); + + jobject points = env->GetObjectField(polygon, polygonPointsId); + mbgl::AnnotationSegment segment = annotation_segment_from_latlng_jlist(env, points); + env->DeleteLocalRef(points); + + return std::make_pair(segment, shapeProperties); +} + +} +} + +namespace { + +using namespace mbgl::android; + +jlong JNICALL nativeCreate(JNIEnv *env, jobject obj, jstring cachePath_, jstring dataPath_, jstring apkPath_, jfloat pixelRatio, jint availableProcessors, jlong totalMemory) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreate"); + cachePath = std_string_from_jstring(env, cachePath_); + dataPath = std_string_from_jstring(env, dataPath_); + apkPath = std_string_from_jstring(env, apkPath_); + NativeMapView *nativeMapView = new NativeMapView(env, obj, pixelRatio, availableProcessors, totalMemory); + jlong mapViewPtr = reinterpret_cast(nativeMapView); + return mapViewPtr; +} + +void JNICALL nativeDestroy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroy"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + delete nativeMapView; + nativeMapView = nullptr; +} + +void JNICALL nativeInitializeDisplay(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeDisplay"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + try + { + nativeMapView->initializeDisplay(); + } catch(const std::exception& e) { + throw_jni_error(env, "Unable to initialize GL display."); + } +} + +void JNICALL nativeTerminateDisplay(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateDisplay"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->terminateDisplay(); +} + +void JNICALL nativeInitializeContext(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeContext"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + try { + nativeMapView->initializeContext(); + } catch(const std::exception& e) { + throw_jni_error(env, "Unable to initialize GL context."); + } +} + +void JNICALL nativeTerminateContext(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateContext"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->terminateContext(); +} + +void JNICALL nativeCreateSurface(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject surface) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreateSurface"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + try { + nativeMapView->createSurface(ANativeWindow_fromSurface(env, surface)); + } catch(const std::exception& e) { + throw_jni_error(env, "Unable to create GL surface."); + } +} + +void JNICALL nativeDestroySurface(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroySurface"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->destroySurface(); +} + +void JNICALL nativePause(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativePause"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->pause(); +} + +void JNICALL nativeResume(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeResume"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->resume(); +} + +void JNICALL nativeUpdate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdate"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().update(mbgl::Update::Repaint); +} + +void JNICALL nativeOnInvalidate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeOnInvalidate"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->onInvalidate(); +} + +void JNICALL nativeViewResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint width, jint height) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeViewResize"); + assert(nativeMapViewPtr != 0); + assert(width >= 0); + assert(height >= 0); + assert(width <= UINT16_MAX); + assert(height <= UINT16_MAX); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->resizeView(width, height); +} + +void JNICALL nativeFramebufferResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint fbWidth, jint fbHeight) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeFramebufferResize"); + assert(nativeMapViewPtr != 0); + assert(fbWidth >= 0); + assert(fbHeight >= 0); + assert(fbWidth <= UINT16_MAX); + assert(fbHeight <= UINT16_MAX); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->resizeFramebuffer(fbWidth, fbHeight); +} + +void JNICALL nativeRemoveClass(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring clazz) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeRemoveClass"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().removeClass(std_string_from_jstring(env, clazz)); +} + +jboolean JNICALL nativeHasClass(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring clazz) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeHasClass"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().hasClass(std_string_from_jstring(env, clazz)); +} + +void JNICALL nativeAddClass(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring clazz) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddClass"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().addClass(std_string_from_jstring(env, clazz)); +} + +void JNICALL nativeSetClasses(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject classes) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetClasses"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setClasses(std_vector_string_from_jobject(env, classes)); +} + +jobject JNICALL nativeGetClasses(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetClasses"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return std_vector_string_to_jobject(env, nativeMapView->getMap().getClasses()); +} + +void JNICALL nativeSetDefaultTransitionDuration(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, + jlong duration) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetDefaultTransitionDuration"); + assert(nativeMapViewPtr != 0); + assert(duration >= 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setDefaultTransitionDuration(std::chrono::milliseconds(duration)); +} + +jlong JNICALL nativeGetDefaultTransitionDuration(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetDefaultTransitionDuration"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return std::chrono::duration_cast(nativeMapView->getMap().getDefaultTransitionDuration()).count(); +} + +void JNICALL nativeSetStyleURL(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring url) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetStyleURL"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setStyleURL(std_string_from_jstring(env, url)); +} + +void JNICALL nativeSetStyleJSON(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, + jstring newStyleJson, jstring base) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetStyleJSON"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setStyleJSON(std_string_from_jstring(env, newStyleJson), + std_string_from_jstring(env, base)); +} + +jstring JNICALL nativeGetStyleJSON(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetStyleJSON"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return std_string_to_jstring(env, nativeMapView->getMap().getStyleJSON()); +} + +void JNICALL nativeSetAccessToken(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring accessToken) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetAccessToken"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getFileSource().setAccessToken(std_string_from_jstring(env, accessToken)); +} + +jstring JNICALL nativeGetAccessToken(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetAccessToken"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return std_string_to_jstring(env, nativeMapView->getFileSource().getAccessToken()); +} + +void JNICALL nativeCancelTransitions(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeCancelTransitions"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().cancelTransitions(); +} + +void JNICALL nativeSetGestureInProgress(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jboolean inProgress) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetGestureInProgress"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setGestureInProgress(inProgress); +} + +void JNICALL nativeMoveBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble dx, jdouble dy, + jlong duration) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeMoveBy"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().moveBy(dx, dy, std::chrono::milliseconds(duration)); +} + +void JNICALL nativeSetLatLng(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject latLng, + jlong duration) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetLatLng"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jdouble latitude = env->GetDoubleField(latLng, latLngLatitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return; + } + + jdouble longitude = env->GetDoubleField(latLng, latLngLongitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return; + } + + nativeMapView->getMap().setLatLng(mbgl::LatLng(latitude, longitude), std::chrono::milliseconds(duration)); +} + +jobject JNICALL nativeGetLatLng(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetLatLng"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(); + + jobject ret = env->NewObject(latLngClass, latLngConstructorId, latLng.latitude, latLng.longitude); + if (ret == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return ret; +} + +void JNICALL nativeResetPosition(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeResetPosition"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().resetPosition(); +} + +void JNICALL nativeScaleBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble ds, jdouble cx, + jdouble cy, jlong duration) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeScaleBy"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().scaleBy(ds, cx, cy, std::chrono::milliseconds(duration)); +} + +void JNICALL nativeSetScale(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble scale, + jdouble cx, jdouble cy, jlong duration) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetScale"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setScale(scale, cx, cy, std::chrono::milliseconds(duration)); +} + +jdouble JNICALL nativeGetScale(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetScale"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().getScale(); +} + +void JNICALL nativeSetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble zoom, jlong duration) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetZoom"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setZoom(zoom, std::chrono::milliseconds(duration)); +} + +jdouble JNICALL nativeGetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetZoom"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().getZoom(); +} + +void JNICALL nativeSetLatLngZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, + jobject latLngZoom, jlong duration) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetLatLngZoom"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jdouble latitude = env->GetDoubleField(latLngZoom, latLngZoomLatitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return; + } + + jdouble longitude = env->GetDoubleField(latLngZoom, latLngZoomLongitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return; + } + + jdouble zoom = env->GetDoubleField(latLngZoom, latLngZoomZoomId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return; + } + + nativeMapView->getMap().setLatLngZoom(mbgl::LatLng(latitude, longitude), zoom, std::chrono::milliseconds(duration)); +} + +jobject JNICALL nativeGetLatLngZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetLatLngZoom"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(); + jdouble zoom = nativeMapView->getMap().getZoom(); + + jobject ret = env->NewObject(latLngZoomClass, latLngZoomConstructorId, latLng.longitude, latLng.latitude, zoom); + if (ret == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return ret; +} + +void JNICALL nativeResetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeResetZoom"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().resetZoom(); +} + +jdouble JNICALL nativeGetMinZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetMinZoom"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().getMinZoom(); +} + +jdouble JNICALL nativeGetMaxZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetMaxZoom"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().getMaxZoom(); +} + +void JNICALL nativeRotateBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble sx, + jdouble sy, jdouble ex, jdouble ey, jlong duration) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeRotateBy"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().rotateBy(sx, sy, ex, ey, std::chrono::milliseconds(duration)); +} + +void JNICALL nativeSetBearing(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble degrees, + jlong duration) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetBearing"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setBearing(degrees, std::chrono::milliseconds(duration)); +} + +void JNICALL nativeSetBearing(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble degrees, + jdouble cx, jdouble cy) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetBearing"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setBearing(degrees, cx, cy); +} + +jdouble JNICALL nativeGetBearing(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetBearing"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().getBearing(); +} + +void JNICALL nativeResetNorth(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeResetNorth"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().resetNorth(); +} + +jlong JNICALL nativeAddMarker(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject marker) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddMarker"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jobject position = env->GetObjectField(marker, markerPositionId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return -1; + } + + jstring jsprite = reinterpret_cast(env->GetObjectField(marker, markerSpriteId)); + std::string sprite = std_string_from_jstring(env, jsprite); + + jdouble latitude = env->GetDoubleField(position, latLngLatitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return -1; + } + + jdouble longitude = env->GetDoubleField(position, latLngLongitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return -1; + } + + // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long. + return nativeMapView->getMap().addPointAnnotation(mbgl::PointAnnotation(mbgl::LatLng(latitude, longitude), sprite)); +} + +jlong JNICALL nativeAddPolyline(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject polyline) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddPolyline"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jfloat alpha = env->GetFloatField(polyline, polylineAlphaId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return -1; + } + + /*jboolean visible = env->GetBooleanField(polyline, polylineVisibleId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return -1; + }*/ + + jint color = env->GetIntField(polyline, polylineColorId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return -1; + } + + int r = (color >> 16) & 0xFF; + int g = (color >> 8) & 0xFF; + int b = (color) & 0xFF; + int a = (color >> 24) & 0xFF; + + jfloat width = env->GetFloatField(polyline, polylineWidthId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return -1; + } + + mbgl::StyleProperties shapeProperties; + mbgl::LineProperties lineProperties; + lineProperties.opacity = alpha; + lineProperties.color = {{ static_cast(r) / 255.0f, static_cast(g) / 255.0f, static_cast(b) / 255.0f, static_cast(a) / 255.0f }}; + lineProperties.width = width; + shapeProperties.set(lineProperties); + + jobject points = env->GetObjectField(polyline, polylinePointsId); + mbgl::AnnotationSegment segment = annotation_segment_from_latlng_jlist(env, points); + + std::vector shapes; + shapes.emplace_back(mbgl::AnnotationSegments { segment }, shapeProperties); + + std::vector shapeAnnotationIDs = nativeMapView->getMap().addShapeAnnotations(shapes); + uint32_t id = shapeAnnotationIDs.at(0); + + return id; +} + +jlong JNICALL nativeAddPolygon(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject polygon) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddPolygon"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + std::vector shapes; + std::pair segment = annotation_std_pair_from_polygon_jobject(env, polygon); + + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return -1; + } + + shapes.emplace_back(mbgl::AnnotationSegments { segment.first }, segment.second); + + std::vector shapeAnnotationIDs = nativeMapView->getMap().addShapeAnnotations(shapes); + uint32_t id = shapeAnnotationIDs.at(0); + return id; +} + +jlongArray JNICALL nativeAddPolygons(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject jlist) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddPolygons"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + std::vector shapes; + + if (jlist == nullptr) { + if (env->ThrowNew(nullPointerExceptionClass, "List cannot be null.") < 0) { + env->ExceptionDescribe(); + return nullptr; + } + return nullptr; + } + + jobjectArray jarray = + reinterpret_cast(env->CallObjectMethod(jlist, listToArrayId)); + if (env->ExceptionCheck() || (jarray == nullptr)) { + env->ExceptionDescribe(); + return nullptr; + } + + jsize len = env->GetArrayLength(jarray); + if (len < 0) { + env->ExceptionDescribe(); + return nullptr; + } + + shapes.reserve(len); + + for (jsize i = 0; i < len; i++) { + jobject polygon = reinterpret_cast(env->GetObjectArrayElement(jarray, i)); + + std::pair segment = annotation_std_pair_from_polygon_jobject(env, polygon); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + shapes.emplace_back(mbgl::AnnotationSegments { segment.first }, segment.second); + + env->DeleteLocalRef(polygon); + } + + env->DeleteLocalRef(jarray); + + std::vector shapeAnnotationIDs = nativeMapView->getMap().addShapeAnnotations(shapes); + return std_vector_uint_to_jobject(env, shapeAnnotationIDs); +} + +void JNICALL nativeRemoveAnnotation(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jlong annotationId) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeRemoveAnnotation"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().removeAnnotation(static_cast(annotationId)); +} + +void JNICALL nativeRemoveAnnotations(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jlongArray jarray) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeRemoveAnnotations"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + std::vector ids; + + if (env->ExceptionCheck() || (jarray == nullptr)) { + env->ExceptionDescribe(); + return; + } + + jsize len = env->GetArrayLength(jarray); + if (len < 0) { + env->ExceptionDescribe(); + return; + } + + ids.reserve(len); + jlong* jids = env->GetLongArrayElements(jarray, nullptr); + + for (jsize i = 0; i < len; i++) { + if(jids[i] == -1L) + continue; + ids.push_back(static_cast(jids[i])); + } + + env->ReleaseLongArrayElements(jarray, jids, JNI_ABORT); + + nativeMapView->getMap().removeAnnotations(ids); +} + +void JNICALL nativeSetSprite(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, + jstring symbol, jint width, jint height, jfloat scale, jbyteArray jpixels) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetSprite"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + const std::string symbolName = std_string_from_jstring(env, symbol); + + jbyte* pixelData = env->GetByteArrayElements(jpixels, nullptr); + std::string pixels(reinterpret_cast(pixelData), width * height * 4); + env->ReleaseByteArrayElements(jpixels, pixelData, JNI_ABORT); + + auto spriteImage = std::make_shared( + uint16_t(width), + uint16_t(height), + float(scale), + std::move(pixels)); + + nativeMapView->getMap().setSprite(symbolName, spriteImage); +} + +void JNICALL nativeOnLowMemory(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeOnLowMemory"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().onLowMemory(); +} + +void JNICALL nativeSetDebug(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jboolean debug) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetDebug"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setDebug(debug); + nativeMapView->enableFps(debug); +} + +void JNICALL nativeToggleDebug(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeToggleDebug"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().toggleDebug(); + nativeMapView->enableFps(nativeMapView->getMap().getDebug()); +} + +jboolean JNICALL nativeGetDebug(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetDebug"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().getDebug(); +} + +void JNICALL nativeSetCollisionDebug(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jboolean debug) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetCollisionDebug"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().setCollisionDebug(debug); +} + +void JNICALL nativeToggleCollisionDebug(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeToggleCollisionDebug"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + nativeMapView->getMap().toggleCollisionDebug(); +} + +jboolean JNICALL nativeGetCollisionDebug(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetCollisionDebug"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().getCollisionDebug(); +} + +jboolean JNICALL nativeIsFullyLoaded(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeIsFullyLoaded"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().isFullyLoaded(); +} + +void JNICALL nativeSetReachability(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jboolean status) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetReachability"); + assert(nativeMapViewPtr != 0); + if (status) { + mbgl::NetworkStatus::Reachable(); + } +} + +jdouble JNICALL nativeGetMetersPerPixelAtLatitude(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble lat, jdouble zoom) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetMetersPerPixelAtLatitude"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().getMetersPerPixelAtLatitude(lat, zoom); +} + +jobject JNICALL nativeProjectedMetersForLatLng(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject latLng) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeProjectedMetersForLatLng"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jdouble latitude = env->GetDoubleField(latLng, latLngLatitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jdouble longitude = env->GetDoubleField(latLng, latLngLongitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + mbgl::ProjectedMeters projectedMeters = nativeMapView->getMap().projectedMetersForLatLng(mbgl::LatLng(latitude, longitude)); + + jobject ret = env->NewObject(projectedMetersClass, projectedMetersConstructorId, projectedMeters.northing, projectedMeters.easting); + if (ret == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return ret; +} + +jobject JNICALL nativeLatLngForProjectedMeters(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject projectedMeters) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeLatLngForProjectedMeters"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jdouble northing = env->GetDoubleField(projectedMeters, projectedMetersNorthingId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jdouble easting = env->GetDoubleField(projectedMeters, projectedMetersEastingId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + mbgl::LatLng latLng = nativeMapView->getMap().latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting)); + + jobject ret = env->NewObject(latLngClass, latLngConstructorId, latLng.latitude, latLng.longitude); + if (ret == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return ret; +} + +jobject JNICALL nativePixelForLatLng(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject latLng) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativePixelForLatLng"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jdouble latitude = env->GetDoubleField(latLng, latLngLatitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jdouble longitude = env->GetDoubleField(latLng, latLngLongitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + mbgl::vec2 pixel = nativeMapView->getMap().pixelForLatLng(mbgl::LatLng(latitude, longitude)); + + jobject ret = env->NewObject(pointFClass, pointFConstructorId, static_cast(pixel.x), static_cast(pixel.y)); + if (ret == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return ret; +} + +jobject JNICALL nativeLatLngForPixel(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject pixel) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeLatLngForPixel"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jfloat x = env->GetFloatField(pixel, pointFXId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jfloat y = env->GetFloatField(pixel, pointFYId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + mbgl::LatLng latLng = nativeMapView->getMap().latLngForPixel(mbgl::vec2(x, y)); + + jobject ret = env->NewObject(latLngClass, latLngConstructorId, latLng.latitude, latLng.longitude); + if (ret == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return ret; +} + +} + +extern "C" { + +extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + mbgl::Log::Debug(mbgl::Event::JNI, "JNI_OnLoad"); + + theJVM = vm; + + JNIEnv *env = nullptr; + jint ret = vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + if (ret != JNI_OK) { + mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret); + return JNI_ERR; + } + + latLngClass = env->FindClass("com/mapbox/mapboxgl/geometry/LatLng"); + if (latLngClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + latLngConstructorId = env->GetMethodID(latLngClass, "", "(DD)V"); + if (latLngConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + latLngLatitudeId = env->GetFieldID(latLngClass, "latitude", "D"); + if (latLngLatitudeId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + latLngLongitudeId = env->GetFieldID(latLngClass, "longitude", "D"); + if (latLngLongitudeId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + latLngZoomClass = env->FindClass("com/mapbox/mapboxgl/geometry/LatLngZoom"); + if (latLngZoomClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + latLngZoomConstructorId = env->GetMethodID(latLngZoomClass, "", "(DDD)V"); + if (latLngZoomConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + latLngZoomLatitudeId = env->GetFieldID(latLngZoomClass, "latitude", "D"); + if (latLngZoomLatitudeId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + latLngZoomLongitudeId = env->GetFieldID(latLngZoomClass, "longitude", "D"); + if (latLngZoomLongitudeId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + latLngZoomZoomId = env->GetFieldID(latLngZoomClass, "zoom", "D"); + if (latLngZoomZoomId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + markerClass = env->FindClass("com/mapbox/mapboxgl/annotations/Marker"); + if (markerClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + markerConstructorId = env->GetMethodID(markerClass, "", "()V"); + if (markerConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + markerPositionId = env->GetFieldID(markerClass, "position", "Lcom/mapbox/mapboxgl/geometry/LatLng;"); + if (markerPositionId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + markerSpriteId = env->GetFieldID(markerClass, "sprite", "Ljava/lang/String;"); + if (markerSpriteId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polylineClass = env->FindClass("com/mapbox/mapboxgl/annotations/Polyline"); + if (polylineClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polylineConstructorId = env->GetMethodID(polylineClass, "", "()V"); + if (polylineConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polylineAlphaId = env->GetFieldID(polylineClass, "alpha", "F"); + if (polylineAlphaId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polylineVisibleId = env->GetFieldID(polylineClass, "visible", "Z"); + if (polylineVisibleId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polylineColorId = env->GetFieldID(polylineClass, "color", "I"); + if (polylineColorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polylineWidthId = env->GetFieldID(polylineClass, "width", "F"); + if (polylineWidthId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polylinePointsId = env->GetFieldID(polylineClass, "points", "Ljava/util/List;"); + if (polylineWidthId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polygonClass = env->FindClass("com/mapbox/mapboxgl/annotations/Polygon"); + if (polygonClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polygonConstructorId = env->GetMethodID(polygonClass, "", "()V"); + if (polygonConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polygonAlphaId = env->GetFieldID(polygonClass, "alpha", "F"); + if (polygonAlphaId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polygonVisibleId = env->GetFieldID(polygonClass, "visible", "Z"); + if (polygonVisibleId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polygonFillColorId = env->GetFieldID(polygonClass, "fillColor", "I"); + if (polygonFillColorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polygonStrokeColorId = env->GetFieldID(polygonClass, "strokeColor", "I"); + if (polygonStrokeColorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polygonStrokeWidthId = env->GetFieldID(polygonClass, "strokeWidth", "F"); + if (polygonStrokeWidthId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polygonPointsId = env->GetFieldID(polygonClass, "points", "Ljava/util/List;"); + if (polygonPointsId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + polygonHolesId = env->GetFieldID(polygonClass, "holes", "Ljava/util/List;"); + if (polygonHolesId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + jclass nativeMapViewClass = env->FindClass("com/mapbox/mapboxgl/views/NativeMapView"); + if (nativeMapViewClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + onInvalidateId = env->GetMethodID(nativeMapViewClass, "onInvalidate", "()V"); + if (onInvalidateId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + onMapChangedId = env->GetMethodID(nativeMapViewClass, "onMapChanged", "()V"); + if (onMapChangedId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + onFpsChangedId = env->GetMethodID(nativeMapViewClass, "onFpsChanged", "(D)V"); + if (onFpsChangedId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + runtimeExceptionClass = env->FindClass("java/lang/RuntimeException"); + if (runtimeExceptionClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + nullPointerExceptionClass = env->FindClass("java/lang/NullPointerException"); + if (nullPointerExceptionClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + jclass listClass = env->FindClass("java/util/List"); + if (listClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + listToArrayId = env->GetMethodID(listClass, "toArray", "()[Ljava/lang/Object;"); + if (listToArrayId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + arrayListClass = env->FindClass("java/util/ArrayList"); + if (arrayListClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + arrayListConstructorId = env->GetMethodID(arrayListClass, "", "()V"); + if (arrayListConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + arrayListAddId = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"); + if (arrayListAddId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + projectedMetersClass = env->FindClass("com/mapbox/mapboxgl/geometry/ProjectedMeters"); + if (projectedMetersClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + projectedMetersConstructorId = env->GetMethodID(projectedMetersClass, "", "(DD)V"); + if (projectedMetersConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + projectedMetersNorthingId = env->GetFieldID(projectedMetersClass, "northing", "D"); + if (projectedMetersNorthingId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + projectedMetersEastingId = env->GetFieldID(projectedMetersClass, "easting", "D"); + if (projectedMetersEastingId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + pointFClass = env->FindClass("android/graphics/PointF"); + if (pointFClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + pointFConstructorId = env->GetMethodID(pointFClass, "", "(FF)V"); + if (pointFConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + pointFXId = env->GetFieldID(pointFClass, "x", "F"); + if (pointFXId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + pointFYId = env->GetFieldID(pointFClass, "y", "F"); + if (pointFYId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + httpContextClass = env->FindClass("com/mapbox/mapboxgl/http/HTTPContext"); + if (httpContextClass == nullptr) { + env->ExceptionDescribe(); + } + + httpContextGetInstanceId = env->GetStaticMethodID(httpContextClass, "getInstance", "()Lcom/mapbox/mapboxgl/http/HTTPContext;"); + if (httpContextGetInstanceId == nullptr) { + env->ExceptionDescribe(); + } + + httpContextCreateRequestId = env->GetMethodID(httpContextClass, "createRequest", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/mapbox/mapboxgl/http/HTTPContext$HTTPRequest;"); + if (httpContextCreateRequestId == nullptr) { + env->ExceptionDescribe(); + } + + httpRequestClass = env->FindClass("com/mapbox/mapboxgl/http/HTTPContext$HTTPRequest"); + if (httpRequestClass == nullptr) { + env->ExceptionDescribe(); + } + + httpRequestStartId = env->GetMethodID(httpRequestClass, "start", "()V"); + if (httpRequestStartId == nullptr) { + env->ExceptionDescribe(); + } + + httpRequestCancelId = env->GetMethodID(httpRequestClass, "cancel", "()V"); + if (httpRequestCancelId == nullptr) { + env->ExceptionDescribe(); + } + + const std::vector methods = { + {"nativeCreate", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;FIJ)J", + reinterpret_cast(&nativeCreate)}, + {"nativeDestroy", "(J)V", reinterpret_cast(&nativeDestroy)}, + {"nativeInitializeDisplay", "(J)V", reinterpret_cast(&nativeInitializeDisplay)}, + {"nativeTerminateDisplay", "(J)V", reinterpret_cast(&nativeTerminateDisplay)}, + {"nativeInitializeContext", "(J)V", reinterpret_cast(&nativeInitializeContext)}, + {"nativeTerminateContext", "(J)V", reinterpret_cast(&nativeTerminateContext)}, + {"nativeCreateSurface", "(JLandroid/view/Surface;)V", + reinterpret_cast(&nativeCreateSurface)}, + {"nativeDestroySurface", "(J)V", reinterpret_cast(&nativeDestroySurface)}, + {"nativePause", "(J)V", reinterpret_cast(&nativePause)}, + {"nativeResume", "(J)V", reinterpret_cast(&nativeResume)}, + {"nativeUpdate", "(J)V", reinterpret_cast(&nativeUpdate)}, + {"nativeOnInvalidate", "(J)V", reinterpret_cast(&nativeOnInvalidate)}, + {"nativeViewResize", "(JII)V", + reinterpret_cast(static_cast(&nativeViewResize))}, + {"nativeFramebufferResize", "(JII)V", + reinterpret_cast(static_cast(&nativeFramebufferResize))}, + {"nativeAddClass", "(JLjava/lang/String;)V", + reinterpret_cast(&nativeAddClass)}, + {"nativeRemoveClass", "(JLjava/lang/String;)V", + reinterpret_cast(&nativeRemoveClass)}, + {"nativeHasClass", "(JLjava/lang/String;)Z", + reinterpret_cast(&nativeHasClass)}, + {"nativeSetClasses", "(JLjava/util/List;)V", + reinterpret_cast(&nativeSetClasses)}, + {"nativeGetClasses", "(J)Ljava/util/List;", + reinterpret_cast(&nativeGetClasses)}, + {"nativeSetDefaultTransitionDuration", "(JJ)V", + reinterpret_cast(&nativeSetDefaultTransitionDuration)}, + {"nativeGetDefaultTransitionDuration", "(J)J", + reinterpret_cast(&nativeGetDefaultTransitionDuration)}, + {"nativeSetStyleUrl", "(JLjava/lang/String;)V", + reinterpret_cast(&nativeSetStyleURL)}, + {"nativeSetStyleJson", "(JLjava/lang/String;Ljava/lang/String;)V", + reinterpret_cast(&nativeSetStyleJSON)}, + {"nativeGetStyleJson", "(J)Ljava/lang/String;", + reinterpret_cast(&nativeGetStyleJSON)}, + {"nativeSetAccessToken", "(JLjava/lang/String;)V", + reinterpret_cast(&nativeSetAccessToken)}, + {"nativeGetAccessToken", "(J)Ljava/lang/String;", + reinterpret_cast(&nativeGetAccessToken)}, + {"nativeCancelTransitions", "(J)V", reinterpret_cast(&nativeCancelTransitions)}, + {"nativeSetGestureInProgress", "(JZ)V", reinterpret_cast(&nativeSetGestureInProgress)}, + {"nativeMoveBy", "(JDDJ)V", reinterpret_cast(&nativeMoveBy)}, + {"nativeSetLatLng", "(JLcom/mapbox/mapboxgl/geometry/LatLng;J)V", + reinterpret_cast(&nativeSetLatLng)}, + {"nativeGetLatLng", "(J)Lcom/mapbox/mapboxgl/geometry/LatLng;", + reinterpret_cast(&nativeGetLatLng)}, + {"nativeResetPosition", "(J)V", reinterpret_cast(&nativeResetPosition)}, + {"nativeScaleBy", "(JDDDJ)V", reinterpret_cast(&nativeScaleBy)}, + {"nativeSetScale", "(JDDDJ)V", reinterpret_cast(&nativeSetScale)}, + {"nativeGetScale", "(J)D", reinterpret_cast(&nativeGetScale)}, + {"nativeSetZoom", "(JDJ)V", reinterpret_cast(&nativeSetZoom)}, + {"nativeGetZoom", "(J)D", reinterpret_cast(&nativeGetZoom)}, + {"nativeSetLatLngZoom", "(JLcom/mapbox/mapboxgl/geometry/LatLngZoom;J)V", + reinterpret_cast(&nativeSetLatLngZoom)}, + {"nativeGetLatLngZoom", "(J)Lcom/mapbox/mapboxgl/geometry/LatLngZoom;", + reinterpret_cast(&nativeGetLatLngZoom)}, + {"nativeResetZoom", "(J)V", reinterpret_cast(&nativeResetZoom)}, + {"nativeGetMinZoom", "(J)D", reinterpret_cast(&nativeGetMinZoom)}, + {"nativeGetMaxZoom", "(J)D", reinterpret_cast(&nativeGetMaxZoom)}, + {"nativeRotateBy", "(JDDDDJ)V", reinterpret_cast(&nativeRotateBy)}, + {"nativeSetBearing", "(JDJ)V", + reinterpret_cast( + static_cast( + &nativeSetBearing))}, + {"nativeSetBearing", "(JDDD)V", + reinterpret_cast( + static_cast( + &nativeSetBearing))}, + {"nativeGetBearing", "(J)D", reinterpret_cast(&nativeGetBearing)}, + {"nativeResetNorth", "(J)V", reinterpret_cast(&nativeResetNorth)}, + {"nativeAddMarker", "(JLcom/mapbox/mapboxgl/annotations/Marker;)J", + reinterpret_cast(&nativeAddMarker)}, + {"nativeAddPolyline", "(JLcom/mapbox/mapboxgl/annotations/Polyline;)J", + reinterpret_cast(&nativeAddPolyline)}, + {"nativeAddPolygon", "(JLcom/mapbox/mapboxgl/annotations/Polygon;)J", + reinterpret_cast(&nativeAddPolygon)}, + {"nativeAddPolygons", "(JLjava/util/List;)[J", + reinterpret_cast(&nativeAddPolygons)}, + {"nativeRemoveAnnotation", "(JJ)V", reinterpret_cast(&nativeRemoveAnnotation)}, + {"nativeRemoveAnnotations", "(J[J)V", reinterpret_cast(&nativeRemoveAnnotations)}, + {"nativeSetSprite", "(JLjava/lang/String;IIF[B)V", reinterpret_cast(&nativeSetSprite)}, + {"nativeOnLowMemory", "(J)V", reinterpret_cast(&nativeOnLowMemory)}, + {"nativeSetDebug", "(JZ)V", reinterpret_cast(&nativeSetDebug)}, + {"nativeToggleDebug", "(J)V", reinterpret_cast(&nativeToggleDebug)}, + {"nativeGetDebug", "(J)Z", reinterpret_cast(&nativeGetDebug)}, + {"nativeSetCollisionDebug", "(JZ)V", reinterpret_cast(&nativeSetCollisionDebug)}, + {"nativeToggleCollisionDebug", "(J)V", reinterpret_cast(&nativeToggleCollisionDebug)}, + {"nativeGetCollisionDebug", "(J)Z", reinterpret_cast(&nativeGetCollisionDebug)}, + {"nativeIsFullyLoaded", "(J)Z", reinterpret_cast(&nativeIsFullyLoaded)}, + {"nativeSetReachability", "(JZ)V", reinterpret_cast(&nativeSetReachability)}, + //{"nativeGetWorldBoundsMeters", "(J)V", reinterpret_cast(&nativeGetWorldBoundsMeters)}, + //{"nativeGetWorldBoundsLatLng", "(J)V", reinterpret_cast(&nativeGetWorldBoundsLatLng)}, + {"nativeGetMetersPerPixelAtLatitude", "(JDD)D", reinterpret_cast(&nativeGetMetersPerPixelAtLatitude)}, + {"nativeProjectedMetersForLatLng", + "(JLcom/mapbox/mapboxgl/geometry/LatLng;)Lcom/mapbox/mapboxgl/geometry/ProjectedMeters;", + reinterpret_cast(&nativeProjectedMetersForLatLng)}, + {"nativeLatLngForProjectedMeters", + "(JLcom/mapbox/mapboxgl/geometry/ProjectedMeters;)Lcom/mapbox/mapboxgl/geometry/LatLng;", + reinterpret_cast(&nativeLatLngForProjectedMeters)}, + {"nativePixelForLatLng", "(JLcom/mapbox/mapboxgl/geometry/LatLng;)Landroid/graphics/PointF;", + reinterpret_cast(&nativePixelForLatLng)}, + {"nativeLatLngForPixel", "(JLandroid/graphics/PointF;)Lcom/mapbox/mapboxgl/geometry/LatLng;", + reinterpret_cast(&nativeLatLngForPixel)}, + }; + + if (env->RegisterNatives(nativeMapViewClass, methods.data(), methods.size()) < 0) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + latLngClass = reinterpret_cast(env->NewGlobalRef(latLngClass)); + if (latLngClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + latLngZoomClass = reinterpret_cast(env->NewGlobalRef(latLngZoomClass)); + if (latLngZoomClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + return JNI_ERR; + } + + markerClass = reinterpret_cast(env->NewGlobalRef(markerClass)); + if (markerClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); + return JNI_ERR; + } + + polylineClass = reinterpret_cast(env->NewGlobalRef(polylineClass)); + if (polylineClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(markerClass); + return JNI_ERR; + } + + polygonClass = reinterpret_cast(env->NewGlobalRef(polygonClass)); + if (polygonClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(markerClass); + env->DeleteGlobalRef(polylineClass); + return JNI_ERR; + } + + runtimeExceptionClass = reinterpret_cast(env->NewGlobalRef(runtimeExceptionClass)); + if (runtimeExceptionClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(markerClass); + env->DeleteGlobalRef(polylineClass); + env->DeleteGlobalRef(polygonClass); + return JNI_ERR; + } + + nullPointerExceptionClass = + reinterpret_cast(env->NewGlobalRef(nullPointerExceptionClass)); + if (nullPointerExceptionClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(markerClass); + env->DeleteGlobalRef(polylineClass); + env->DeleteGlobalRef(polygonClass); + env->DeleteGlobalRef(runtimeExceptionClass); + return JNI_ERR; + } + + arrayListClass = reinterpret_cast(env->NewGlobalRef(arrayListClass)); + if (arrayListClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(markerClass); + env->DeleteGlobalRef(polylineClass); + env->DeleteGlobalRef(polygonClass); + env->DeleteGlobalRef(runtimeExceptionClass); + env->DeleteGlobalRef(nullPointerExceptionClass); + return JNI_ERR; + } + + projectedMetersClass = reinterpret_cast(env->NewGlobalRef(projectedMetersClass)); + if (projectedMetersClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(markerClass); + env->DeleteGlobalRef(polylineClass); + env->DeleteGlobalRef(polygonClass); + env->DeleteGlobalRef(runtimeExceptionClass); + env->DeleteGlobalRef(nullPointerExceptionClass); + env->DeleteGlobalRef(arrayListClass); + return JNI_ERR; + } + + pointFClass = reinterpret_cast(env->NewGlobalRef(pointFClass)); + if (pointFClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(markerClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(polylineClass); + env->DeleteGlobalRef(polygonClass); + env->DeleteGlobalRef(runtimeExceptionClass); + env->DeleteGlobalRef(nullPointerExceptionClass); + env->DeleteGlobalRef(arrayListClass); + env->DeleteGlobalRef(projectedMetersClass); + return JNI_ERR; + } + + httpContextClass = reinterpret_cast(env->NewGlobalRef(httpContextClass)); + if (httpContextClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(markerClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(polylineClass); + env->DeleteGlobalRef(polygonClass); + env->DeleteGlobalRef(runtimeExceptionClass); + env->DeleteGlobalRef(nullPointerExceptionClass); + env->DeleteGlobalRef(arrayListClass); + env->DeleteGlobalRef(projectedMetersClass); + env->DeleteGlobalRef(pointFClass); + } + + httpRequestClass = reinterpret_cast(env->NewGlobalRef(httpRequestClass)); + if (httpRequestClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(markerClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(polylineClass); + env->DeleteGlobalRef(polygonClass); + env->DeleteGlobalRef(runtimeExceptionClass); + env->DeleteGlobalRef(nullPointerExceptionClass); + env->DeleteGlobalRef(arrayListClass); + env->DeleteGlobalRef(projectedMetersClass); + env->DeleteGlobalRef(pointFClass); + env->DeleteGlobalRef(httpContextClass); + } + + char release[PROP_VALUE_MAX] = ""; + __system_property_get("ro.build.version.release", release); + androidRelease = std::string(release); + + return JNI_VERSION_1_6; +} + +extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { + mbgl::Log::Debug(mbgl::Event::JNI, "JNI_OnUnload"); + + theJVM = vm; + + JNIEnv *env = nullptr; + jint ret = vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + if (ret != JNI_OK) { + mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret); + throw new std::runtime_error("GetEnv() failed"); + } + + env->DeleteGlobalRef(latLngClass); + latLngClass = nullptr; + latLngConstructorId = nullptr; + latLngLongitudeId = nullptr; + latLngLatitudeId = nullptr; + + env->DeleteGlobalRef(latLngZoomClass); + latLngZoomClass = nullptr; + latLngZoomConstructorId = nullptr; + latLngZoomLongitudeId = nullptr; + latLngZoomLatitudeId = nullptr; + latLngZoomZoomId = nullptr; + + env->DeleteGlobalRef(markerClass); + markerClass = nullptr; + markerConstructorId = nullptr; + markerPositionId = nullptr; + markerSpriteId = nullptr; + + env->DeleteGlobalRef(polylineClass); + polylineClass = nullptr; + polylineConstructorId = nullptr; + polylineAlphaId = nullptr; + polylineVisibleId = nullptr; + polylineColorId = nullptr; + polylineWidthId = nullptr; + polylinePointsId = nullptr; + + env->DeleteGlobalRef(polygonClass); + polygonClass = nullptr; + polygonConstructorId = nullptr; + polygonAlphaId = nullptr; + polygonVisibleId = nullptr; + polygonFillColorId = nullptr; + polygonStrokeColorId = nullptr; + polygonStrokeWidthId = nullptr; + polygonPointsId = nullptr; + polygonHolesId = nullptr; + + onInvalidateId = nullptr; + onMapChangedId = nullptr; + onFpsChangedId = nullptr; + + env->DeleteGlobalRef(runtimeExceptionClass); + runtimeExceptionClass = nullptr; + + env->DeleteGlobalRef(nullPointerExceptionClass); + nullPointerExceptionClass = nullptr; + + listToArrayId = nullptr; + + env->DeleteGlobalRef(arrayListClass); + arrayListClass = nullptr; + arrayListConstructorId = nullptr; + arrayListAddId = nullptr; + + env->DeleteGlobalRef(projectedMetersClass); + projectedMetersClass = nullptr; + projectedMetersConstructorId = nullptr; + projectedMetersNorthingId = nullptr; + projectedMetersEastingId = nullptr; + + env->DeleteGlobalRef(pointFClass); + pointFClass = nullptr; + pointFConstructorId = nullptr; + pointFXId = nullptr; + pointFYId = nullptr; + + env->DeleteGlobalRef(httpContextClass); + httpContextGetInstanceId = nullptr; + httpContextCreateRequestId = nullptr; + + env->DeleteGlobalRef(httpRequestClass); + httpRequestStartId = nullptr; + httpRequestCancelId = nullptr; + + theJVM = nullptr; +} +} diff --git a/android/cpp/native_map_view.cpp b/android/cpp/native_map_view.cpp new file mode 100644 index 000000000..d7c40ba5a --- /dev/null +++ b/android/cpp/native_map_view.cpp @@ -0,0 +1,728 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace mbgl { +namespace android { + +void log_egl_string(EGLDisplay display, EGLint name, const char *label) { + const char *str = eglQueryString(display, name); + if (str == nullptr) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglQueryString(%d) returned error %d", name, + eglGetError()); + throw new std::runtime_error("eglQueryString() failed"); + } else { + char buf[513]; + for (int len = std::strlen(str), pos = 0; len > 0; len -= 512, pos += 512) { + strncpy(buf, str + pos, 512); + buf[512] = 0; + mbgl::Log::Info(mbgl::Event::OpenGL, "EGL %s: %s", label, buf); + } + } +} + +void log_gl_string(GLenum name, const char *label) { + const GLubyte *str = glGetString(name); + if (str == nullptr) { + mbgl::Log::Error(mbgl::Event::OpenGL, "glGetString(%d) returned error %d", name, + glGetError()); + throw new std::runtime_error("glGetString() failed"); + } else { + char buf[513]; + for (int len = std::strlen(reinterpret_cast(str)), pos = 0; len > 0; + len -= 512, pos += 512) { + strncpy(buf, reinterpret_cast(str) + pos, 512); + buf[512] = 0; + mbgl::Log::Info(mbgl::Event::OpenGL, "GL %s: %s", label, buf); + } + } +} + +NativeMapView::NativeMapView(JNIEnv *env, jobject obj_, float pixelRatio_, int availableProcessors_, size_t totalMemory_) + : mbgl::View(*this), + pixelRatio(pixelRatio_), + availableProcessors(availableProcessors_), + totalMemory(totalMemory_), + fileCache(mbgl::android::cachePath + "/mbgl-cache.db"), + fileSource(&fileCache), + map(*this, fileSource, MapMode::Continuous) { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::NativeMapView"); + + map.pause(); + + assert(env != nullptr); + assert(obj_ != nullptr); + + if (env->GetJavaVM(&vm) < 0) { + env->ExceptionDescribe(); + return; + } + + obj = env->NewGlobalRef(obj_); + if (obj == nullptr) { + env->ExceptionDescribe(); + return; + } +} + +NativeMapView::~NativeMapView() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::~NativeMapView"); + terminateContext(); + destroySurface(); + terminateDisplay(); + + assert(vm != nullptr); + assert(obj != nullptr); + + jint ret; + JNIEnv *env = nullptr; + ret = vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + if (ret == JNI_OK) { + env->DeleteGlobalRef(obj); + } else { + mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret); + throw new std::runtime_error("GetEnv() failed"); + } + obj = nullptr; + vm = nullptr; +} + +float NativeMapView::getPixelRatio() const { + return pixelRatio; +} + +std::array NativeMapView::getSize() const { + return {{ static_cast(width), static_cast(height) }}; +} + +std::array NativeMapView::getFramebufferSize() const { + return {{ static_cast(fbWidth), static_cast(fbHeight) }}; +} + +void NativeMapView::activate() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::activate"); + if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE) && (context != EGL_NO_CONTEXT)) { + if (!eglMakeCurrent(display, surface, surface, context)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d", + eglGetError()); + throw new std::runtime_error("eglMakeCurrent() failed"); + } + } else { + mbgl::Log::Info(mbgl::Event::Android, "Not activating as we are not ready"); + } +} + +void NativeMapView::deactivate() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::deactivate"); + if (display != EGL_NO_DISPLAY) { + if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", + eglGetError()); + throw new std::runtime_error("eglMakeCurrent() failed"); + } + } else { + mbgl::Log::Info(mbgl::Event::Android, "Not deactivating as we are not ready"); + } +} + +void NativeMapView::invalidate() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::invalidate()"); + + clean.clear(); + + assert(vm != nullptr); + assert(obj != nullptr); + + JNIEnv *env = nullptr; + bool detach = attach_jni_thread(vm, &env, "NativeMapView::invalidate()"); + + env->CallVoidMethod(obj, onInvalidateId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + } + + detach_jni_thread(vm, &env, detach); +} + +void NativeMapView::swap() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::swap"); + + if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) { + if (!eglSwapBuffers(display, surface)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglSwapBuffers() returned error %d", + eglGetError()); + throw new std::runtime_error("eglSwapBuffers() failed"); + } + updateFps(); + } else { + mbgl::Log::Info(mbgl::Event::Android, "Not swapping as we are not ready"); + } +} + +void NativeMapView::notify() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::notify()"); + // noop +} + +mbgl::Map &NativeMapView::getMap() { return map; } + +mbgl::DefaultFileSource &NativeMapView::getFileSource() { return fileSource; } + +bool NativeMapView::inEmulator() { + // Detect if we are in emulator + char prop[PROP_VALUE_MAX]; + __system_property_get("ro.kernel.qemu", prop); + return strtol(prop, nullptr, 0) == 1; +} + +void NativeMapView::initializeDisplay() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::initializeDisplay"); + + assert(display == EGL_NO_DISPLAY); + assert(config == nullptr); + assert(format < 0); + + display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (display == EGL_NO_DISPLAY) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglGetDisplay() returned error %d", eglGetError()); + throw new std::runtime_error("eglGetDisplay() failed"); + } + + EGLint major, minor; + if (!eglInitialize(display, &major, &minor)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglInitialize() returned error %d", eglGetError()); + throw new std::runtime_error("eglInitialize() failed"); + } + if ((major <= 1) && (minor < 3)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "EGL version is too low, need 1.3, got %d.%d", major, + minor); + throw new std::runtime_error("EGL version is too low"); + } + + log_egl_string(display, EGL_VENDOR, "Vendor"); + log_egl_string(display, EGL_VERSION, "Version"); + log_egl_string(display, EGL_CLIENT_APIS, "Client APIs"); + log_egl_string(display, EGL_EXTENSIONS, "Client Extensions"); + + // Detect if we are in emulator + if (inEmulator()) { + mbgl::Log::Warning(mbgl::Event::Android, "In emulator! Enabling hacks :-("); + } + + // Get all configs at least RGB 565 with 16 depth and 8 stencil + EGLint configAttribs[] = { + EGL_CONFIG_CAVEAT, EGL_NONE, EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_BUFFER_SIZE, 16, EGL_RED_SIZE, + 5, EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, + 16, EGL_STENCIL_SIZE, 8, + (inEmulator() ? EGL_NONE : EGL_CONFORMANT), EGL_OPENGL_ES2_BIT, // Ugly hack + (inEmulator() ? EGL_NONE : EGL_COLOR_BUFFER_TYPE), EGL_RGB_BUFFER, // Ugly hack + EGL_NONE}; + EGLint numConfigs; + if (!eglChooseConfig(display, configAttribs, nullptr, 0, &numConfigs)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig(NULL) returned error %d", + eglGetError()); + throw new std::runtime_error("eglChooseConfig() failed"); + } + if (numConfigs < 1) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig() returned no configs."); + throw new std::runtime_error("eglChooseConfig() failed"); + } + + const auto configs = std::make_unique(numConfigs); + if (!eglChooseConfig(display, configAttribs, configs.get(), numConfigs, &numConfigs)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig() returned error %d", eglGetError()); + throw new std::runtime_error("eglChooseConfig() failed"); + } + + config = chooseConfig(configs.get(), numConfigs); + if (config == nullptr) { + mbgl::Log::Error(mbgl::Event::OpenGL, "No config chosen"); + throw new std::runtime_error("No config chosen"); + } + + if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglGetConfigAttrib() returned error %d", + eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + mbgl::Log::Info(mbgl::Event::OpenGL, "Chosen window format is %d", format); +} + +void NativeMapView::terminateDisplay() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::terminateDisplay"); + + if (display != EGL_NO_DISPLAY) { + // Destroy the surface first, if it still exists. This call needs a valid surface. + if (surface != EGL_NO_SURFACE) { + if (!eglDestroySurface(display, surface)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d", + eglGetError()); + throw new std::runtime_error("eglDestroySurface() failed"); + } + surface = EGL_NO_SURFACE; + } + + if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError()); + throw new std::runtime_error("eglMakeCurrent() failed"); + } + + if (!eglTerminate(display)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglTerminate() returned error %d", + eglGetError()); + throw new std::runtime_error("eglTerminate() failed"); + } + } + + display = EGL_NO_DISPLAY; + config = nullptr; + format = -1; +} + +void NativeMapView::initializeContext() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::initializeContext"); + + assert(display != EGL_NO_DISPLAY); + assert(context == EGL_NO_CONTEXT); + assert(config != nullptr); + + const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); + if (context == EGL_NO_CONTEXT) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error %d", + eglGetError()); + throw new std::runtime_error("eglCreateContext() failed"); + } +} + +void NativeMapView::terminateContext() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::terminateContext"); + if (display != EGL_NO_DISPLAY) { + + if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError()); + throw new std::runtime_error("eglMakeCurrent() failed"); + } + + if (context != EGL_NO_CONTEXT) { + if (!eglDestroyContext(display, context)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroyContext() returned error %d", + eglGetError()); + throw new std::runtime_error("eglDestroyContext() failed"); + } + } + } + + context = EGL_NO_CONTEXT; +} + +void NativeMapView::createSurface(ANativeWindow *window_) { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::createSurface"); + + assert(window == nullptr); + assert(window_ != nullptr); + window = window_; + + assert(display != EGL_NO_DISPLAY); + assert(surface == EGL_NO_SURFACE); + assert(config != nullptr); + assert(format >= 0); + + ANativeWindow_setBuffersGeometry(window, 0, 0, format); + + const EGLint surfaceAttribs[] = {EGL_NONE}; + surface = eglCreateWindowSurface(display, config, window, surfaceAttribs); + if (surface == EGL_NO_SURFACE) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateWindowSurface() returned error %d", + eglGetError()); + throw new std::runtime_error("eglCreateWindowSurface() failed"); + } + + if (!firstTime) { + firstTime = true; + + if (!eglMakeCurrent(display, surface, surface, context)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d", + eglGetError()); + throw new std::runtime_error("eglMakeCurrent() failed"); + } + + log_gl_string(GL_VENDOR, "Vendor"); + log_gl_string(GL_RENDERER, "Renderer"); + log_gl_string(GL_VERSION, "Version"); + if (!inEmulator()) { + log_gl_string(GL_SHADING_LANGUAGE_VERSION, + "SL Version"); // In the emulator this returns NULL with error code 0? + // https://code.google.com/p/android/issues/detail?id=78977 + } + + log_gl_string(GL_EXTENSIONS, "Extensions"); + mbgl::gl::InitializeExtensions([] (const char * name) { + return reinterpret_cast(eglGetProcAddress(name)); + }); + + if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError()); + throw new std::runtime_error("eglMakeCurrent() failed"); + } + } + + resume(); +} + +void NativeMapView::destroySurface() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::destroySurface"); + + pause(); + + if (surface != EGL_NO_SURFACE) { + if (!eglDestroySurface(display, surface)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d", + eglGetError()); + throw new std::runtime_error("eglDestroySurface() failed"); + } + } + + surface = EGL_NO_SURFACE; + + if (window != nullptr) { + ANativeWindow_release(window); + window = nullptr; + } +} + +// Speed +/* +typedef enum { + Format16Bit = 0, + Format32BitNoAlpha = 1, + Format32BitAlpha = 2, + Format24Bit = 3, + Unknown = 4 +} BufferFormat; + +typedef enum { + Format16Depth8Stencil = 0, + Format24Depth8Stencil = 1, +} DepthStencilFormat; +*/ + +// Quality +typedef enum { + Format16Bit = 3, + Format32BitNoAlpha = 1, + Format32BitAlpha = 2, + Format24Bit = 0, + Unknown = 4 +} BufferFormat; + +typedef enum { + Format16Depth8Stencil = 1, + Format24Depth8Stencil = 0, +} DepthStencilFormat; + +// Tuple is +typedef std::tuple ConfigProperties; + +EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[], EGLint numConfigs) { + mbgl::Log::Info(mbgl::Event::OpenGL, "Found %d configs", numConfigs); + + // Create a list of configs that pass our filters + std::list configList; + for (int i = 0; i < numConfigs; i++) { + mbgl::Log::Info(mbgl::Event::OpenGL, "Config %d:", i); + + EGLint caveat, conformant, bits, red, green, blue, alpha, alphaMask, depth, stencil, + sampleBuffers, samples; + + if (!eglGetConfigAttrib(display, configs[i], EGL_CONFIG_CAVEAT, &caveat)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_CONFIG_CAVEAT) returned error %d", + eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_CONFORMANT, &conformant)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_CONFORMANT) returned error %d", eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_BUFFER_SIZE, &bits)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_BUFFER_SIZE) returned error %d", + eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &red)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_RED_SIZE) returned error %d", eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &green)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_GREEN_SIZE) returned error %d", eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &blue)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_BLUE_SIZE) returned error %d", eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &alpha)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_ALPHA_SIZE) returned error %d", eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_ALPHA_MASK_SIZE, &alphaMask)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_ALPHA_MASK_SIZE) returned error %d", + eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_DEPTH_SIZE, &depth)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_DEPTH_SIZE) returned error %d", eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_STENCIL_SIZE, &stencil)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_STENCIL_SIZE) returned error %d", + eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_SAMPLE_BUFFERS, &sampleBuffers)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_SAMPLE_BUFFERS) returned error %d", + eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + if (!eglGetConfigAttrib(display, configs[i], EGL_SAMPLES, &samples)) { + mbgl::Log::Error(mbgl::Event::OpenGL, + "eglGetConfigAttrib(EGL_SAMPLES) returned error %d", eglGetError()); + throw new std::runtime_error("eglGetConfigAttrib() failed"); + } + + mbgl::Log::Info(mbgl::Event::OpenGL, "...Caveat: %d", caveat); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Conformant: %d", conformant); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Color: %d", bits); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Red: %d", red); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Green: %d", green); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Blue: %d", blue); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Alpha: %d", alpha); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Alpha mask: %d", alphaMask); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Depth: %d", depth); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Stencil: %d", stencil); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Sample buffers: %d", sampleBuffers); + mbgl::Log::Info(mbgl::Event::OpenGL, "...Samples: %d", samples); + + bool configOk = true; + configOk &= (depth == 24) || (depth == 16); + configOk &= stencil == 8; + configOk &= sampleBuffers == 0; + configOk &= samples == 0; + + // Filter our configs first for depth, stencil and anti-aliasing + if (configOk) { + // Work out the config's buffer format + BufferFormat bufferFormat; + if ((bits == 16) && (red == 5) && (green == 6) && (blue == 5) && (alpha == 0)) { + bufferFormat = Format16Bit; + } else if ((bits == 32) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 0)) { + bufferFormat = Format32BitNoAlpha; + } else if ((bits == 32) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 8)) { + bufferFormat = Format32BitAlpha; + } else if ((bits == 24) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 0)) { + bufferFormat = Format24Bit; + } else { + bufferFormat = Unknown; + } + + // Work out the config's depth stencil format + DepthStencilFormat depthStencilFormat; + if ((depth == 16) && (stencil == 8)) { + depthStencilFormat = Format16Depth8Stencil; + } else { + depthStencilFormat = Format24Depth8Stencil; + } + + bool isNotConformant = (conformant & EGL_OPENGL_ES2_BIT) != EGL_OPENGL_ES2_BIT; + bool isCaveat = caveat != EGL_NONE; + EGLConfig configId = configs[i]; + + // Ignore formats we don't recognise + if (bufferFormat != Unknown) { + configList.push_back(std::make_tuple(bufferFormat, depthStencilFormat, + isNotConformant, isCaveat, i, configId)); + } + } + } + + if (configList.empty()) { + mbgl::Log::Error(mbgl::Event::OpenGL, "Config list was empty."); + } + + // Sort the configs to find the best one + configList.sort(); + bool isConformant = !std::get<2>(configList.front()); + bool isCaveat = std::get<3>(configList.front()); + int configNum = std::get<4>(configList.front()); + EGLConfig configId = std::get<5>(configList.front()); + + mbgl::Log::Info(mbgl::Event::OpenGL, "Chosen config is %d", configNum); + + if (isCaveat) { + mbgl::Log::Warning(mbgl::Event::OpenGL, "Chosen config has a caveat."); + } + if (!isConformant) { + mbgl::Log::Warning(mbgl::Event::OpenGL, "Chosen config is not conformant."); + } + + return configId; +} + +void NativeMapView::pause() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::pause"); + + if ((display != EGL_NO_DISPLAY) && (context != EGL_NO_CONTEXT)) { + map.pause(); + } +} + +void NativeMapView::resume() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::resume"); + + assert(display != EGL_NO_DISPLAY); + assert(context != EGL_NO_CONTEXT); + + if (surface != EGL_NO_SURFACE) { + map.resume(); + } else { + mbgl::Log::Debug(mbgl::Event::Android, "Not resuming because we are not ready"); + } +} + +void NativeMapView::notifyMapChange(mbgl::MapChange) { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::notifyMapChange()"); + + assert(vm != nullptr); + assert(obj != nullptr); + + JNIEnv *env = nullptr; + bool detach = attach_jni_thread(vm, &env, "NativeMapView::notifyMapChange()"); + + env->CallVoidMethod(obj, onMapChangedId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + } + + detach_jni_thread(vm, &env, detach); +} + +void NativeMapView::enableFps(bool enable) { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::enableFps()"); + + fpsEnabled = enable; +} + +void NativeMapView::updateFps() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::updateFps()"); + + if (!fpsEnabled) { + return; + } + + static int frames = 0; + static int64_t timeElapsed = 0LL; + + frames++; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + int64_t currentTime = now.tv_sec * 1000000000LL + now.tv_nsec; + + if (currentTime - timeElapsed >= 1) { + fps = frames / ((currentTime - timeElapsed) / 1E9); + mbgl::Log::Debug(mbgl::Event::Render, "FPS: %4.2f", fps); + timeElapsed = currentTime; + frames = 0; + } + + assert(vm != nullptr); + assert(obj != nullptr); + + JNIEnv *env = nullptr; + bool detach = attach_jni_thread(vm, &env, "NativeMapView::updateFps()"); + + env->CallVoidMethod(obj, onFpsChangedId, fps); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + } + + detach_jni_thread(vm, &env, detach); +} + +void NativeMapView::onInvalidate() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::onInvalidate()"); + + const bool dirty = !clean.test_and_set(); + if (dirty) { + float zoomFactor = map.getMaxZoom() - map.getMinZoom() + 1; + float cpuFactor = availableProcessors; + float memoryFactor = static_cast(totalMemory) / 1000.0f / 1000.0f / 1000.0f; + float sizeFactor = (static_cast(map.getWidth()) / mbgl::util::tileSize) * + (static_cast(map.getHeight()) / mbgl::util::tileSize); + + size_t cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f; + + map.setSourceTileCacheSize(cacheSize); + + map.renderSync(); + map.nudgeTransitions(); + } +} + +void NativeMapView::resizeView(int w, int h) { + width = w; + height = h; + map.update(mbgl::Update::Dimensions); +} + +void NativeMapView::resizeFramebuffer(int w, int h) { + fbWidth = w; + fbHeight = h; + map.update(mbgl::Update::Repaint); +} + +} +} diff --git a/android/java/.gitignore b/android/java/.gitignore new file mode 100644 index 000000000..866441810 --- /dev/null +++ b/android/java/.gitignore @@ -0,0 +1,23 @@ +# Gradle files +.gradle/ + +# IntelliJ files +.idea/ +*.iml + +# Build files +build/ +*.so +*.apk + +# Lib assets +MapboxGLAndroidSDK/src/main/assets/ + +# Local settings +local.properties + +# Token file +MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt + +# Twitter Fabric / Crashlytics +fabric.properties diff --git a/android/java/MapboxGLAndroidSDK/build.gradle b/android/java/MapboxGLAndroidSDK/build.gradle new file mode 100644 index 000000000..b749765eb --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/build.gradle @@ -0,0 +1,256 @@ +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.0' + classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' + } +} + +apply plugin: 'android-sdk-manager' +apply plugin: 'com.android.library' +apply plugin: 'checkstyle' +apply plugin: 'maven' +apply plugin: 'signing' + +allprojects { + group project.GROUP + version project.VERSION_NAME + + repositories { + mavenCentral() + } +} + +repositories { + mavenCentral() +} + +dependencies { + compile 'com.android.support:support-annotations:23.0.0' + compile 'com.android.support:support-v4:23.0.0' + compile 'com.android.support:design:23.0.0' + compile 'com.squareup.okhttp:okhttp:2.4.0' + compile 'com.mapzen.android:lost:1.0.1' +} + +android { + compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) + buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION + + defaultConfig { + minSdkVersion Integer.parseInt(project.ANDROID_MIN_SDK) + targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) + } + + repositories { + mavenCentral() + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + lintOptions { + checkAllWarnings true + warningsAsErrors true + disable 'InvalidPackage' + } + + buildTypes { + debug { + jniDebuggable true + } + + release { + minifyEnabled false + jniDebuggable false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +configurations { + all*.exclude group: 'commons-logging', module: 'commons-logging' + all*.exclude group: 'commons-collections', module: 'commons-collections' +} + + +android.libraryVariants.all { variant -> + def name = variant.name + task "javadoc$name"(type: Javadoc) { + description = "Generates javadoc for build $name" + failOnError = false + destinationDir = new File(destinationDir, variant.baseName) + source = files(variant.javaCompile.source) + classpath = files(variant.javaCompile.classpath.files) + files(android.bootClasspath) + options.links("http://docs.oracle.com/javase/7/docs/api/") + options.links("http://d.android.com/reference/") + exclude '**/R.html', '**/R.*.html' + } +} + +checkstyle { + configFile project.file('../checks.xml') + showViolations true +} + +/* +task cleanJNIBuilds { + def jniLibsDir = new File("MapboxGLAndroidSDK/src/main/jniLibs") + delete jniLibsDir.absolutePath +} +*/ + +android.libraryVariants.all { variant -> + def name = variant.buildType.name + def checkstyle = project.tasks.create "checkstyle${name.capitalize()}", Checkstyle + checkstyle.dependsOn variant.javaCompile + checkstyle.source variant.javaCompile.source + checkstyle.classpath = project.fileTree(variant.javaCompile.destinationDir) + checkstyle.exclude('**/BuildConfig.java') + checkstyle.exclude('**/R.java') + checkstyle.exclude('**/com/almeros/android/multitouch/**') + project.tasks.getByName("check").dependsOn checkstyle +} + +// From https://raw.github.com/mcxiaoke/gradle-mvn-push/master/jar.gradle +android.libraryVariants.all { variant -> + def jarTask = project.tasks.create(name: "jar${variant.name.capitalize()}", type: Jar) { + from variant.javaCompile.destinationDir + exclude "**/R.class" + exclude "**/BuildConfig.class" + } + jarTask.dependsOn variant.javaCompile + artifacts.add('archives', jarTask); +} + +// From https://raw.github.com/mcxiaoke/gradle-mvn-push/master/gradle-mvn-push.gradle +def isReleaseBuild() { + return VERSION_NAME.contains("SNAPSHOT") == false +} + +def getReleaseRepositoryUrl() { + return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL : + "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +} + +def getSnapshotRepositoryUrl() { + return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL : + "https://oss.sonatype.org/content/repositories/snapshots/" +} + +def getRepositoryUsername() { + return hasProperty('USERNAME') ? USERNAME : + (hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "") +} + +def getRepositoryPassword() { + return hasProperty('PASSWORD') ? PASSWORD : + (hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "") +} + + +task apklib(type: Zip) { + appendix = extension = 'apklib' + + from 'AndroidManifest.xml' + into('res') { + from 'res' + } + into('src') { + from 'src' + } +} + +artifacts { + archives apklib +} + +afterEvaluate { project -> + uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + pom.groupId = GROUP + pom.artifactId = POM_ARTIFACT_ID + pom.version = VERSION_NAME + + repository(url: getReleaseRepositoryUrl()) { + authentication(userName: getRepositoryUsername(), + password: getRepositoryPassword()) + } + snapshotRepository(url: getSnapshotRepositoryUrl()) { + authentication(userName: getRepositoryUsername(), + password: getRepositoryPassword()) + } + +/* + // Leaving out as artifact was incorrectly named when found + addFilter('aar') { artifact, file -> + artifact.name == archivesBaseName + } + addFilter('apklib') { artifact, file -> + artifact.name == archivesBaseName + '-apklib' + } +*/ + + pom.project { + name POM_NAME + packaging POM_PACKAGING + description POM_DESCRIPTION + url POM_URL + + scm { + url POM_SCM_URL + connection POM_SCM_CONNECTION + developerConnection POM_SCM_DEV_CONNECTION + } + + licenses { + license { + name POM_LICENCE_NAME + url POM_LICENCE_URL + distribution POM_LICENCE_DIST + } + } + + developers { + developer { + id POM_DEVELOPER_ID + name POM_DEVELOPER_NAME + } + } + } + } + } + } + + signing { + required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } + sign configurations.archives + } + + task androidJavadocs(type: Javadoc) { + source = android.sourceSets.main.java.sourceFiles + classpath = files(android.bootClasspath) + } + + task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { + classifier = 'javadoc' + from androidJavadocs.destinationDir + } + + task androidSourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.sourceFiles + } + + artifacts { + archives androidSourcesJar + archives androidJavadocsJar + } +} diff --git a/android/java/MapboxGLAndroidSDK/deploy.sh b/android/java/MapboxGLAndroidSDK/deploy.sh new file mode 100755 index 000000000..c9392201e --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/deploy.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +../gradlew -b build.gradle clean assembleRelease uploadArchives diff --git a/android/java/MapboxGLAndroidSDK/gradle.properties b/android/java/MapboxGLAndroidSDK/gradle.properties new file mode 100644 index 000000000..a441dfd27 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/gradle.properties @@ -0,0 +1,22 @@ +GROUP=com.mapbox.mapboxgl +VERSION_NAME=0.0.1-SNAPSHOT + +POM_DESCRIPTION=Mapbox GL Android SDK +POM_URL=https://github.com/mapbox/mapbox-gl-native +POM_SCM_URL=https://github.com/mapbox/mapbox-gl-native +POM_SCM_CONNECTION=scm:git@github.com:mapbox/mapbox-gl-native.git +POM_SCM_DEV_CONNECTION=scm:git@github.com:mapbox/mapbox-gl-native.git +POM_LICENCE_NAME=The Apache Software License, Version 2.0 +POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt +POM_LICENCE_DIST=repo +POM_DEVELOPER_ID=mapbox +POM_DEVELOPER_NAME=Mapbox + +ANDROID_MIN_SDK=8 +ANDROID_BUILD_TARGET_SDK_VERSION=23 +ANDROID_BUILD_TOOLS_VERSION=23 +ANDROID_BUILD_SDK_VERSION=23 + +POM_NAME=Mapbox GL Android SDK +POM_ARTIFACT_ID=mapbox-gl-android-sdk +POM_PACKAGING=aar diff --git a/android/java/MapboxGLAndroidSDK/lint.xml b/android/java/MapboxGLAndroidSDK/lint.xml new file mode 100644 index 000000000..3a244199a --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/lint.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/android/java/MapboxGLAndroidSDK/src/main/AndroidManifest.xml b/android/java/MapboxGLAndroidSDK/src/main/AndroidManifest.xml new file mode 100644 index 000000000..471582eb6 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java new file mode 100644 index 000000000..622e8f759 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java @@ -0,0 +1,161 @@ +package com.almeros.android.multitouch.gesturedetectors; + +import android.content.Context; +import android.view.MotionEvent; + +/** + * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie + * (code.almeros.com) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +public abstract class BaseGestureDetector { + protected final Context mContext; + protected boolean mGestureInProgress; + + protected MotionEvent mPrevEvent; + protected MotionEvent mCurrEvent; + + protected float mCurrPressure; + protected float mPrevPressure; + protected long mTimeDelta; + + /** + * This value is the threshold ratio between the previous combined pressure + * and the current combined pressure. When pressure decreases rapidly + * between events the position values can often be imprecise, as it usually + * indicates that the user is in the process of lifting a pointer off of the + * device. This value was tuned experimentally. + */ + protected static final float PRESSURE_THRESHOLD = 0.67f; + + public BaseGestureDetector(Context context) { + mContext = context; + } + + /** + * All gesture detectors need to be called through this method to be able to + * detect gestures. This method delegates work to handler methods + * (handleStartProgressEvent, handleInProgressEvent) implemented in + * extending classes. + * + * @param event MotionEvent + * @return {@code true} as handled + */ + public boolean onTouchEvent(MotionEvent event) { + final int actionCode = event.getAction() & MotionEvent.ACTION_MASK; + if (!mGestureInProgress) { + handleStartProgressEvent(actionCode, event); + } else { + handleInProgressEvent(actionCode, event); + } + return true; + } + + /** + * Called when the current event occurred when NO gesture is in progress + * yet. The handling in this implementation may set the gesture in progress + * (via mGestureInProgress) or out of progress + * + * @param actionCode Action Code from MotionEvent + * @param event MotionEvent + */ + protected abstract void handleStartProgressEvent(int actionCode, + MotionEvent event); + + /** + * Called when the current event occurred when a gesture IS in progress. The + * handling in this implementation may set the gesture out of progress (via + * mGestureInProgress). + * + * + * @param actionCode Action Code from MotionEvent + * @param event MotionEvent + */ + protected abstract void handleInProgressEvent(int actionCode, + MotionEvent event); + + protected void updateStateByEvent(MotionEvent curr) { + final MotionEvent prev = mPrevEvent; + + // Reset mCurrEvent + if (mCurrEvent != null) { + mCurrEvent.recycle(); + mCurrEvent = null; + } + mCurrEvent = MotionEvent.obtain(curr); + + // Delta time + mTimeDelta = curr.getEventTime() - prev.getEventTime(); + + // Pressure + mCurrPressure = curr.getPressure(curr.getActionIndex()); + mPrevPressure = prev.getPressure(prev.getActionIndex()); + } + + protected void resetState() { + if (mPrevEvent != null) { + mPrevEvent.recycle(); + mPrevEvent = null; + } + if (mCurrEvent != null) { + mCurrEvent.recycle(); + mCurrEvent = null; + } + mGestureInProgress = false; + } + + /** + * Returns {@code true} if a gesture is currently in progress. + * + * @return {@code true} if a gesture is currently in progress, {@code false} + * otherwise. + */ + public boolean isInProgress() { + return mGestureInProgress; + } + + /** + * Return the time difference in milliseconds between the previous accepted + * GestureDetector event and the current GestureDetector event. + * + * @return Time difference since the last move event in milliseconds. + */ + public long getTimeDelta() { + return mTimeDelta; + } + + /** + * Return the event time of the current GestureDetector event being + * processed. + * + * @return Current GestureDetector event time in milliseconds. + */ + public long getEventTime() { + return mCurrEvent.getEventTime(); + } + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java new file mode 100644 index 000000000..2430f3f92 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java @@ -0,0 +1,185 @@ +package com.almeros.android.multitouch.gesturedetectors; + +import android.content.Context; +import android.graphics.PointF; +import android.view.MotionEvent; + +/** + * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie + * (code.almeros.com) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +public class MoveGestureDetector extends BaseGestureDetector { + + /** + * Listener which must be implemented which is used by MoveGestureDetector + * to perform callbacks to any implementing class which is registered to a + * MoveGestureDetector via the constructor. + * + * @see MoveGestureDetector.SimpleOnMoveGestureListener + */ + public interface OnMoveGestureListener { + public boolean onMove(MoveGestureDetector detector); + + public boolean onMoveBegin(MoveGestureDetector detector); + + public void onMoveEnd(MoveGestureDetector detector); + } + + /** + * Helper class which may be extended and where the methods may be + * implemented. This way it is not necessary to implement all methods of + * OnMoveGestureListener. + */ + public static class SimpleOnMoveGestureListener implements + OnMoveGestureListener { + public boolean onMove(MoveGestureDetector detector) { + return false; + } + + public boolean onMoveBegin(MoveGestureDetector detector) { + return true; + } + + public void onMoveEnd(MoveGestureDetector detector) { + // Do nothing, overridden implementation may be used + } + } + + private static final PointF FOCUS_DELTA_ZERO = new PointF(); + + private final OnMoveGestureListener mListener; + + private PointF mFocusExternal = new PointF(); + private PointF mFocusDeltaExternal = new PointF(); + + public MoveGestureDetector(Context context, OnMoveGestureListener listener) { + super(context); + mListener = listener; + } + + @Override + protected void handleStartProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_DOWN: + resetState(); // In case we missed an UP/CANCEL event + + mPrevEvent = MotionEvent.obtain(event); + mTimeDelta = 0; + + updateStateByEvent(event); + break; + + case MotionEvent.ACTION_MOVE: + mGestureInProgress = mListener.onMoveBegin(this); + break; + } + } + + @Override + protected void handleInProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mListener.onMoveEnd(this); + resetState(); + break; + + case MotionEvent.ACTION_MOVE: + updateStateByEvent(event); + + // Only accept the event if our relative pressure is within + // a certain limit. This can help filter shaky data as a + // finger is lifted. + if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) { + final boolean updatePrevious = mListener.onMove(this); + if (updatePrevious) { + mPrevEvent.recycle(); + mPrevEvent = MotionEvent.obtain(event); + } + } + break; + } + } + + protected void updateStateByEvent(MotionEvent curr) { + super.updateStateByEvent(curr); + + final MotionEvent prev = mPrevEvent; + + // Focus intenal + PointF mCurrFocusInternal = determineFocalPoint(curr); + PointF mPrevFocusInternal = determineFocalPoint(prev); + + // Focus external + // - Prevent skipping of focus delta when a finger is added or removed + boolean mSkipNextMoveEvent = prev.getPointerCount() != curr + .getPointerCount(); + mFocusDeltaExternal = mSkipNextMoveEvent ? FOCUS_DELTA_ZERO + : new PointF(mCurrFocusInternal.x - mPrevFocusInternal.x, + mCurrFocusInternal.y - mPrevFocusInternal.y); + + // - Don't directly use mFocusInternal (or skipping will occur). Add + // unskipped delta values to mFocusExternal instead. + mFocusExternal.x += mFocusDeltaExternal.x; + mFocusExternal.y += mFocusDeltaExternal.y; + } + + /** + * Determine (multi)finger focal point (a.k.a. center point between all + * fingers) + * + * @param e + * @return PointF focal point + */ + private PointF determineFocalPoint(MotionEvent e) { + // Number of fingers on screen + final int pCount = e.getPointerCount(); + float x = 0.0f; + float y = 0.0f; + + for (int i = 0; i < pCount; i++) { + x += e.getX(i); + y += e.getY(i); + } + + return new PointF(x / pCount, y / pCount); + } + + public float getFocusX() { + return mFocusExternal.x; + } + + public float getFocusY() { + return mFocusExternal.y; + } + + public PointF getFocusDelta() { + return mFocusDeltaExternal; + } + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java new file mode 100644 index 000000000..124fe8509 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java @@ -0,0 +1,180 @@ +package com.almeros.android.multitouch.gesturedetectors; + +import android.content.Context; +import android.view.MotionEvent; + +/** + * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie + * (code.almeros.com) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +public class RotateGestureDetector extends TwoFingerGestureDetector { + + /** + * Listener which must be implemented which is used by RotateGestureDetector + * to perform callbacks to any implementing class which is registered to a + * RotateGestureDetector via the constructor. + * + * @see RotateGestureDetector.SimpleOnRotateGestureListener + */ + public interface OnRotateGestureListener { + public boolean onRotate(RotateGestureDetector detector); + + public boolean onRotateBegin(RotateGestureDetector detector); + + public void onRotateEnd(RotateGestureDetector detector); + } + + /** + * Helper class which may be extended and where the methods may be + * implemented. This way it is not necessary to implement all methods of + * OnRotateGestureListener. + */ + public static class SimpleOnRotateGestureListener implements + OnRotateGestureListener { + public boolean onRotate(RotateGestureDetector detector) { + return false; + } + + public boolean onRotateBegin(RotateGestureDetector detector) { + return true; + } + + public void onRotateEnd(RotateGestureDetector detector) { + // Do nothing, overridden implementation may be used + } + } + + private final OnRotateGestureListener mListener; + private boolean mSloppyGesture; + + public RotateGestureDetector(Context context, + OnRotateGestureListener listener) { + super(context); + mListener = listener; + } + + @Override + protected void handleStartProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_POINTER_DOWN: + // At least the second finger is on screen now + + resetState(); // In case we missed an UP/CANCEL event + mPrevEvent = MotionEvent.obtain(event); + mTimeDelta = 0; + + updateStateByEvent(event); + + // See if we have a sloppy gesture + mSloppyGesture = isSloppyGesture(event); + if (!mSloppyGesture) { + // No, start gesture now + mGestureInProgress = mListener.onRotateBegin(this); + } + break; + + case MotionEvent.ACTION_MOVE: + if (!mSloppyGesture) { + break; + } + + // See if we still have a sloppy gesture + mSloppyGesture = isSloppyGesture(event); + if (!mSloppyGesture) { + // No, start normal gesture now + mGestureInProgress = mListener.onRotateBegin(this); + } + + break; + + case MotionEvent.ACTION_POINTER_UP: + if (!mSloppyGesture) { + break; + } + + break; + } + } + + @Override + protected void handleInProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_POINTER_UP: + // Gesture ended but + updateStateByEvent(event); + + if (!mSloppyGesture) { + mListener.onRotateEnd(this); + } + + resetState(); + break; + + case MotionEvent.ACTION_CANCEL: + if (!mSloppyGesture) { + mListener.onRotateEnd(this); + } + + resetState(); + break; + + case MotionEvent.ACTION_MOVE: + updateStateByEvent(event); + + // Only accept the event if our relative pressure is within + // a certain limit. This can help filter shaky data as a + // finger is lifted. + if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) { + final boolean updatePrevious = mListener.onRotate(this); + if (updatePrevious) { + mPrevEvent.recycle(); + mPrevEvent = MotionEvent.obtain(event); + } + } + break; + } + } + + @Override + protected void resetState() { + super.resetState(); + mSloppyGesture = false; + } + + /** + * Return the rotation difference from the previous rotate event to the + * current event. + * + * @return The current rotation //difference in degrees. + */ + public float getRotationDegreesDelta() { + double diffRadians = Math.atan2(mPrevFingerDiffY, mPrevFingerDiffX) + - Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX); + return (float) (diffRadians * 180.0 / Math.PI); + } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java new file mode 100644 index 000000000..254597105 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java @@ -0,0 +1,213 @@ +package com.almeros.android.multitouch.gesturedetectors; + +import android.content.Context; +import android.view.MotionEvent; + +/** + * @author Robert Nordan (robert.nordan@norkart.no) + * + * Copyright (c) 2013, Norkart AS + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +public class ShoveGestureDetector extends TwoFingerGestureDetector { + + /** + * Listener which must be implemented which is used by ShoveGestureDetector + * to perform callbacks to any implementing class which is registered to a + * ShoveGestureDetector via the constructor. + * + * @see ShoveGestureDetector.SimpleOnShoveGestureListener + */ + public interface OnShoveGestureListener { + public boolean onShove(ShoveGestureDetector detector); + + public boolean onShoveBegin(ShoveGestureDetector detector); + + public void onShoveEnd(ShoveGestureDetector detector); + } + + /** + * Helper class which may be extended and where the methods may be + * implemented. This way it is not necessary to implement all methods of + * OnShoveGestureListener. + */ + public static class SimpleOnShoveGestureListener implements + OnShoveGestureListener { + public boolean onShove(ShoveGestureDetector detector) { + return false; + } + + public boolean onShoveBegin(ShoveGestureDetector detector) { + return true; + } + + public void onShoveEnd(ShoveGestureDetector detector) { + // Do nothing, overridden implementation may be used + } + } + + private float mPrevAverageY; + private float mCurrAverageY; + + private final OnShoveGestureListener mListener; + private boolean mSloppyGesture; + + public ShoveGestureDetector(Context context, OnShoveGestureListener listener) { + super(context); + mListener = listener; + } + + @Override + protected void handleStartProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_POINTER_DOWN: + // At least the second finger is on screen now + + resetState(); // In case we missed an UP/CANCEL event + mPrevEvent = MotionEvent.obtain(event); + mTimeDelta = 0; + + updateStateByEvent(event); + + // See if we have a sloppy gesture + mSloppyGesture = isSloppyGesture(event); + if (!mSloppyGesture) { + // No, start gesture now + mGestureInProgress = mListener.onShoveBegin(this); + } + break; + + case MotionEvent.ACTION_MOVE: + if (!mSloppyGesture) { + break; + } + + // See if we still have a sloppy gesture + mSloppyGesture = isSloppyGesture(event); + if (!mSloppyGesture) { + // No, start normal gesture now + mGestureInProgress = mListener.onShoveBegin(this); + } + + break; + + case MotionEvent.ACTION_POINTER_UP: + if (!mSloppyGesture) { + break; + } + + break; + } + } + + @Override + protected void handleInProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_POINTER_UP: + // Gesture ended but + updateStateByEvent(event); + + if (!mSloppyGesture) { + mListener.onShoveEnd(this); + } + + resetState(); + break; + + case MotionEvent.ACTION_CANCEL: + if (!mSloppyGesture) { + mListener.onShoveEnd(this); + } + + resetState(); + break; + + case MotionEvent.ACTION_MOVE: + updateStateByEvent(event); + + // Only accept the event if our relative pressure is within + // a certain limit. This can help filter shaky data as a + // finger is lifted. Also check that shove is meaningful. + if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD + && Math.abs(getShovePixelsDelta()) > 0.5f) { + final boolean updatePrevious = mListener.onShove(this); + if (updatePrevious) { + mPrevEvent.recycle(); + mPrevEvent = MotionEvent.obtain(event); + } + } + break; + } + } + + @Override + protected void resetState() { + super.resetState(); + mSloppyGesture = false; + mPrevAverageY = 0.0f; + mCurrAverageY = 0.0f; + } + + @Override + protected void updateStateByEvent(MotionEvent curr) { + super.updateStateByEvent(curr); + + final MotionEvent prev = mPrevEvent; + float py0 = prev.getY(0); + float py1 = prev.getY(1); + mPrevAverageY = (py0 + py1) / 2.0f; + + float cy0 = curr.getY(0); + float cy1 = curr.getY(1); + mCurrAverageY = (cy0 + cy1) / 2.0f; + } + + @Override + protected boolean isSloppyGesture(MotionEvent event) { + boolean sloppy = super.isSloppyGesture(event); + if (sloppy) + return true; + + // If it's not traditionally sloppy, we check if the angle between + // fingers + // is acceptable. + double angle = Math.abs(Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX)); + // about 20 degrees, left or right + return !((0.0f < angle && angle < 0.35f) || 2.79f < angle + && angle < Math.PI); + } + + /** + * Return the distance in pixels from the previous shove event to the + * current event. + * + * @return The current distance in pixels. + */ + public float getShovePixelsDelta() { + return mCurrAverageY - mPrevAverageY; + } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java new file mode 100644 index 000000000..91e5ef13c --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java @@ -0,0 +1,223 @@ +package com.almeros.android.multitouch.gesturedetectors; + +import android.content.Context; +import android.graphics.PointF; +import android.util.DisplayMetrics; +import android.view.MotionEvent; +import android.view.ViewConfiguration; + +/** + * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie + * (code.almeros.com) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +public abstract class TwoFingerGestureDetector extends BaseGestureDetector { + + private final float mEdgeSlop; + + protected float mPrevFingerDiffX; + protected float mPrevFingerDiffY; + protected float mCurrFingerDiffX; + protected float mCurrFingerDiffY; + + private float mCurrLen; + private float mPrevLen; + + private PointF mFocus; + + public TwoFingerGestureDetector(Context context) { + super(context); + + ViewConfiguration config = ViewConfiguration.get(context); + mEdgeSlop = config.getScaledEdgeSlop(); + } + + @Override + protected abstract void handleStartProgressEvent(int actionCode, + MotionEvent event); + + @Override + protected abstract void handleInProgressEvent(int actionCode, + MotionEvent event); + + protected void updateStateByEvent(MotionEvent curr) { + super.updateStateByEvent(curr); + + final MotionEvent prev = mPrevEvent; + + mCurrLen = -1; + mPrevLen = -1; + + // Previous + final float px0 = prev.getX(0); + final float py0 = prev.getY(0); + final float px1 = prev.getX(1); + final float py1 = prev.getY(1); + final float pvx = px1 - px0; + final float pvy = py1 - py0; + mPrevFingerDiffX = pvx; + mPrevFingerDiffY = pvy; + + // Current + final float cx0 = curr.getX(0); + final float cy0 = curr.getY(0); + final float cx1 = curr.getX(1); + final float cy1 = curr.getY(1); + final float cvx = cx1 - cx0; + final float cvy = cy1 - cy0; + mCurrFingerDiffX = cvx; + mCurrFingerDiffY = cvy; + mFocus = determineFocalPoint(curr); + } + + /** + * Return the current distance between the two pointers forming the gesture + * in progress. + * + * @return Distance between pointers in pixels. + */ + public float getCurrentSpan() { + if (mCurrLen == -1) { + final float cvx = mCurrFingerDiffX; + final float cvy = mCurrFingerDiffY; + mCurrLen = (float) Math.sqrt(cvx * cvx + cvy * cvy); + } + return mCurrLen; + } + + /** + * Return the previous distance between the two pointers forming the gesture + * in progress. + * + * @return Previous distance between pointers in pixels. + */ + public float getPreviousSpan() { + if (mPrevLen == -1) { + final float pvx = mPrevFingerDiffX; + final float pvy = mPrevFingerDiffY; + mPrevLen = (float) Math.sqrt(pvx * pvx + pvy * pvy); + } + return mPrevLen; + } + + /** + * MotionEvent has no getRawX(int) method; simulate it pending future API + * approval. + * + * @param event Motion Event + * @param pointerIndex Pointer Index + * @return Raw x value or 0 + */ + protected static float getRawX(MotionEvent event, int pointerIndex) { + float offset = event.getX() - event.getRawX(); + if (pointerIndex < event.getPointerCount()) { + return event.getX(pointerIndex) + offset; + } + return 0.0f; + } + + /** + * MotionEvent has no getRawY(int) method; simulate it pending future API + * approval. + * + * @param event Motion Event + * @param pointerIndex Pointer Index + * @return Raw y value or 0 + */ + protected static float getRawY(MotionEvent event, int pointerIndex) { + float offset = event.getY() - event.getRawY(); + if (pointerIndex < event.getPointerCount()) { + return event.getY(pointerIndex) + offset; + } + return 0.0f; + } + + /** + * Check if we have a sloppy gesture. Sloppy gestures can happen if the edge + * of the user's hand is touching the screen, for example. + * + * @param event Motion Event + * @return {@code true} if is sloppy gesture, {@code false} if not + */ + protected boolean isSloppyGesture(MotionEvent event) { + // As orientation can change, query the metrics in touch down + DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); + float mRightSlopEdge = metrics.widthPixels - mEdgeSlop; + float mBottomSlopEdge = metrics.heightPixels - mEdgeSlop; + + final float edgeSlop = mEdgeSlop; + + final float x0 = event.getRawX(); + final float y0 = event.getRawY(); + final float x1 = getRawX(event, 1); + final float y1 = getRawY(event, 1); + + boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > mRightSlopEdge + || y0 > mBottomSlopEdge; + boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > mRightSlopEdge + || y1 > mBottomSlopEdge; + + if (p0sloppy && p1sloppy) { + return true; + } else if (p0sloppy) { + return true; + } else if (p1sloppy) { + return true; + } + return false; + } + + /** + * Determine (multi)finger focal point (a.k.a. center point between all + * fingers) + * + * @param e Motion Event + * @return PointF focal point + */ + public static PointF determineFocalPoint(MotionEvent e) { + // Number of fingers on screen + final int pCount = e.getPointerCount(); + float x = 0.0f; + float y = 0.0f; + + for (int i = 0; i < pCount; i++) { + x += e.getX(i); + y += e.getY(i); + } + + return new PointF(x / pCount, y / pCount); + } + + public float getFocusX() { + return mFocus.x; + } + + public float getFocusY() { + return mFocus.y; + } + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Annotation.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Annotation.java new file mode 100644 index 000000000..4f172c6e2 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Annotation.java @@ -0,0 +1,63 @@ +package com.mapbox.mapboxgl.annotations; + +import com.mapbox.mapboxgl.views.MapView; + + +public abstract class Annotation { + + /** + * The annotation id + * + * Internal C++ id is stored as unsigned int. + */ + protected long id = -1; // -1 unless added to a MapView + private MapView mapView; + + float alpha = 1.0f; + boolean visible = true; + + public Annotation() {} + + public float getAlpha() { + return alpha; + } + + public long getId() { + return id; + } + + public boolean isVisible() { + return visible; + } + + public void remove() { + if (mapView == null) return; + mapView.removeAnnotation(this); + } + + public void setAlpha(float alpha) { + this.alpha = alpha; + } + + public void setId(long id) { + this.id = id; + } + + public void setMapView(MapView mapView) { + this.mapView = mapView; + } + + public void setVisible(boolean visible) { + this.visible = visible; + } + + // TODO: Implement getZIndex of Google Maps Android API +// public float getZIndex() { +// +// } + + // TODO: Implement setZIndex of Google Maps Android API +// public void setZIndex(float zIndex) { +// +// } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/AnnotationOptions.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/AnnotationOptions.java new file mode 100644 index 000000000..f03ff45f7 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/AnnotationOptions.java @@ -0,0 +1,22 @@ +package com.mapbox.mapboxgl.annotations; + +public abstract class AnnotationOptions { + + protected Annotation annotation; + + public AnnotationOptions() {} + + public AnnotationOptions alpha(float alpha) { + annotation.alpha = alpha; + return this; + } + + public float getAlpha() { + return annotation.alpha; + } + + public boolean isVisible() { + return annotation.visible; + } + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Circle.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Circle.java new file mode 100644 index 000000000..f8908465b --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Circle.java @@ -0,0 +1,67 @@ +package com.mapbox.mapboxgl.annotations; + + +import android.graphics.Color; + +import com.mapbox.mapboxgl.geometry.LatLng; + +/** + * UNIMPLEMENTED: Needs implementation in Native. + * + * https://github.com/mapbox/mapbox-gl-native/issues/1882 + * https://github.com/mapbox/mapbox-gl-native/issues/1726 + */ +public class Circle extends Annotation { + + LatLng center; + int fillColor = Color.BLACK; + double radius; + int strokeColor = Color.BLACK; + float strokeWidth = 10; // Google Maps API defaults to 10 + + public LatLng getCenter() { + return center; + } + + public int getFillColor() { + return fillColor; + } + + /** + * Returns the circle's radius, in meters. + * + * @return radius in meters + */ + public double getRadius() { + return radius; + } + + public int getStrokeColor() { + return strokeColor; + } + + public float getStrokeWidth() { + return strokeWidth; + } + + public void setCenter(LatLng center) { + this.center = center; + } + + public void setFillColor(int color) { + fillColor = color; + } + + public void setRadius(double radius) { + this.radius = radius; + } + + public void setStrokeColor (int color) { + strokeColor = color; + } + + public void setStrokeWidth (float width) { + strokeWidth = width; + } + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/CircleOptions.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/CircleOptions.java new file mode 100644 index 000000000..5e97d5b5e --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/CircleOptions.java @@ -0,0 +1,64 @@ +package com.mapbox.mapboxgl.annotations; + + +import com.mapbox.mapboxgl.geometry.LatLng; + +/** + * UNIMPLEMENTED: Needs implementation in Native. + * + * https://github.com/mapbox/mapbox-gl-native/issues/1882 + * https://github.com/mapbox/mapbox-gl-native/issues/1726 + */ +public class CircleOptions extends AnnotationOptions { + + private Circle circle; + + public CircleOptions() { + circle = new Circle(); + } + public CircleOptions center(LatLng center) { + circle.center = center; + return this; + } + + public CircleOptions fillColor(int color) { + circle.fillColor = color; + return this; + } + + public LatLng getCenter() { + return circle.center; + } + + public int getFillColor() { + return circle.fillColor; + } + + public double getRadius() { + return circle.radius; + } + + public int getStrokeColor () { + return circle.strokeColor; + } + + public float getStrokeWidth() { + return circle.strokeWidth; + } + + public CircleOptions radius (double radius) { + circle.radius = radius; + return this; + } + + public CircleOptions strokeColor(int color) { + circle.strokeColor = color; + return this; + } + + public CircleOptions strokeWidth (float width) { + circle.strokeWidth = width; + return this; + } + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Marker.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Marker.java new file mode 100644 index 000000000..515852ae6 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Marker.java @@ -0,0 +1,143 @@ +package com.mapbox.mapboxgl.annotations; + +import com.mapbox.mapboxgl.geometry.LatLng; + + +public class Marker extends Annotation { + + float anchorU; + float anchorV; + boolean draggable; + boolean flat; + float infoWindowAnchorU; + float infoWindowAnchorV; + LatLng position; + float rotation; + String snippet; + String sprite = "default_marker"; + String title; + + private boolean infoWindowShown = false; + + public Marker() {} + + /** + * If two markers have the same LatLng, they are equal. + * + * @param other object + * @return boolean - do they have the same LatLng + */ + public boolean equals(Object other) { + if (!(other instanceof Marker)) return false; + double lat = position.getLatitude(); + double lng = position.getLongitude(); + LatLng otherPosition = ((Marker)other).getPosition(); + double otherLat = otherPosition.getLatitude(); + double otherLng = otherPosition.getLongitude(); + return (lat == otherLat && otherLng == lng); + } + + public float getAlpha() { + return alpha; + } + + public float getAnchorU() { + return anchorU; + } + + public float getAnchorV() { + return anchorV; + } + + public LatLng getPosition() { + return position; + } + + public float getRotation() { + return rotation; + } + + public String getSnippet() { + return snippet; + } + + public String getTitle() { + return title; + } + + public void hideInfoWindow() { + //TODO hideInfoWindow + infoWindowShown = false; + } + + public boolean isDraggable() { + return draggable; + } + + public boolean isFlat() { + return flat; + } + + public boolean isInfoWindowShown () { + return infoWindowShown; + } + + void setAnchor(float u, float v) { + this.anchorU = u; + this.anchorV = v; + } + + void setDraggable(boolean draggable) { + this.draggable = draggable; + } + + void setFlat(boolean flat) { + this.flat = flat; + } + + void setInfoWindowAnchor(float u, float v) { + infoWindowAnchorU = u; + infoWindowAnchorV = v; + } + + void setPosition(LatLng latlng) { + this.position = position; + } + + void setRotation(float rotation) { + this.rotation = rotation; + } + + void setSnippet(String snippet) { + this.snippet = snippet; + } + + /** + * You can specify the name of a sprite to get a marker other than the default marker. + * This name can be found in the sprite json file: + * + * https://github.com/mapbox/mapbox-gl-styles/blob/mb-pages/sprites/mapbox-streets.json + * + * @param sprite + */ + void setSprite(String sprite) { + this.sprite = sprite; + } + + void setTitle(String title) { + this.title = title; + } + + void showInfoWindow() { + infoWindowShown = true; + } + + + // TODO Method in Google Maps Android API +// public int hashCode() + + // TODO: Implement this method of Google Maps Android API +// void setIcon(BitmapDescriptor icon) { +// +// } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/MarkerOptions.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/MarkerOptions.java new file mode 100644 index 000000000..2e577067d --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/MarkerOptions.java @@ -0,0 +1,125 @@ +package com.mapbox.mapboxgl.annotations; + +import com.mapbox.mapboxgl.geometry.LatLng; + +public class MarkerOptions extends AnnotationOptions { + + public MarkerOptions() { + annotation = new Marker(); + } + + public MarkerOptions anchor(float u, float v) { + ((Marker)annotation).anchorU = u; + ((Marker)annotation).anchorV = v; + return this; + } + + public MarkerOptions draggable(boolean draggable) { + ((Marker)annotation).draggable = draggable; + return this; + } + + public MarkerOptions flat(boolean flat) { + ((Marker)annotation).flat = flat; + return this; + } + + public float getAnchorU() { + return ((Marker)annotation).anchorU; + } + + public float getAnchorV() { + return ((Marker)annotation).anchorV; + } + + // TODO: Implement this method of Google Maps Android API +// public BitmapDescriptor getIcon () { +// +// } + + public float getInfoWindowAnchorU() { + return ((Marker)annotation).infoWindowAnchorU; + } + + public float getInfoWindowAnchorV() { + return ((Marker)annotation).infoWindowAnchorV; + } + + public Marker getMarker() { + return (Marker)annotation; + } + + public LatLng getPosition() { + return ((Marker)annotation).position; + } + + public float getRotation() { + return ((Marker)annotation).rotation; + } + + public String getSnippet() { + return ((Marker)annotation).snippet; + } + + public String getTitle() { + return ((Marker)annotation).title; + } + + public MarkerOptions infoWindowAnchor(float u, float v) { + ((Marker)annotation).infoWindowAnchorU = u; + ((Marker)annotation).infoWindowAnchorV = v; + return this; + } + + public boolean isDraggable() { + return ((Marker)annotation).draggable; + } + + public boolean isFlat() { + return ((Marker)annotation).flat; + } + + public boolean isVisible() { + return ((Marker)annotation).visible; + } + + public MarkerOptions position(LatLng position) { + ((Marker)annotation).position = position; + return this; + } + + public MarkerOptions rotation(float rotation) { + ((Marker)annotation).rotation = rotation; + return this; + } + + public MarkerOptions snippet(String snippet) { + ((Marker)annotation).snippet = snippet; + return this; + } + + public MarkerOptions sprite(String sprite) { + ((Marker)annotation).sprite = sprite; + return this; + } + + public MarkerOptions title(String title) { + ((Marker)annotation).title = title; + return this; + } + + public MarkerOptions visible(boolean visible) { + annotation.visible = visible; + return this; + } + + + // TODO: Implement this method of Google Maps Android API +// public MarkerOptions icon(BitmapDescriptor icon) { +// +// } + + // TODO: Implement this method of Google Maps Android API +// public void writeToParcel (Parcel out, int flags) + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/MultiPoint.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/MultiPoint.java new file mode 100644 index 000000000..4ebdd5071 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/MultiPoint.java @@ -0,0 +1,53 @@ +package com.mapbox.mapboxgl.annotations; + +import com.mapbox.mapboxgl.geometry.LatLng; + +import java.util.ArrayList; +import java.util.List; + +public abstract class MultiPoint extends Annotation { + + List points; + + public MultiPoint() { + super(); + points = new ArrayList<>(); + } + + /** + * Returns a copy of the points. + * + * @return points - as a copy + */ + public List getPoints() { + return new ArrayList<>(points); + } + + /** + * Sets the points of this polyline. This method will take a copy + * of the points, so further mutations to points will have no effect + * on this polyline. + * + * @param points + */ + void setPoints(List points) { + this.points = new ArrayList<>(points); + } + + + // TODO: Implement hashCode of Google Maps Android API +// public int hashCode() { +// +// } + + // TODO: Implement isGeodesic of Google Maps Android API +// public boolean isGeodesic() { +// +// } + + // TODO: Implement setGeodesic of Google Maps Android API +// public void setGeodesic(boolean geodesic) { +// +// } + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/MultiPointOptions.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/MultiPointOptions.java new file mode 100644 index 000000000..581c42bfd --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/MultiPointOptions.java @@ -0,0 +1,15 @@ +package com.mapbox.mapboxgl.annotations; + +import com.mapbox.mapboxgl.geometry.LatLng; + +import java.util.List; + +public abstract class MultiPointOptions extends AnnotationOptions { + + public MultiPointOptions() {} + + public List getPoints() { + // the getter gives us a copy, which is the safe thing to do... + return ((MultiPoint)annotation).getPoints(); + } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Polygon.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Polygon.java new file mode 100644 index 000000000..41edb2a5d --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Polygon.java @@ -0,0 +1,99 @@ +package com.mapbox.mapboxgl.annotations; + + +import android.graphics.Color; + +import com.mapbox.mapboxgl.geometry.LatLng; + +import java.util.ArrayList; +import java.util.List; + +public class Polygon extends MultiPoint { + + int fillColor = Color.BLACK; // default fillColor is black + float strokeAlpha = 1; + int strokeColor = Color.BLACK; // default strokeColor is black + float strokeWidth = 10; // As specified by Google API Docs (in pixels) + + List> holes; + + public Polygon() { + super(); + holes = new ArrayList<>(); + } + + public int getFillColor() { + return fillColor; + } + + public List> getHoles () { + return holes; + } + + public int getStrokeColor() { + return strokeColor; + } + + /** + * UNIMPLEMENTED: Needs implementation in Native. + * https://github.com/mapbox/mapbox-gl-native/issues/1737 + * @return stroke width as float + */ + public float getStrokeWidth() { + return strokeWidth; + } + + public void setFillAlpha(float alpha) { + this.alpha = alpha; + } + + public void setFillColor(int color) { + fillColor = color; + } + + /** + * Sets the holes of this polygon. This method will take a copy of the holes, + * so further mutations to holes parameter will have no effect on this polygon. + * + * @param holes + */ + public void setHoles(List> holes) { + this.holes = new ArrayList<>(); + for (List hole : holes) { + this.holes.add(new ArrayList<>(hole)); + } + } + + /** + * Sets the alpha (opacity) of the stroke + * + * UNIMPLEMENTED: Needs implementation in Native. + */ + public void setStrokeAlpha(float alpha) { + strokeAlpha = alpha; + } + + public void setStrokeColor(int color) { + strokeColor = color; + } + + /** + * UNIMPLEMENTED: Needs implementation in Native. + * https://github.com/mapbox/mapbox-gl-native/issues/1737 + * @return stroke width as float + */ + public void setStrokeWidth(float width) { + strokeWidth = width; + } + + + // TODO: Implement equals of Google Maps Android API +// public boolean equals (Object other) { +// +// } + + // TODO: Implement hashCode of Google Maps Android API +// public int hashCode () { +// +// } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/PolygonOptions.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/PolygonOptions.java new file mode 100644 index 000000000..25ee75019 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/PolygonOptions.java @@ -0,0 +1,125 @@ +package com.mapbox.mapboxgl.annotations; + + +import com.mapbox.mapboxgl.geometry.LatLng; + +import java.util.ArrayList; +import java.util.List; + +public class PolygonOptions extends MultiPointOptions { + + public PolygonOptions() { + annotation = new Polygon(); + } + + public PolygonOptions add(LatLng point) { + ((MultiPoint)annotation).points.add(point); + return this; + } + + public PolygonOptions add(LatLng... points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + public PolygonOptions addAll(Iterable points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + /** + * UNIMPLEMENTED: Needs implementation in Native. + * https://github.com/mapbox/mapbox-gl-native/issues/1729 + * + * @param points - an iterable (list) of points for cutting a hole + * @return PolygonOptions - the options object + */ + public PolygonOptions addHole (Iterable points) { + List hole = new ArrayList<>(); + for (LatLng point : points) { + hole.add(point); + } + ((Polygon)annotation).holes.add(hole); + return this; + } + + /** + * Sets the color of the polygon. + * + * @param color - the color in ARGB format + * @return PolygonOptions - the options object + */ + public PolygonOptions fillColor(int color) { + ((Polygon)annotation).fillColor = color; + return this; + } + + public int getFillColor() { + return ((Polygon)annotation).fillColor; + } + + /** + * UNIMPLEMENTED: Needs implementation in Native. + * https://github.com/mapbox/mapbox-gl-native/issues/1729 + * + * @return a list of lists of points for cutting holes + */ + public List> getHoles() { + return ((Polygon)annotation).holes; + } + + public Polygon getPolygon() { + return ((Polygon)annotation); + } + + public int getStrokeColor() { + return ((Polygon)annotation).strokeColor; + } + + /** + * UNIMPLEMENTED: Needs implementation in Native. + * https://github.com/mapbox/mapbox-gl-native/issues/1737 + * + * @return stroke width as float + */ + public float getStrokeWidth() { + return ((Polygon)annotation).strokeWidth; + } + + /** + * Sets the color of the stroke of the polygon. + * + * @param color - the color in ARGB format + * @return PolygonOptions - the options object + */ + public PolygonOptions strokeColor(int color) { + ((Polygon)annotation).strokeColor = color; + return this; + } + + /** + * UNIMPLEMENTED: Needs implementation in Native. + * https://github.com/mapbox/mapbox-gl-native/issues/1737 + * + * @return stroke width as float + */ + public PolygonOptions strokeWidth(float width) { + ((Polygon)annotation).strokeWidth = width; + return this; + } + + public PolygonOptions visible(boolean visible) { + annotation.visible = visible; + return this; + } + + // TODO: Implement writeToParcel of Google Maps Android API +// public void writeToParcel(Parcel out, int flags) { +// +// } + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Polyline.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Polyline.java new file mode 100644 index 000000000..764723833 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Polyline.java @@ -0,0 +1,51 @@ +package com.mapbox.mapboxgl.annotations; + +import android.graphics.Color; + +import com.mapbox.mapboxgl.geometry.LatLng; + +import java.util.List; + +public class Polyline extends MultiPoint { + + int color = Color.BLACK; // default color is black + float width = 10; // As specified by Google API Docs (in pixels) + + public Polyline() { + super(); + } + + public int getColor() { + return color; + } + + public float getWidth() { + return width; + } + + + /** + * Sets the color of the polyline. + * + * @param color - the color in ARGB format + */ + public void setColor(int color) { + this.color = color; + } + + + /** + * Sets the width of the polyline. + * + * @param width in pixels + * @return + */ + public void setWidth(float width) { + this.width = width; + } + + // TODO: Implement equals of Google Maps Android API +// public boolean equals(Object other) { +// +// } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/PolylineOptions.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/PolylineOptions.java new file mode 100644 index 000000000..d825399f7 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/PolylineOptions.java @@ -0,0 +1,75 @@ +package com.mapbox.mapboxgl.annotations; + +import com.mapbox.mapboxgl.geometry.LatLng; + +import java.util.List; + +public class PolylineOptions extends MultiPointOptions { + + public PolylineOptions() { + annotation = new Polyline(); + } + + public PolylineOptions add(LatLng point) { + ((MultiPoint)annotation).points.add(point); + return this; + } + + public PolylineOptions add(LatLng... points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + public PolylineOptions addAll(Iterable points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + /** + * Sets the color of the polyline. + * + * @param color - the color in ARGB format + */ + public PolylineOptions color(int color) { + ((Polyline)annotation).color = color; + return this; + } + + public int getColor() { + return ((Polyline)annotation).color; + } + + public Polyline getPolyline() { + return ((Polyline)annotation); + } + + public float getWidth() { + return ((Polyline)annotation).width; + } + + public PolylineOptions visible(boolean visible) { + annotation.visible = visible; + return this; + } + + /** + * Sets the width of the polyline. + * + * @param width in pixels + * @return + */ + public PolylineOptions width(float width) { + ((Polyline)annotation).width = width; + return this; + } + + // TODO: Implement writeToParcel of Google Maps Android API +// public void writeToParcel(Parcel out, int flags) { +// +// } + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/GeoConstants.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/GeoConstants.java new file mode 100644 index 000000000..4c899d2d8 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/GeoConstants.java @@ -0,0 +1,10 @@ +package com.mapbox.mapboxgl.constants; + +public class GeoConstants { + // http://en.wikipedia.org/wiki/Earth_radius#Equatorial_radius + public static final int RADIUS_EARTH_METERS = 6378137; + public static final double MIN_LATITUDE = -85.05112878; + public static final double MAX_LATITUDE = 85.05112878; + public static final double MIN_LONGITUDE = -180; + public static final double MAX_LONGITUDE = 180; +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/MapboxConstants.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/MapboxConstants.java new file mode 100644 index 000000000..7c59a756d --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/MapboxConstants.java @@ -0,0 +1,10 @@ +package com.mapbox.mapboxgl.constants; + +import java.util.Locale; + +public class MapboxConstants { + + // Default Locale for data processing (ex: String.toLowerCase(MAPBOX_LOCALE, "foo")) + public static final Locale MAPBOX_LOCALE = Locale.US; + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/MathConstants.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/MathConstants.java new file mode 100644 index 000000000..71e235c91 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/MathConstants.java @@ -0,0 +1,8 @@ +package com.mapbox.mapboxgl.constants; + +public class MathConstants { + public static final double DEG2RAD = (Math.PI / 180.0); + public static final double RAD2DEG = (180.0 / Math.PI); + + public static final double PI = Math.PI; +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/BoundingBox.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/BoundingBox.java new file mode 100644 index 000000000..091ac4d06 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/BoundingBox.java @@ -0,0 +1,273 @@ +package com.mapbox.mapboxgl.geometry; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.Serializable; +import java.util.List; + +/** + * A rectangular geographical area defined in latitude and longitude units. + */ +public final class BoundingBox implements Parcelable, Serializable { + + private final double mLatNorth; + private final double mLatSouth; + private final double mLonEast; + private final double mLonWest; + + private final boolean mIsValid; + + /** + * Construct a new bounding box based on its corners, given in NESW + * order. + * + * @param north Northern Coordinate + * @param east Eastern Coordinate + * @param south Southern Coordinate + * @param west Western Coordinate + */ + public BoundingBox(final double north, final double east, final double south, final double west) { + this.mLatNorth = north; + this.mLonEast = east; + this.mLatSouth = south; + this.mLonWest = west; + this.mIsValid = ((this.mLonWest < this.mLonEast) && (this.mLatNorth > this.mLatSouth)); + } + + /** + * Construct a new bounding box based on its corners, given in NESW + * order. + * + * @param northEast Coordinate + * @param southWest Coordinate + */ + public BoundingBox(final LatLng northEast, final LatLng southWest) { + this(northEast.getLatitude(), northEast.getLongitude(), southWest.getLatitude(), southWest.getLongitude()); + } + + /** + * Create a bounding box from another bounding box + * + * @param other the other bounding box + */ + public BoundingBox(final BoundingBox other) { + this.mLatNorth = other.getLatNorth(); + this.mLonEast = other.getLonEast(); + this.mLatSouth = other.getLatSouth(); + this.mLonWest = other.getLonWest(); + this.mIsValid = other.isValid(); + } + + /** + * Create a new BoundingBox with no size centered at 0, 0, also known as null island + */ + public BoundingBox() { + this(0, 0, 0, 0); + } + + /** + * Calculates the centerpoint of this bounding box by simple interpolation and returns + * it as a point. This is a non-geodesic calculation which is not the geographic center. + * + * @return LatLng center of this BoundingBox + */ + public LatLng getCenter() { + return new LatLng((this.mLatNorth + this.mLatSouth) / 2, + (this.mLonEast + this.mLonWest) / 2); + } + + public double getLatNorth() { + return this.mLatNorth; + } + + public double getLatSouth() { + return this.mLatSouth; + } + + public double getLonEast() { + return this.mLonEast; + } + + public double getLonWest() { + return this.mLonWest; + } + + public boolean isValid() { + return this.mIsValid; + } + + /** + * Get the absolute distance, in degrees, between the north and + * south boundaries of this bounding box + * + * @return Span distance + */ + public double getLatitudeSpan() { + return Math.abs(this.mLatNorth - this.mLatSouth); + } + + /** + * Get the absolute distance, in degrees, between the west and + * east boundaries of this bounding box + * + * @return Span distance + */ + public double getLongitudeSpan() { + return Math.abs(this.mLonEast - this.mLonWest); + } + + @Override + public String toString() { + return "N:" + this.mLatNorth + "; E:" + this.mLonEast + "; S:" + this.mLatSouth + "; W:" + this.mLonWest; + } + + /** + * Constructs a bounding box that contains all of a list of LatLng + * objects. Empty lists will yield invalid bounding boxes. + * + * @param latLngs List of LatLng objects + * @return BoundingBox + */ + public static BoundingBox fromLatLngs(final List latLngs) { + double minLat = 90, + minLon = 180, + maxLat = -90, + maxLon = -180; + + for (final ILatLng gp : latLngs) { + final double latitude = gp.getLatitude(); + final double longitude = gp.getLongitude(); + + minLat = Math.min(minLat, latitude); + minLon = Math.min(minLon, longitude); + maxLat = Math.max(maxLat, latitude); + maxLon = Math.max(maxLon, longitude); + } + + return new BoundingBox(maxLat, maxLon, minLat, minLon); + } + + /** + * Determines whether this bounding box matches another one via coordinates. + * + * @param other another bounding box + * @return a boolean indicating whether the bounding boxes are equal + */ + public boolean equals(final BoundingBox other) { + + return other != null && (other == this || mLatNorth == other.getLatNorth() && mLatSouth == other.getLatSouth() && mLonEast == other.getLonEast() && mLonWest == other.getLonWest()); + + } + + /** + * Determines whether this bounding box contains a point and the point + * does not touch its boundary. + * + * @param pGeoPoint the point which may be contained + * @return true, if the point is contained within the box. + */ + public boolean contains(final ILatLng pGeoPoint) { + final double latitude = pGeoPoint.getLatitude(); + final double longitude = pGeoPoint.getLongitude(); + return ((latitude < this.mLatNorth) && (latitude > this.mLatSouth)) && ((longitude + < this.mLonEast) && (longitude > this.mLonWest)); + } + + /** + * Returns a new BoundingBox that stretches to contain both this and another BoundingBox. + * + * @param box BoundingBox to add + * @return BoundingBox + */ + public BoundingBox union(BoundingBox box) { + return union(box.getLatNorth(), box.getLonEast(), box.getLatSouth(), box.getLonWest()); + } + + /** + * Returns a new BoundingBox that stretches to include another bounding box, + * given by corner points. + * + * @param pLatNorth Northern Coordinate + * @param pLonEast Eastern Coordinate + * @param pLatSouth Southern Coordinate + * @param pLonWest Western Coordinate + * @return BoundingBox + */ + public BoundingBox union(final double pLatNorth, final double pLonEast, final double pLatSouth, + final double pLonWest) { + return new BoundingBox((this.mLatNorth < pLatNorth) ? pLatNorth : this.mLatNorth, + (this.mLonEast < pLonEast) ? pLonEast : this.mLonEast, + (this.mLatSouth > pLatSouth) ? pLatSouth : this.mLatSouth, + (this.mLonWest > pLonWest) ? pLonWest : this.mLonWest); + } + + /** + * Returns a new BoundingBox that is the intersection of this with another box + * + * @param box BoundingBox to intersect with + * @return BoundingBox + */ + public BoundingBox intersect(BoundingBox box) { + double maxLonWest = Math.max(this.mLonWest, box.getLonWest()); + double minLonEast = Math.min(this.mLonEast, box.getLonEast()); + double maxLatNorth = Math.min(this.mLatNorth, box.getLatNorth()); + double minLatSouth = Math.max(this.mLatSouth, box.getLatSouth()); + return new BoundingBox(maxLatNorth, minLonEast, minLatSouth, maxLonWest); + } + + /** + * Returns a new BoundingBox that is the intersection of this with another box + * + * @param north Northern Coordinate + * @param east Eastern Coordinate + * @param south Southern Coordinate + * @param west Western Coordinate + * @return BoundingBox + */ + public BoundingBox intersect(double north, double east, double south, double west) { + return intersect(new BoundingBox(north, east, south, west)); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public BoundingBox createFromParcel(final Parcel in) { + return readFromParcel(in); + } + + @Override + public BoundingBox[] newArray(final int size) { + return new BoundingBox[size]; + } + }; + + @Override + public int hashCode() { + return (int) ((mLatNorth + 90) + + ((mLatSouth + 90) * 1000) + + ((mLonEast + 180) * 1000000) + + ((mLonEast + 180) * 1000000000)); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel out, final int arg1) { + out.writeDouble(this.mLatNorth); + out.writeDouble(this.mLonEast); + out.writeDouble(this.mLatSouth); + out.writeDouble(this.mLonWest); + } + + private static BoundingBox readFromParcel(final Parcel in) { + final double latNorth = in.readDouble(); + final double lonEast = in.readDouble(); + final double latSouth = in.readDouble(); + final double lonWest = in.readDouble(); + return new BoundingBox(latNorth, lonEast, latSouth, lonWest); + } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateRegion.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateRegion.java new file mode 100644 index 000000000..c7f63e790 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateRegion.java @@ -0,0 +1,30 @@ +package com.mapbox.mapboxgl.geometry; + +/** + * Implementation of iOS MKCoordinateRegion + */ +public class CoordinateRegion { + private LatLng center; + private CoordinateSpan span; + + public CoordinateRegion(final LatLng center, final CoordinateSpan span) { + this.center = center; + this.span = span; + } + + public LatLng getCenter() { + return center; + } + + public void setCenter(final LatLng center) { + this.center = center; + } + + public CoordinateSpan getSpan() { + return span; + } + + public void setSpan(final CoordinateSpan span) { + this.span = span; + } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateSpan.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateSpan.java new file mode 100644 index 000000000..b673f83f7 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateSpan.java @@ -0,0 +1,31 @@ +package com.mapbox.mapboxgl.geometry; + +/** + * Implementation of iOS MKCoordinateSpan + */ +public class CoordinateSpan { + + private double latitudeSpan; + private double longitudeSpan; + + public CoordinateSpan(final double latitudeSpan, final double longitudeSpan) { + this.latitudeSpan = latitudeSpan; + this.longitudeSpan = longitudeSpan; + } + + public double getLatitudeSpan() { + return latitudeSpan; + } + + public void setLatitudeSpan(final double latitudeSpan) { + this.latitudeSpan = latitudeSpan; + } + + public double getLongitudeSpan() { + return longitudeSpan; + } + + public void setLongitudeSpan(final double longitudeSpan) { + this.longitudeSpan = longitudeSpan; + } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ILatLng.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ILatLng.java new file mode 100644 index 000000000..620676d83 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ILatLng.java @@ -0,0 +1,12 @@ +package com.mapbox.mapboxgl.geometry; + +/** + * A Latitude, Longitude point. + */ +public interface ILatLng { + double getLatitude(); + + double getLongitude(); + + double getAltitude(); +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/IProjectedMeters.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/IProjectedMeters.java new file mode 100644 index 000000000..99f4fdec3 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/IProjectedMeters.java @@ -0,0 +1,7 @@ +package com.mapbox.mapboxgl.geometry; + +public interface IProjectedMeters { + double getNorthing(); + + double getEasting(); +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLng.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLng.java new file mode 100644 index 000000000..141f0dc96 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLng.java @@ -0,0 +1,156 @@ +package com.mapbox.mapboxgl.geometry; + +import android.location.Location; +import android.os.Parcel; +import android.os.Parcelable; + +import com.mapbox.mapboxgl.constants.GeoConstants; +import com.mapbox.mapboxgl.constants.MathConstants; + +import java.io.Serializable; + +public class LatLng implements ILatLng, Parcelable, Serializable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public LatLng createFromParcel(Parcel in) { + return new LatLng(in); + } + + public LatLng[] newArray(int size) { + return new LatLng[size]; + } + }; + + private double latitude; + private double longitude; + private double altitude = 0.0; + + /** + * Construct a new latitude, longitude point given float arguments + * @param latitude Latitude in degrees + * @param longitude Longitude in degrees + */ + public LatLng(double latitude, double longitude) { + this.latitude = latitude; + this.longitude = longitude; + } + + /** + * Construct a new latitude, longitude, altitude point given float arguments + * @param latitude Latitude in degrees + * @param longitude Longitude in degress + * @param altitude Altitude in meters + */ + public LatLng(double latitude, double longitude, double altitude) { + this.latitude = latitude; + this.longitude = longitude; + this.altitude = altitude; + } + + /** + * Transform a Location into a LatLng point + * @param location Android Location + */ + public LatLng(Location location) { + this(location.getLatitude(), location.getLongitude(), location.getAltitude()); + } + + /** + * Clone an existing latitude longitude point + * @param aLatLng LatLng + */ + public LatLng(LatLng aLatLng) { + this.latitude = aLatLng.latitude; + this.longitude = aLatLng.longitude; + this.altitude = aLatLng.altitude; + } + + protected LatLng(Parcel in) { + latitude = in.readDouble(); + longitude = in.readDouble(); + altitude = in.readDouble(); + } + + @Override + public double getLatitude() { + return latitude; + } + + @Override + public double getLongitude() { + return longitude; + } + + @Override + public double getAltitude() { + return altitude; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + LatLng latLng = (LatLng) o; + + return Double.compare(latLng.altitude, altitude) == 0 && Double.compare(latLng.latitude, latitude) == 0 && Double.compare(latLng.longitude, longitude) == 0; + + } + + @Override + public int hashCode() { + int result; + long temp; + temp = Double.doubleToLongBits(latitude); + result = (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(longitude); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(altitude); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public String toString() { + return "LatLng [longitude=" + longitude + ", latitude=" + latitude + ", altitude=" + altitude + "]"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeDouble(latitude); + out.writeDouble(longitude); + out.writeDouble(altitude); + } + + /** + * Calculate distance between two points + * @param other Other LatLng to compare to + * @return distance in meters + */ + public double distanceTo(LatLng other) { + + final double a1 = MathConstants.DEG2RAD * this.latitude; + final double a2 = MathConstants.DEG2RAD * this.longitude; + final double b1 = MathConstants.DEG2RAD * other.getLatitude(); + final double b2 = MathConstants.DEG2RAD * other.getLongitude(); + + final double cosa1 = Math.cos(a1); + final double cosb1 = Math.cos(b1); + + final double t1 = cosa1 * Math.cos(a2) * cosb1 * Math.cos(b2); + final double t2 = cosa1 * Math.sin(a2) * cosb1 * Math.sin(b2); + final double t3 = Math.sin(a1) * Math.sin(b1); + final double tt = Math.acos(t1 + t2 + t3); + + return GeoConstants.RADIUS_EARTH_METERS * tt; + } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLngZoom.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLngZoom.java new file mode 100644 index 000000000..5d841477a --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLngZoom.java @@ -0,0 +1,88 @@ +package com.mapbox.mapboxgl.geometry; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.Serializable; + +public class LatLngZoom extends LatLng implements Parcelable, Serializable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public LatLngZoom createFromParcel(Parcel in) { + return new LatLngZoom(in); + } + + public LatLngZoom[] newArray(int size) { + return new LatLngZoom[size]; + } + }; + + private double zoom; + + public LatLngZoom(double latitude, double longitude, double zoom) { + super(latitude, longitude); + this.zoom = zoom; + } + + public LatLngZoom(LatLng latLng, double zoom) { + super(latLng.getLatitude(), latLng.getLongitude()); + this.zoom = zoom; + } + + private LatLngZoom(Parcel in) { + super(in); + zoom = in.readDouble(); + } + + public double getZoom() { + return zoom; + } + + public void setZoom(double zoom) { + this.zoom = zoom; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + + LatLngZoom that = (LatLngZoom) o; + + return Double.compare(that.zoom, zoom) == 0; + + } + + @Override + public int hashCode() { + int result = super.hashCode(); + long temp; + temp = Double.doubleToLongBits(zoom); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public String toString() { + return "LatLngZoom [latitude=" + super.getLatitude() + ", longitude=" + super.getLongitude() + ", altitude=" + super.getAltitude() + ", zoom=" + zoom + "]"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeDouble(zoom); + } + +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ProjectedMeters.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ProjectedMeters.java new file mode 100644 index 000000000..156d4355b --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ProjectedMeters.java @@ -0,0 +1,89 @@ +package com.mapbox.mapboxgl.geometry; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.Serializable; + +public class ProjectedMeters implements IProjectedMeters, Parcelable, Serializable { + + public static final Creator CREATOR = new Creator() { + public ProjectedMeters createFromParcel(Parcel in) { + return new ProjectedMeters(in); + } + + public ProjectedMeters[] newArray(int size) { + return new ProjectedMeters[size]; + } + }; + + private double northing; + private double easting; + + public ProjectedMeters(double northing, double easting) { + this.northing = northing; + this.easting = easting; + } + + public ProjectedMeters(ProjectedMeters aProjectedMeters) { + this.northing = aProjectedMeters.northing; + this.easting = aProjectedMeters.easting; + } + + protected ProjectedMeters(Parcel in) { + northing = in.readDouble(); + easting = in.readDouble(); + } + + @Override + public double getNorthing() { + return northing; + } + + @Override + public double getEasting() { + return easting; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ProjectedMeters projectedMeters = (ProjectedMeters) o; + + return Double.compare(projectedMeters.easting, easting) == 0 && Double.compare(projectedMeters.northing, northing) == 0; + + } + + @Override + public int hashCode() { + int result; + long temp; + temp = Double.doubleToLongBits(easting); + result = (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(northing); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public String toString() { + return "ProjectedMeters [northing=" + northing + ", easting=" + easting + "]"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeDouble(northing); + out.writeDouble(easting); + } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/http/HTTPContext.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/http/HTTPContext.java new file mode 100644 index 000000000..4558bbfe3 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/http/HTTPContext.java @@ -0,0 +1,100 @@ +package com.mapbox.mapboxgl.http; + +import com.mapbox.mapboxgl.constants.MapboxConstants; +import com.squareup.okhttp.Call; +import com.squareup.okhttp.Callback; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.ProtocolException; +import java.net.SocketException; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLException; + +class HTTPContext { + + private static final int CONNECTION_ERROR = 0; + private static final int TEMPORARY_ERROR = 1; + private static final int PERMANENT_ERROR = 2; + + private static HTTPContext mInstance = null; + + private OkHttpClient mClient; + + private HTTPContext() { + super(); + mClient = new OkHttpClient(); + } + + public static HTTPContext getInstance() { + if (mInstance == null) { + mInstance = new HTTPContext(); + } + + return mInstance; + } + + public HTTPRequest createRequest(long nativePtr, String resourceUrl, String userAgent, String etag, String modified) { + return new HTTPRequest(nativePtr, resourceUrl, userAgent, etag, modified); + } + + public class HTTPRequest implements Callback { + private long mNativePtr = 0; + + private Call mCall; + private Request mRequest; + + private native void nativeOnFailure(long nativePtr, int type, String message); + private native void nativeOnResponse(long nativePtr, int code, String message, String etag, String modified, String cacheControl, String expires, byte[] body); + + private HTTPRequest(long nativePtr, String resourceUrl, String userAgent, String etag, String modified) { + mNativePtr = nativePtr; + Request.Builder builder = new Request.Builder().url(resourceUrl).tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE)).addHeader("User-Agent", userAgent); + if (etag.length() > 0) { + builder = builder.addHeader("If-None-Match", etag); + } else if (modified.length() > 0) { + builder = builder.addHeader("If-Modified-Since", modified); + } + mRequest = builder.build(); + } + + public void start() { + mCall = HTTPContext.getInstance().mClient.newCall(mRequest); + mCall.enqueue(this); + } + + public void cancel() { + mCall.cancel(); + } + + @Override + public void onFailure(Request request, IOException e) { + int type = PERMANENT_ERROR; + if ((e instanceof UnknownHostException) || (e instanceof SocketException) || (e instanceof ProtocolException) || (e instanceof SSLException)) { + type = CONNECTION_ERROR; + } else if ((e instanceof InterruptedIOException)) { + type = TEMPORARY_ERROR; + } + nativeOnFailure(mNativePtr, type, e.getMessage()); + } + + @Override + public void onResponse(Response response) throws IOException { + byte[] body; + try { + body = response.body().bytes(); + } catch (IOException e) { + onFailure(mRequest, e); + return; + } finally { + response.body().close(); + } + + nativeOnResponse(mNativePtr, response.code(), response.message(), response.header("ETag"), response.header("Last-Modified"), response.header("Cache-Control"), response.header("Expires"), body); + } + } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java new file mode 100644 index 000000000..de99fcd63 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java @@ -0,0 +1,1770 @@ +package com.mapbox.mapboxgl.views; + +import android.annotation.TargetApi; +import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.graphics.PointF; +import android.hardware.GeomagneticField; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.location.Location; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.GestureDetectorCompat; +import android.support.v4.view.ScaleGestureDetectorCompat; +import android.text.TextUtils; +import android.util.Log; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.ScaleGestureDetector; +import android.util.AttributeSet; +import android.view.InputDevice; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ZoomButtonsController; +import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector; +import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector; +import com.mapbox.mapboxgl.annotations.Annotation; +import com.mapbox.mapboxgl.annotations.Marker; +import com.mapbox.mapboxgl.annotations.MarkerOptions; +import com.mapbox.mapboxgl.annotations.Polygon; +import com.mapbox.mapboxgl.annotations.PolygonOptions; +import com.mapbox.mapboxgl.annotations.Polyline; +import com.mapbox.mapboxgl.annotations.PolylineOptions; +import com.mapbox.mapboxgl.geometry.LatLng; +import com.mapbox.mapboxgl.geometry.LatLngZoom; +import com.mapzen.android.lost.api.LocationListener; +import com.mapzen.android.lost.api.LocationRequest; +import com.mapzen.android.lost.api.LocationServices; +import com.mapzen.android.lost.api.LostApiClient; +import com.squareup.okhttp.HttpUrl; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +// Custom view that shows a Map +// Based on SurfaceView as we use OpenGL ES to render +public class MapView extends FrameLayout implements LocationListener { + + // + // Static members + // + private static final String TAG = "MapView"; + + // Used for animation + private static final long ANIMATION_DURATION = 300; + + // Used for saving instance state + private static final String STATE_CENTER_COORDINATE = "centerCoordinate"; + private static final String STATE_CENTER_DIRECTION = "centerDirection"; + private static final String STATE_ZOOM_LEVEL = "zoomLevel"; + private static final String STATE_DIRECTION = "direction"; + private static final String STATE_ZOOM_ENABLED = "zoomEnabled"; + private static final String STATE_SCROLL_ENABLED = "scrollEnabled"; + private static final String STATE_ROTATE_ENABLED = "rotateEnabled"; + private static final String STATE_DEBUG_ACTIVE = "debugActive"; + private static final String STATE_STYLE_URL = "styleUrl"; + private static final String STATE_ACCESS_TOKEN = "accessToken"; + private static final String STATE_STYLE_CLASSES = "styleClasses"; + private static final String STATE_DEFAULT_TRANSITION_DURATION = "defaultTransitionDuration"; + private static final String STATE_COMPASS_ENABLED = "compassEnabled"; + private static final String STATE_MY_LOCATION_ENABLED = "myLocationEnabled"; + private static final String STATE_USER_LOCATION_TRACKING_MODE = "userLocationTrackingMode"; + + /** + * Every annotation that has been added to the map. + */ + private List mAnnotations = new ArrayList<>(); + + // + // Instance members + // + + // Used to call JNI NativeMapView + private NativeMapView mNativeMapView; + + // Used to handle DPI scaling + private float mScreenDensity = 1.0f; + + // Touch gesture detectors + private GestureDetectorCompat mGestureDetector; + private ScaleGestureDetector mScaleGestureDetector; + private RotateGestureDetector mRotateGestureDetector; + private boolean mTwoTap = false; + + // Shows zoom buttons + private ZoomButtonsController mZoomButtonsController; + + // Used to track trackball long presses + private TrackballLongPressTimeOut mCurrentTrackballLongPressTimeOut; + + private ConnectivityReceiver mConnectivityReceiver; + + // Holds the context + private Context mContext; + + // Used for GPS / Location + private boolean mIsMyLocationEnabled = false; + private LostApiClient mLocationClient; + private LocationRequest mLocationRequest; + private ImageView mGpsMarker; + private Location mGpsLocation; + + public enum UserLocationTrackingMode { + NONE, FOLLOW, FOLLOW_BEARING + } + private UserLocationTrackingMode mUserLocationTrackingMode = UserLocationTrackingMode.FOLLOW; + + // Used for compass + private boolean mIsCompassEnabled = true; + private ImageView mCompassView; + private SensorManager mSensorManager; + private Sensor mSensorAccelerometer; + private Sensor mSensorMagneticField; + private CompassListener mCompassListener; + private float[] mValuesAccelerometer = new float[3]; + private float[] mValuesMagneticField = new float[3]; + private float[] mMatrixR = new float[9]; + private float[] mMatrixI = new float[9]; + private float[] mMatrixValues = new float[3]; + private float mCompassBearing; + private boolean mCompassValid = false; + + // Used for map toggle mode + private long t0 = new Date().getTime(); + + // Used to manage Event Listeners + private ArrayList mOnMapChangedListener; + + // + // Properties + // + + private boolean mZoomEnabled = true; + private boolean mScrollEnabled = true; + private boolean mRotateEnabled = true; + private String mStyleUrl; + + // + // Constructors + // + + // Called when no properties are being set from XML + public MapView(Context context) { + super(context); + initialize(context, null); + } + + public MapView(Context context, @NonNull String accessToken) { + super(context); + setAccessToken(accessToken); + initialize(context, null); + } + + public MapView(Context context, @NonNull String accessToken, String styleUrl) { + super(context); + setAccessToken(accessToken); + setStyleUrl(styleUrl); + initialize(context, null); + } + + // Called when properties are being set from XML + public MapView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context, attrs); + } + + // Called when properties are being set from XML + public MapView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initialize(context, attrs); + } + + // + // Initialization + // + + // Common initialization code goes here + @TargetApi(16) + private void initialize(Context context, AttributeSet attrs) { + + // Save the context + mContext = context; + + SurfaceView surfaceView = new SurfaceView(mContext); + addView(surfaceView); + + // Check if we are in Eclipse UI editor + if (isInEditMode()) { + return; + } + + // Get the screen's density + mScreenDensity = context.getResources().getDisplayMetrics().density; + + // Get the cache path + String cachePath = context.getCacheDir().getAbsolutePath(); + String dataPath = context.getFilesDir().getAbsolutePath(); + String apkPath = context.getPackageCodePath(); + + // Create the NativeMapView + int availableProcessors = Runtime.getRuntime().availableProcessors(); + ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); + ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + activityManager.getMemoryInfo(memoryInfo); + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + long totalMemory = memoryInfo.totalMem; + mNativeMapView = new NativeMapView(this, cachePath, dataPath, apkPath, mScreenDensity, availableProcessors, totalMemory); + } else { + throw new RuntimeException("Need to implement totalMemory on pre-Jelly Bean devices."); + } + + // Ensure this view is interactable + setClickable(true); + setLongClickable(true); + setFocusable(true); + setFocusableInTouchMode(true); + requestFocus(); + + // Register the SurfaceHolder callbacks + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { + surfaceView.getHolder().addCallback(new Callbacks2()); + } else { + surfaceView.getHolder().addCallback(new Callbacks()); + } + + // Touch gesture detectors + mGestureDetector = new GestureDetectorCompat(context, new GestureListener()); + mGestureDetector.setIsLongpressEnabled(true); + mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureListener()); + ScaleGestureDetectorCompat.setQuickScaleEnabled(mScaleGestureDetector, true); + mRotateGestureDetector = new RotateGestureDetector(context, new RotateGestureListener()); + + // Shows the zoom controls + // But not when in Eclipse UI editor + if (!isInEditMode()) { + if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)) { + mZoomButtonsController = new ZoomButtonsController(this); + mZoomButtonsController.setZoomSpeed(ANIMATION_DURATION); + mZoomButtonsController.setOnZoomListener(new OnZoomListener()); + } + + // Check current connection status + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo(); + boolean isConnected = (activeNetwork != null) && activeNetwork.isConnectedOrConnecting(); + onConnectivityChanged(isConnected); + } + + // Setup Location Services + mLocationClient = new LostApiClient.Builder(getContext()).build(); + mLocationRequest = LocationRequest.create() + .setInterval(1000) + .setSmallestDisplacement(1) + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + + // Setup Compass + mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); + mSensorAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + mSensorMagneticField = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + mCompassListener = new CompassListener(); + + mCompassView = new ImageView(mContext); + mCompassView.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.compass)); + mCompassView.setContentDescription(getResources().getString(R.string.compassContentDescription)); + LayoutParams lp = new FrameLayout.LayoutParams((int)(48 * mScreenDensity), (int)(48 * mScreenDensity)); + lp.gravity = Gravity.TOP | Gravity.END; + int tenDp = (int)(10 * mScreenDensity); + lp.setMargins(tenDp, tenDp, tenDp, tenDp); + mCompassView.setLayoutParams(lp); + addView(mCompassView); + mCompassView.setOnClickListener(new CompassOnClickListener()); + + // Setup Support For Listener Tracking + // MapView's internal listener is setup in onCreate() + mOnMapChangedListener = new ArrayList<>(); + + // Load the attributes + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MapView, 0, 0); + try { + double centerLatitude = typedArray.getFloat(R.styleable.MapView_centerLatitude, 0.0f); + double centerLongitude = typedArray.getFloat(R.styleable.MapView_centerLongitude, 0.0f); + LatLng centerCoordinate = new LatLng(centerLatitude, centerLongitude); + setCenterCoordinate(centerCoordinate); + setZoomLevel(typedArray.getFloat(R.styleable.MapView_zoomLevel, 0.0f)); // need to set zoom level first because of limitation on rotating when zoomed out + setDirection(typedArray.getFloat(R.styleable.MapView_direction, 0.0f)); + setZoomEnabled(typedArray.getBoolean(R.styleable.MapView_zoomEnabled, true)); + setScrollEnabled(typedArray.getBoolean(R.styleable.MapView_scrollEnabled, true)); + setRotateEnabled(typedArray.getBoolean(R.styleable.MapView_rotateEnabled, true)); + setDebugActive(typedArray.getBoolean(R.styleable.MapView_debugActive, false)); + if (typedArray.getString(R.styleable.MapView_styleUrl) != null) { + setStyleUrl(typedArray.getString(R.styleable.MapView_styleUrl)); + } + if (typedArray.getString(R.styleable.MapView_accessToken) != null) { + setAccessToken(typedArray.getString(R.styleable.MapView_accessToken)); + } + if (typedArray.getString(R.styleable.MapView_styleClasses) != null) { + List styleClasses = Arrays.asList(typedArray.getString(R.styleable.MapView_styleClasses).split("\\s*,\\s*")); + for (String styleClass : styleClasses) { + if (styleClass.length() == 0) { + styleClasses.remove(styleClass); + } + } + setStyleClasses(styleClasses); + } + setCompassEnabled(typedArray.getBoolean(R.styleable.MapView_compassEnabled, true)); + setMyLocationEnabled(typedArray.getBoolean(R.styleable.MapView_myLocationEnabled, false)); + } finally { + typedArray.recycle(); + } + } + + // + // Annotations + // + + public void setSprite(String symbol, float scale, Bitmap bitmap) { + if(bitmap.getConfig() != Bitmap.Config.ARGB_8888) { + bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false); + } + ByteBuffer buffer = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight()); + bitmap.copyPixelsToBuffer(buffer); + + mNativeMapView.setSprite(symbol, bitmap.getWidth(), bitmap.getHeight(), scale, buffer.array()); + } + + public Marker addMarker(MarkerOptions markerOptions) { + Marker marker = markerOptions.getMarker(); + long id = mNativeMapView.addMarker(marker); + marker.setId(id); // the annotation needs to know its id + marker.setMapView(this); // the annotation needs to know which map view it is in + mAnnotations.add(marker); + return marker; + } + + public Polyline addPolyline(PolylineOptions polylineOptions) { + Polyline polyline = polylineOptions.getPolyline(); + long id = mNativeMapView.addPolyline(polyline); + polyline.setId(id); + polyline.setMapView(this); + mAnnotations.add(polyline); + return polyline; + } + + public Polygon addPolygon(PolygonOptions polygonOptions) { + Polygon polygon = polygonOptions.getPolygon(); + long id = mNativeMapView.addPolygon(polygon); + polygon.setId(id); + polygon.setMapView(this); + mAnnotations.add(polygon); + return polygon; + } + + public List addPolygons(List polygonOptions) { + List polygons = new ArrayList<>(); + for(PolygonOptions popts : polygonOptions) { + polygons.add(popts.getPolygon()); + } + + long[] ids = mNativeMapView.addPolygons(polygons); + + for(int i=0; i < polygons.size(); i++) { + polygons.get(i).setId(ids[i]); + polygons.get(i).setMapView(this); + mAnnotations.add(polygons.get(i)); + } + + return Collections.unmodifiableList(polygons); + } + + private void removeAnnotationsWithId(long annotationId){ + for (Iterator iterator = mAnnotations.iterator(); iterator.hasNext();) { + Annotation annotation = iterator.next(); + if (annotation.getId() == annotationId) { + iterator.remove(); + } + } + } + + public void removeAnnotation(Annotation annotation) { + long id = annotation.getId(); + mNativeMapView.removeAnnotation(id); + mAnnotations.remove(annotation); + } + + public void removeAnnotation(long annotationId) { + mNativeMapView.removeAnnotation(annotationId); + removeAnnotationsWithId(annotationId); + } + + public void removeAnnotations() { + long[] ids = new long[mAnnotations.size()]; + for(int i = 0; i < mAnnotations.size(); i++) { + long id = mAnnotations.get(i).getId(); + ids[i] = id; + } + mNativeMapView.removeAnnotations(ids); + mAnnotations.clear(); + } + + public List getAnnotations() { + return Collections.unmodifiableList(mAnnotations); + } + + // + // Property methods + // + + public LatLng getCenterCoordinate() { + return mNativeMapView.getLatLng(); + } + + public void setCenterCoordinate(LatLng centerCoordinate) { + setCenterCoordinate(centerCoordinate, false); + } + + public void setCenterCoordinate(LatLng centerCoordinate, boolean animated) { + long duration = animated ? ANIMATION_DURATION : 0; + mNativeMapView.setLatLng(centerCoordinate, duration); + } + + public void setCenterCoordinate(LatLngZoom centerCoordinate) { + setCenterCoordinate(centerCoordinate, false); + } + + public void setCenterCoordinate(LatLngZoom centerCoordinate, + boolean animated) { + long duration = animated ? ANIMATION_DURATION : 0; + mNativeMapView.setLatLngZoom(centerCoordinate, duration); + } + + public double getDirection() { + double direction = -mNativeMapView.getBearing(); + + while (direction > 360) { + direction -= 360; + } + while (direction < 0) { + direction += 360; + } + + return direction; + } + + public void setDirection(double direction) { + setDirection(direction, false); + } + + public void setDirection(double direction, boolean animated) { + long duration = animated ? ANIMATION_DURATION : 0; + mNativeMapView.setBearing(-direction, duration); + } + + public void resetPosition() { + mNativeMapView.resetPosition(); + } + + public void resetNorth() { + mNativeMapView.resetNorth(); + } + + public double getZoomLevel() { + return mNativeMapView.getZoom(); + } + + public void setZoomLevel(double zoomLevel) { + setZoomLevel(zoomLevel, false); + } + + public void setZoomLevel(double zoomLevel, boolean animated) { + long duration = animated ? ANIMATION_DURATION : 0; + mNativeMapView.setZoom(zoomLevel, duration); + } + + public boolean isZoomEnabled() { + return mZoomEnabled; + } + + public void setZoomEnabled(boolean zoomEnabled) { + this.mZoomEnabled = zoomEnabled; + + if ((mZoomButtonsController != null) && (getVisibility() == View.VISIBLE) && mZoomEnabled) { + mZoomButtonsController.setVisible(true); + } + } + + public boolean isScrollEnabled() { + return mScrollEnabled; + } + + public void setScrollEnabled(boolean scrollEnabled) { + this.mScrollEnabled = scrollEnabled; + } + + public boolean isRotateEnabled() { + return mRotateEnabled; + } + + public void setRotateEnabled(boolean rotateEnabled) { + this.mRotateEnabled = rotateEnabled; + } + + public boolean isDebugActive() { + return mNativeMapView.getDebug() || mNativeMapView.getCollisionDebug(); + } + + public void setDebugActive(boolean debugActive) { + mNativeMapView.setDebug(debugActive); + mNativeMapView.setCollisionDebug(debugActive); + } + + public void toggleDebug() { + mNativeMapView.toggleDebug(); + mNativeMapView.toggleCollisionDebug(); + } + + public UserLocationTrackingMode getUserLocationTrackingMode() { + return mUserLocationTrackingMode; + } + + public void setUserLocationTrackingMode(UserLocationTrackingMode userLocationTrackingMode) { + this.mUserLocationTrackingMode = userLocationTrackingMode; + } + + public boolean isFullyLoaded() { + return mNativeMapView.isFullyLoaded(); + } + + private void validateStyleUrl(String url) { + url = url.replaceFirst("asset://", "http://"); + HttpUrl parsedUrl = HttpUrl.parse(url); + if (parsedUrl == null) { + throw new RuntimeException("Style URL is not a valid http, https or asset URL."); + } + } + + public void setStyleUrl(String url) { + validateStyleUrl(url); + mStyleUrl = url; + mNativeMapView.setStyleUrl(url); + } + + public String getStyleUrl() { + return mStyleUrl; + } + + private void validateAccessToken(@NonNull String accessToken) { + + if (TextUtils.isEmpty(accessToken) || (!accessToken.startsWith("pk.") && !accessToken.startsWith("sk."))) { + throw new RuntimeException("Using MapView requires setting a valid access token. See the README.md"); + } + } + + public void setAccessToken(@NonNull String accessToken) { + validateAccessToken(accessToken); + mNativeMapView.setAccessToken(accessToken); + } + + public String getAccessToken() { + return mNativeMapView.getAccessToken(); + } + + public List getStyleClasses() { + return Collections.unmodifiableList(mNativeMapView.getClasses()); + } + + public void setStyleClasses(List styleClasses) { + setStyleClasses(styleClasses, 0); + } + + public void setStyleClasses(List styleClasses, long transitionDuration) { + mNativeMapView.setDefaultTransitionDuration(transitionDuration); + mNativeMapView.setClasses(styleClasses); + } + + public void addStyleClass(String styleClass) { + mNativeMapView.addClass(styleClass); + } + + public void removeStyleClass(String styleClass) { + mNativeMapView.removeClass(styleClass); + } + + public boolean hasStyleClass(String styleClass) { + return mNativeMapView.hasClass(styleClass); + } + + public void removeAllStyleClasses() { + removeAllStyleClasses(0); + } + + public void removeAllStyleClasses(long transitionDuration) { + mNativeMapView.setDefaultTransitionDuration(transitionDuration); + ArrayList styleClasses = new ArrayList<>(0); + setStyleClasses(styleClasses); + } + + public LatLng fromScreenLocation(PointF point) { + return mNativeMapView.latLngForPixel(new PointF(point.x / mScreenDensity, point.y / mScreenDensity)); + } + + public PointF toScreenLocation(LatLng location) { + PointF point = mNativeMapView.pixelForLatLng(location); + return new PointF(point.x * mScreenDensity, point.y * mScreenDensity); + } + + // + // Lifecycle events + // + + // Called when we need to restore instance state + // Must be called from Activity onCreate + public void onCreate(Bundle savedInstanceState) { + if (savedInstanceState != null) { + setCenterCoordinate((LatLng) savedInstanceState.getParcelable(STATE_CENTER_COORDINATE)); + setZoomLevel(savedInstanceState.getDouble(STATE_ZOOM_LEVEL)); // need to set zoom level first because of limitation on rotating when zoomed out + setDirection(savedInstanceState.getDouble(STATE_CENTER_DIRECTION)); + setDirection(savedInstanceState.getDouble(STATE_DIRECTION)); + setZoomEnabled(savedInstanceState.getBoolean(STATE_ZOOM_ENABLED)); + setScrollEnabled(savedInstanceState.getBoolean(STATE_SCROLL_ENABLED)); + setRotateEnabled(savedInstanceState.getBoolean(STATE_ROTATE_ENABLED)); + setDebugActive(savedInstanceState.getBoolean(STATE_DEBUG_ACTIVE)); + setStyleUrl(savedInstanceState.getString(STATE_STYLE_URL)); + setAccessToken(savedInstanceState.getString(STATE_ACCESS_TOKEN)); + List appliedStyleClasses = savedInstanceState.getStringArrayList(STATE_STYLE_CLASSES); + if (!appliedStyleClasses.isEmpty()) { + setStyleClasses(appliedStyleClasses); + } + mNativeMapView.setDefaultTransitionDuration(savedInstanceState.getLong(STATE_DEFAULT_TRANSITION_DURATION)); + setCompassEnabled(savedInstanceState.getBoolean(STATE_COMPASS_ENABLED)); + setMyLocationEnabled(savedInstanceState.getBoolean(STATE_MY_LOCATION_ENABLED)); + setUserLocationTrackingMode((UserLocationTrackingMode) savedInstanceState.getSerializable(STATE_USER_LOCATION_TRACKING_MODE)); + } + + // Force a check for an access token + validateAccessToken(getAccessToken()); + + mNativeMapView.initializeDisplay(); + mNativeMapView.initializeContext(); + + addOnMapChangedListener(new OnMapChangedListener() { + @Override + public void onMapChanged() { + updateMap(); + } + }); + } + + // Called when we need to save instance state + // Must be called from Activity onSaveInstanceState + public void onSaveInstanceState(Bundle outState) { + outState.putParcelable(STATE_CENTER_COORDINATE, getCenterCoordinate()); + outState.putDouble(STATE_ZOOM_LEVEL, getZoomLevel()); // need to set zoom level first because of limitation on rotating when zoomed out + outState.putDouble(STATE_CENTER_DIRECTION, getDirection()); + outState.putBoolean(STATE_ZOOM_ENABLED, mZoomEnabled); + outState.putBoolean(STATE_SCROLL_ENABLED, mScrollEnabled); + outState.putBoolean(STATE_ROTATE_ENABLED, mRotateEnabled); + outState.putBoolean(STATE_DEBUG_ACTIVE, isDebugActive()); + outState.putString(STATE_STYLE_URL, mStyleUrl); + outState.putString(STATE_ACCESS_TOKEN, getAccessToken()); + outState.putStringArrayList(STATE_STYLE_CLASSES, new ArrayList<>(getStyleClasses())); + outState.putLong(STATE_DEFAULT_TRANSITION_DURATION, mNativeMapView.getDefaultTransitionDuration()); + outState.putBoolean(STATE_COMPASS_ENABLED, isCompassEnabled()); + outState.putBoolean(STATE_MY_LOCATION_ENABLED, isMyLocationEnabled()); + outState.putSerializable(STATE_USER_LOCATION_TRACKING_MODE, getUserLocationTrackingMode()); + } + + // Called when we need to clean up + // Must be called from Activity onDestroy + public void onDestroy() { + mNativeMapView.terminateContext(); + mNativeMapView.terminateDisplay(); + } + + // Called when we need to create the GL context + // Must be called from Activity onStart + public void onStart() { + } + + // Called when we need to terminate the GL context + // Must be called from Activity onPause + public void onStop() { + } + + // Called when we need to stop the render thread + // Must be called from Activity onPause + public void onPause() { + // Register for connectivity changes + getContext().unregisterReceiver(mConnectivityReceiver); + mConnectivityReceiver = null; + + if (mIsMyLocationEnabled) { + toggleGps(false); + }; + + mNativeMapView.pause(); + } + + // Called when we need to start the render thread + // Must be called from Activity onResume + + public void onResume() { + // Register for connectivity changes + mConnectivityReceiver = new ConnectivityReceiver(); + mContext.registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); + + if (mIsMyLocationEnabled) { + toggleGps(true); + } + + mNativeMapView.resume(); + } + + public void onSizeChanged(int width, int height, int oldw, int oldh) { + if (!isInEditMode()) { + mNativeMapView.resizeView((int) (width / mScreenDensity), (int) (height / mScreenDensity)); + } + } + + // This class handles SurfaceHolder callbacks + private class Callbacks implements SurfaceHolder.Callback { + + // Called when the native surface buffer has been created + // Must do all EGL/GL ES initialization here + @Override + public void surfaceCreated(SurfaceHolder holder) { + mNativeMapView.createSurface(holder.getSurface()); + } + + // Called when the native surface buffer has been destroyed + // Must do all EGL/GL ES destruction here + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + mNativeMapView.destroySurface(); + } + + // Called when the format or size of the native surface buffer has been + // changed + // Must handle window resizing here. + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + mNativeMapView.resizeFramebuffer(width, height); + } + } + + @TargetApi(9) + private class Callbacks2 extends Callbacks implements SurfaceHolder.Callback2 { + + // Called when we need to redraw the view + // This is called before our view is first visible to prevent an initial + // flicker (see Android SDK documentation) + @Override + public void surfaceRedrawNeeded(SurfaceHolder holder) { + mNativeMapView.update(); + } + } + + // Called when view is no longer connected + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + // Required by ZoomButtonController (from Android SDK documentation) + if (mZoomButtonsController != null) { + mZoomButtonsController.setVisible(false); + } + } + + // Called when view is hidden and shown + @Override + protected void onVisibilityChanged(@NonNull View changedView, int visibility) { + // Required by ZoomButtonController (from Android SDK documentation) + if ((mZoomButtonsController != null) && (visibility != View.VISIBLE)) { + mZoomButtonsController.setVisible(false); + } + if ((mZoomButtonsController != null) && (visibility == View.VISIBLE) + && mZoomEnabled) { + mZoomButtonsController.setVisible(true); + } + } + + // Called when the system is running low on memory + // Must be called from Activity onLowMemory + public void onLowMemory() { + mNativeMapView.onLowMemory(); + } + + // + // Draw events + // + + // + // Input events + // + + // Zoom in or out + private void zoom(boolean zoomIn) { + zoom(zoomIn, -1.0f, -1.0f); + } + + private void zoom(boolean zoomIn, float x, float y) { + // Cancel any animation + mNativeMapView.cancelTransitions(); + + if (zoomIn) { + mNativeMapView.scaleBy(2.0, x / mScreenDensity, y / mScreenDensity, ANIMATION_DURATION); + } else { + // TODO two finger tap zoom out + mNativeMapView.scaleBy(0.5, x / mScreenDensity, y / mScreenDensity, ANIMATION_DURATION); + } + } + + // Called when user touches the screen, all positions are absolute + @Override @TargetApi(14) + public boolean onTouchEvent(@NonNull MotionEvent event) { + // Check and ignore non touch or left clicks + if ((android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) && (event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { + return false; + } + + // Check two finger gestures first + mRotateGestureDetector.onTouchEvent(event); + mScaleGestureDetector.onTouchEvent(event); + + // Handle two finger tap + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + // First pointer down + mNativeMapView.setGestureInProgress(true); + break; + + case MotionEvent.ACTION_POINTER_DOWN: + // Second pointer down + mTwoTap = event.getPointerCount() == 2; + break; + + case MotionEvent.ACTION_POINTER_UP: + // Second pointer up + break; + + case MotionEvent.ACTION_UP: + // First pointer up + long tapInterval = event.getEventTime() - event.getDownTime(); + boolean isTap = tapInterval <= ViewConfiguration.getTapTimeout(); + boolean inProgress = mRotateGestureDetector.isInProgress() || mScaleGestureDetector.isInProgress(); + mNativeMapView.setGestureInProgress(false); + + if (mTwoTap && isTap && !inProgress) { + PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); + zoom(false, focalPoint.x, focalPoint.y); + mTwoTap = false; + return true; + } + + mTwoTap = false; + break; + + case MotionEvent.ACTION_CANCEL: + mTwoTap = false; + mNativeMapView.setGestureInProgress(false); + break; + } + + boolean retVal = mGestureDetector.onTouchEvent(event); + return retVal || super.onTouchEvent(event); + } + + // This class handles one finger gestures + private class GestureListener extends + GestureDetector.SimpleOnGestureListener { + + // Must always return true otherwise all events are ignored + @Override + public boolean onDown(MotionEvent e) { + // Show the zoom controls + if ((mZoomButtonsController != null) && mZoomEnabled) { + mZoomButtonsController.setVisible(true); + } + + return true; + } + + // Called for double taps + @Override + public boolean onDoubleTap(MotionEvent e) { + if (!mZoomEnabled) { + return false; + } + + // Single finger double tap + // Zoom in + zoom(true, e.getX(), e.getY()); + return true; + } + + @Override + public boolean onSingleTapUp(MotionEvent e) { + // Cancel any animation + mNativeMapView.cancelTransitions(); + + return true; + } + + // Called for single taps after a delay + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + return false; + } + + // Called for a long press + @Override + public void onLongPress(MotionEvent e) { + // TODO + } + + // Called for flings + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + float velocityY) { + if (!mScrollEnabled) { + return false; + } + + // Fling the map + // TODO Google Maps also has a rotate and zoom fling + + float ease = 0.25f; + + velocityX = velocityX * ease; + velocityY = velocityY * ease; + + double speed = Math.sqrt(velocityX * velocityX + velocityY * velocityY); + double deceleration = 2500; + double duration = speed / (deceleration * ease); + + // Cancel any animation + mNativeMapView.cancelTransitions(); + + mNativeMapView.moveBy(velocityX * duration / 2.0 / mScreenDensity, velocityY * duration / 2.0 / mScreenDensity, (long) (duration * 1000.0f)); + + return true; + } + + // Called for drags + // TODO use MoveGestureDetector + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (!mScrollEnabled) { + return false; + } + + // Cancel any animation + mNativeMapView.cancelTransitions(); // TODO need to test canceling + // transitions with touch + + // Scroll the map + mNativeMapView.moveBy(-distanceX / mScreenDensity, -distanceY / mScreenDensity); + return true; + } + } + + // This class handles two finger gestures + private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + + long mBeginTime = 0; + float mScaleFactor = 1.0f; + boolean mStarted = false; + + // Called when two fingers first touch the screen + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + if (!mZoomEnabled) { + return false; + } + + mBeginTime = detector.getEventTime(); + return true; + } + + // Called when fingers leave screen + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + mBeginTime = 0; + mScaleFactor = 1.0f; + mStarted = false; + } + + // Called each time one of the two fingers moves + // Called for pinch zooms + @Override + public boolean onScale(ScaleGestureDetector detector) { + if (!mZoomEnabled) { + return false; + } + + // If scale is large enough ignore a tap + // TODO: Google Maps seem to use a velocity rather than absolute + // value? + mScaleFactor *= detector.getScaleFactor(); + if ((mScaleFactor > 1.05f) || (mScaleFactor < 0.95f)) { + mStarted = true; + } + + // Ignore short touches in case it is a tap + // Also ignore small scales + long time = detector.getEventTime(); + long interval = time - mBeginTime; + if (!mStarted && (interval <= ViewConfiguration.getTapTimeout())) { + return false; + } + + // TODO complex decision between rotate or scale or both (see Google + // Maps app) + + // Cancel any animation + mNativeMapView.cancelTransitions(); + + // Scale the map + mNativeMapView.scaleBy(detector.getScaleFactor(), detector.getFocusX() / mScreenDensity, detector.getFocusY() / mScreenDensity); + + return true; + } + } + + // This class handles two finger rotate gestures + // TODO need way to single finger rotate - need to research how google maps + // does this - for phones with single touch, or when using mouse etc + private class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { + + long mBeginTime = 0; + float mTotalAngle = 0.0f; + boolean mStarted = false; + + // Called when two fingers first touch the screen + @Override + public boolean onRotateBegin(RotateGestureDetector detector) { + if (!mRotateEnabled) { + return false; + } + + mBeginTime = detector.getEventTime(); + return true; + } + + // Called when the fingers leave the screen + @Override + public void onRotateEnd(RotateGestureDetector detector) { + mBeginTime = 0; + mTotalAngle = 0.0f; + mStarted = false; + } + + // Called each time one of the two fingers moves + // Called for rotation + @Override + public boolean onRotate(RotateGestureDetector detector) { + if (!mRotateEnabled) { + return false; + } + + // If rotate is large enough ignore a tap + // TODO: Google Maps seem to use a velocity rather than absolute + // value, up to a point then they always rotate + mTotalAngle += detector.getRotationDegreesDelta(); + if ((mTotalAngle > 5.0f) || (mTotalAngle < -5.0f)) { + mStarted = true; + } + + // Ignore short touches in case it is a tap + // Also ignore small rotate + long time = detector.getEventTime(); + long interval = time - mBeginTime; + if (!mStarted && (interval <= ViewConfiguration.getTapTimeout())) { + return false; + } + + // TODO complex decision between rotate or scale or both (see Google + // Maps app). It seems if you start one or the other it takes more + // to start the other too. Haven't figured out what it uses to + // decide when to transition to both at the same time. + + // Cancel any animation + mNativeMapView.cancelTransitions(); + + // Rotate the map + double bearing = mNativeMapView.getBearing(); + bearing += detector.getRotationDegreesDelta(); + mNativeMapView.setBearing(bearing, detector.getFocusX() / mScreenDensity, detector.getFocusY() / mScreenDensity); + + return true; + } + } + + // This class handles input events from the zoom control buttons + // Zoom controls allow single touch only devices to zoom in and out + private class OnZoomListener implements ZoomButtonsController.OnZoomListener { + + // Not used + @Override + public void onVisibilityChanged(boolean visible) { + // Ignore + } + + // Called when user pushes a zoom button + @Override + public void onZoom(boolean zoomIn) { + if (!mZoomEnabled) { + return; + } + + // Zoom in or out + zoom(zoomIn); + } + } + + // Called when the user presses a key, also called for repeating keys held + // down + @Override + public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) { + // If the user has held the scroll key down for a while then accelerate + // the scroll speed + double scrollDist = event.getRepeatCount() >= 5 ? 50.0 : 10.0; + + // Check which key was pressed via hardware/real key code + switch (keyCode) { + // Tell the system to track these keys for long presses on + // onKeyLongPress is fired + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + event.startTracking(); + return true; + + case KeyEvent.KEYCODE_DPAD_LEFT: + if (!mScrollEnabled) { + return false; + } + + // Cancel any animation + mNativeMapView.cancelTransitions(); + + // Move left + mNativeMapView.moveBy(scrollDist / mScreenDensity, 0.0 / mScreenDensity); + return true; + + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (!mScrollEnabled) { + return false; + } + + // Cancel any animation + mNativeMapView.cancelTransitions(); + + // Move right + mNativeMapView.moveBy(-scrollDist / mScreenDensity, 0.0 / mScreenDensity); + return true; + + case KeyEvent.KEYCODE_DPAD_UP: + if (!mScrollEnabled) { + return false; + } + + // Cancel any animation + mNativeMapView.cancelTransitions(); + + // Move up + mNativeMapView.moveBy(0.0 / mScreenDensity, scrollDist / mScreenDensity); + return true; + + case KeyEvent.KEYCODE_DPAD_DOWN: + if (!mScrollEnabled) { + return false; + } + + // Cancel any animation + mNativeMapView.cancelTransitions(); + + // Move down + mNativeMapView.moveBy(0.0 / mScreenDensity, -scrollDist / mScreenDensity); + return true; + + default: + // We are not interested in this key + return super.onKeyUp(keyCode, event); + } + } + + // Called when the user long presses a key that is being tracked + @Override + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + // Check which key was pressed via hardware/real key code + switch (keyCode) { + // Tell the system to track these keys for long presses on + // onKeyLongPress is fired + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + if (!mZoomEnabled) { + return false; + } + + // Zoom out + zoom(false); + return true; + + default: + // We are not interested in this key + return super.onKeyUp(keyCode, event); + } + } + + // Called when the user releases a key + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + // Check if the key action was canceled (used for virtual keyboards) + if (event.isCanceled()) { + return super.onKeyUp(keyCode, event); + } + + // Check which key was pressed via hardware/real key code + // Note if keyboard does not have physical key (ie primary non-shifted + // key) then it will not appear here + // Must use the key character map as physical to character is not + // fixed/guaranteed + switch (keyCode) { + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + if (!mZoomEnabled) { + return false; + } + + // Zoom in + zoom(true); + return true; + } + + // We are not interested in this key + return super.onKeyUp(keyCode, event); + } + + // Called for trackball events, all motions are relative in device specific + // units + @Override + public boolean onTrackballEvent(MotionEvent event) { + // Choose the action + switch (event.getActionMasked()) { + // The trackball was rotated + case MotionEvent.ACTION_MOVE: + if (!mScrollEnabled) { + return false; + } + + // Cancel any animation + mNativeMapView.cancelTransitions(); + + // Scroll the map + mNativeMapView.moveBy(-10.0 * event.getX() / mScreenDensity, -10.0 * event.getY() / mScreenDensity); + return true; + + // Trackball was pushed in so start tracking and tell system we are + // interested + // We will then get the up action + case MotionEvent.ACTION_DOWN: + // Set up a delayed callback to check if trackball is still + // After waiting the system long press time out + if (mCurrentTrackballLongPressTimeOut != null) { + mCurrentTrackballLongPressTimeOut.cancel(); + mCurrentTrackballLongPressTimeOut = null; + } + mCurrentTrackballLongPressTimeOut = new TrackballLongPressTimeOut(); + postDelayed(mCurrentTrackballLongPressTimeOut, + ViewConfiguration.getLongPressTimeout()); + return true; + + // Trackball was released + case MotionEvent.ACTION_UP: + if (!mZoomEnabled) { + return false; + } + + // Only handle if we have not already long pressed + if (mCurrentTrackballLongPressTimeOut != null) { + // Zoom in + zoom(true); + } + return true; + + // Trackball was cancelled + case MotionEvent.ACTION_CANCEL: + if (mCurrentTrackballLongPressTimeOut != null) { + mCurrentTrackballLongPressTimeOut.cancel(); + mCurrentTrackballLongPressTimeOut = null; + } + return true; + + default: + // We are not interested in this event + return super.onTrackballEvent(event); + } + } + + // This class implements the trackball long press time out callback + private class TrackballLongPressTimeOut implements Runnable { + + // Track if we have been cancelled + private boolean cancelled; + + public TrackballLongPressTimeOut() { + cancelled = false; + } + + // Cancel the timeout + public void cancel() { + cancelled = true; + } + + // Called when long press time out expires + @Override + public void run() { + // Check if the trackball is still pressed + if (!cancelled) { + // Zoom out + zoom(false); + + // Ensure the up action is not run + mCurrentTrackballLongPressTimeOut = null; + } + } + } + + // Called for events that don't fit the other handlers + // such as mouse scroll events, mouse moves, joystick, trackpad + @Override @TargetApi(12) + public boolean onGenericMotionEvent(MotionEvent event) { + // Mouse events + //if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // this is not available before API 18 + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == InputDevice.SOURCE_CLASS_POINTER) { + // Choose the action + switch (event.getActionMasked()) { + // Mouse scrolls + case MotionEvent.ACTION_SCROLL: + if (!mZoomEnabled) { + return false; + } + + // Cancel any animation + mNativeMapView.cancelTransitions(); + + // Get the vertical scroll amount, one click = 1 + float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL); + + // Scale the map by the appropriate power of two factor + mNativeMapView.scaleBy(Math.pow(2.0, scrollDist), event.getX() / mScreenDensity, event.getY() / mScreenDensity); + + return true; + + default: + // We are not interested in this event + return super.onGenericMotionEvent(event); + } + } + + // We are not interested in this event + return super.onGenericMotionEvent(event); + } + + // Called when the mouse pointer enters or exits the view + // or when it fades in or out due to movement + @Override @TargetApi(14) + public boolean onHoverEvent(@NonNull MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_HOVER_ENTER: + case MotionEvent.ACTION_HOVER_MOVE: + // Show the zoom controls + if ((mZoomButtonsController != null) && mZoomEnabled) { + mZoomButtonsController.setVisible(true); + } + return true; + + case MotionEvent.ACTION_HOVER_EXIT: + // Hide the zoom controls + if (mZoomButtonsController != null) { + mZoomButtonsController.setVisible(false); + } + + default: + // We are not interested in this event + return super.onHoverEvent(event); + } + } + + // + // Action events + // + + // This class handles connectivity changes + public class ConnectivityReceiver extends BroadcastReceiver { + + // Called when an action we are listening to in the manifest has been sent + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); + onConnectivityChanged(!noConnectivity); + } + } + } + + // Called when our Internet connectivity has changed + private void onConnectivityChanged(boolean isConnected) { + mNativeMapView.setReachability(isConnected); + } + + // + // Accessibility events + // + + // + // Map events + // + + // Called when the map needs to be rerendered + // Called via JNI from NativeMapView + protected void onInvalidate() { + post(new Runnable() { + @Override + public void run() { + mNativeMapView.invalidate(); + } + }); + } + + + /** + * Defines callback for events OnMapChange + */ + public interface OnMapChangedListener { + void onMapChanged(); + } + + /** + * Add an OnMapChangedListner + * @param listener Listener to add + */ + public void addOnMapChangedListener(@NonNull OnMapChangedListener listener) { + if (listener != null) { + mOnMapChangedListener.add(listener); + } + } + + /** + * Remove an OnMapChangedListener + * @param listener Listener to remove + */ + public void removeOnMapChangedListener(@NonNull OnMapChangedListener listener) { + if (listener != null) { + mOnMapChangedListener.remove(listener); + } + } + + // Called when the map view transformation has changed + // Called via JNI from NativeMapView + // Need to update anything that relies on map state + protected void onMapChanged() { + if (mOnMapChangedListener != null) { + post(new Runnable() { + @Override + public void run() { + for (OnMapChangedListener listener : mOnMapChangedListener) { + listener.onMapChanged(); + } + } + }); + } + } + + public interface OnFpsChangedListener { + void onFpsChanged(double fps); + } + + private OnFpsChangedListener mOnFpsChangedListener; + + // Adds a listener for onFpsChanged + public void setOnFpsChangedListener(OnFpsChangedListener listener) { + mOnFpsChangedListener = listener; + } + + // Called when debug mode is enabled to update a FPS counter + // Called via JNI from NativeMapView + protected void onFpsChanged(final double fps) { + if (mOnFpsChangedListener != null) { + post(new Runnable() { + @Override + public void run() { + mOnFpsChangedListener.onFpsChanged(fps); + } + }); + } + } + + // Google Maps Inspired API + + /** + * Gets the status of the my-location layer. + * @return True if the my-location layer is enabled, false otherwise. + */ + public final boolean isMyLocationEnabled () { + return mIsMyLocationEnabled; + } + + /** + * Enables or disables the my-location layer. + * While enabled, the my-location layer continuously draws an indication of a user's current + * location and bearing, and displays UI controls that allow a user to interact with their + * location (for example, to enable or disable camera tracking of their location and bearing). + * @param enabled True to enable; false to disable. + */ + public final void setMyLocationEnabled (boolean enabled) { + mIsMyLocationEnabled = enabled; + toggleGps(enabled); + updateMap(); + } + + /** + * Returns the currently displayed user location, or null if there is no location data available. + * @return The currently displayed user location. + */ + public final Location getMyLocation () { + return mGpsLocation; + } + + /** + * Enabled / Disable GPS location updates along with updating the UI + * @param enableGps true if GPS is to be enabled, false if GPS is to be disabled + */ + private void toggleGps(boolean enableGps) { + if (enableGps) { + if (!mLocationClient.isConnected()) { + mGpsLocation = null; + mLocationClient.connect(); + updateLocation(LocationServices.FusedLocationApi.getLastLocation()); + LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, this); + mSensorManager.registerListener(mCompassListener, mSensorAccelerometer, SensorManager.SENSOR_DELAY_UI); + mSensorManager.registerListener(mCompassListener, mSensorMagneticField, SensorManager.SENSOR_DELAY_UI); + } + } else { + if (mLocationClient.isConnected()) { + LocationServices.FusedLocationApi.removeLocationUpdates(this); + mLocationClient.disconnect(); + mGpsLocation = null; + mSensorManager.unregisterListener(mCompassListener, mSensorAccelerometer); + mSensorManager.unregisterListener(mCompassListener, mSensorMagneticField); + } + } + } + + /** + * Gets whether the compass is enabled/disabled. + * @return true if the compass is enabled; false if the compass is disabled. + */ + public boolean isCompassEnabled () { + return mIsCompassEnabled; + } + + /** + * Enables or disables the compass. The compass is an icon on the map that indicates the + * direction of north on the map. If enabled, it is only shown when the camera is tilted or + * rotated away from its default orientation (tilt of 0 and a bearing of 0). When a user clicks + * the compass, the camera orients itself to its default orientation and fades away shortly + * after. If disabled, the compass will never be displayed. + * + * By default, the compass is enabled + * @param compassEnabled true to enable the compass; false to disable the compass. + */ + public void setCompassEnabled (boolean compassEnabled) { + // Set value + this.mIsCompassEnabled = compassEnabled; + + // Toggle UI + if (mIsCompassEnabled) { + mCompassView.setVisibility(View.VISIBLE); + } else { + mCompassView.setVisibility(View.GONE); + } + + // Update Map + updateMap(); + } + + // This class handles sensor updates to calculate compass bearing + private class CompassListener implements SensorEventListener { + + @Override + public void onSensorChanged(SensorEvent event) { + switch (event.sensor.getType()) { + case Sensor.TYPE_ACCELEROMETER: + System.arraycopy(event.values, 0, mValuesAccelerometer, 0, 3); + break; + case Sensor.TYPE_MAGNETIC_FIELD: + System.arraycopy(event.values, 0, mValuesMagneticField, 0, 3); + break; + } + + boolean valid = SensorManager.getRotationMatrix(mMatrixR, mMatrixI, + mValuesAccelerometer, + mValuesMagneticField); + + if (valid) { + SensorManager.getOrientation(mMatrixR, mMatrixValues); + //mAzimuthRadians.putValue(mMatrixValues[0]); + //mAzimuth = Math.toDegrees(mAzimuthRadians.getAverage()); + + Location mGpsLocation = getMyLocation(); + if (mGpsLocation != null) { + GeomagneticField geomagneticField = new GeomagneticField( + (float) mGpsLocation.getLatitude(), + (float) mGpsLocation.getLongitude(), + (float) mGpsLocation.getAltitude(), + System.currentTimeMillis()); + mCompassBearing = (float) Math.toDegrees(mMatrixValues[0]) + geomagneticField.getDeclination(); + mCompassValid = true; + } + } + + updateMap(); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + // TODO: ignore unreliable stuff + } + } + + // Called when someone presses the compass + private class CompassOnClickListener implements View.OnClickListener { + + @Override + public void onClick(View view) { + resetNorth(); + } + + } + + /** + * LOST's LocationListener Callback + * @param location New Location + */ + @Override + public void onLocationChanged(Location location) { + Log.i(TAG, "onLocationChanged(): " + location); + updateLocation(location); + } + + // Handles location updates from GPS + private void updateLocation(Location location) { + if (location != null) { + mGpsLocation = location; + updateMap(); + } + } + + // Rotates an ImageView - does not work if the ImageView has padding, use margins + private void rotateImageView(ImageView imageView, float angle) { + Matrix matrix = new Matrix(); + matrix.setScale((float) imageView.getWidth() / (float) imageView.getDrawable().getIntrinsicWidth(), (float) imageView.getHeight() / (float) imageView.getDrawable().getIntrinsicHeight()); + matrix.postRotate(angle, (float) imageView.getWidth() / 2.0f, (float) imageView.getHeight() / 2.0f); + imageView.setImageMatrix(matrix); + imageView.setScaleType(ImageView.ScaleType.MATRIX); + } + + // Updates the UI to match the current map's position + private void updateMap() { + // Using direct access to mIsCompassEnabled instead of isCompassEnabled() for + // small performance boost as this method is called rapidly. + if (mIsCompassEnabled) { + rotateImageView(mCompassView, (float) getDirection()); + } + + if (isMyLocationEnabled() && mGpsLocation != null) { + if (mGpsMarker == null) { + // Setup User Location UI + // NOTE: mIsMyLocationEnabled == false to begin with + mGpsMarker = new ImageView(getContext()); + mGpsMarker.setImageResource(R.drawable.location_marker); + addView(mGpsMarker); + } + + mGpsMarker.setVisibility(View.VISIBLE); + LatLng coordinate = new LatLng(mGpsLocation); + PointF screenLocation = toScreenLocation(coordinate); + + float iconSize = 27.0f * mScreenDensity; + // Update Location + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) iconSize, (int) iconSize); + lp.leftMargin = (int) (screenLocation.x - iconSize / 2.0f); + lp.topMargin = getHeight() - (int) (screenLocation.y + iconSize / 2.0f); + mGpsMarker.setLayoutParams(lp); + rotateImageView(mGpsMarker, 0.0f); + mGpsMarker.requestLayout(); + + // Update direction if tracking mode + if(mUserLocationTrackingMode == UserLocationTrackingMode.FOLLOW_BEARING && mCompassValid){ + // TODO need to do proper filtering (see branch filter-compass) or else map will lock up because of all the compass events + long t = new Date().getTime(); + if((t-t0)>1000){ + t0 = t; + setDirection(-mCompassBearing, true); + } + } + +/* + // TODO - Too much overhead on main thread. Needs to be refactored before it + // can be re-enabled + // Update map position if NOT in NONE mode + if (mUserLocationTrackingMode != UserLocationTrackingMode.NONE) { + setCenterCoordinate(new LatLng(mGpsLocation)); + } +*/ + +/* + // Used For User Location Bearing UI + if (mGpsLocation.hasBearing() || mCompassValid) { + mGpsMarker.setImageResource(R.drawable.direction_arrow); + float iconSize = 54.0f * mScreenDensity; + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) iconSize, (int) iconSize); + lp.leftMargin = (int) (screenLocation.x - iconSize / 2.0f); + lp.topMargin = mMapFrameLayout.getHeight() - (int) (screenLocation.y + iconSize / 2.0f); + mGpsMarker.setLayoutParams(lp); + float bearing = mGpsLocation.hasBearing() ? mGpsLocation.getBearing() : mCompassBearing; + rotateImageView(mGpsMarker, bearing); + mGpsMarker.requestLayout(); + } +*/ + } else { + if (mGpsMarker != null) { + mGpsMarker.setVisibility(View.INVISIBLE); + } + } + } +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java new file mode 100644 index 000000000..6257a2362 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java @@ -0,0 +1,600 @@ +package com.mapbox.mapboxgl.views; + +import android.graphics.PointF; +import android.view.Surface; + +import com.mapbox.mapboxgl.annotations.Marker; +import com.mapbox.mapboxgl.annotations.Polygon; +import com.mapbox.mapboxgl.annotations.Polyline; +import com.mapbox.mapboxgl.geometry.LatLng; +import com.mapbox.mapboxgl.geometry.LatLngZoom; +import com.mapbox.mapboxgl.geometry.ProjectedMeters; + +import java.util.List; + +// Class that wraps the native methods for convenience +class NativeMapView { + + // + // Static members + // + + // + // Instance members + // + + // Holds the pointer to JNI NativeMapView + private long mNativeMapViewPtr = 0; + + // Used for callbacks + private MapView mMapView; + + // + // Static methods + // + + static { + System.loadLibrary("mapbox-gl"); + } + + // + // Constructors + // + + public NativeMapView(MapView mapView, String cachePath, String dataPath, String apkPath, float pixelRatio, int availableProcessors, long totalMemory) { + if (availableProcessors < 0) { + throw new IllegalArgumentException("availableProcessors cannot be negative."); + } + + if (totalMemory < 0) { + throw new IllegalArgumentException("totalMemory cannot be negative."); + } + + mMapView = mapView; + + // Create the NativeMapView + mNativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio, availableProcessors, totalMemory); + } + + // + // Methods + // + + public void initializeDisplay() { + nativeInitializeDisplay(mNativeMapViewPtr); + } + + public void terminateDisplay() { + nativeTerminateDisplay(mNativeMapViewPtr); + } + + public void initializeContext() { + nativeInitializeContext(mNativeMapViewPtr); + } + + public void terminateContext() { + nativeTerminateContext(mNativeMapViewPtr); + } + + public void createSurface(Surface surface) { + nativeCreateSurface(mNativeMapViewPtr, surface); + } + + public void destroySurface() { + nativeDestroySurface(mNativeMapViewPtr); + } + + public void pause() { + nativePause(mNativeMapViewPtr); + } + + public void resume() { + nativeResume(mNativeMapViewPtr); + } + + public void update() { + nativeUpdate(mNativeMapViewPtr); + } + + public void invalidate() { + nativeOnInvalidate(mNativeMapViewPtr); + } + + public void resizeView(int width, int height) { + if (width < 0) { + throw new IllegalArgumentException("width cannot be negative."); + } + + if (height < 0) { + throw new IllegalArgumentException("height cannot be negative."); + } + + if (width > 65535) { + throw new IllegalArgumentException( + "width cannot be greater than 65535."); + } + + if (height > 65535) { + throw new IllegalArgumentException( + "height cannot be greater than 65535."); + } + nativeViewResize(mNativeMapViewPtr, width, height); + } + + public void resizeFramebuffer(int fbWidth, int fbHeight) { + if (fbWidth < 0) { + throw new IllegalArgumentException("fbWidth cannot be negative."); + } + + if (fbHeight < 0) { + throw new IllegalArgumentException("fbHeight cannot be negative."); + } + + if (fbWidth > 65535) { + throw new IllegalArgumentException( + "fbWidth cannot be greater than 65535."); + } + + if (fbHeight > 65535) { + throw new IllegalArgumentException( + "fbHeight cannot be greater than 65535."); + } + nativeFramebufferResize(mNativeMapViewPtr, fbWidth, fbHeight); + } + + public void addClass(String clazz) { + nativeAddClass(mNativeMapViewPtr, clazz); + } + + public void removeClass(String clazz) { + nativeRemoveClass(mNativeMapViewPtr, clazz); + } + + public boolean hasClass(String clazz) { + return nativeHasClass(mNativeMapViewPtr, clazz); + } + + public void setClasses(List classes) { + nativeSetClasses(mNativeMapViewPtr, classes); + } + + public List getClasses() { + return nativeGetClasses(mNativeMapViewPtr); + } + + public void setDefaultTransitionDuration() { + setDefaultTransitionDuration(0); + } + + public long getDefaultTransitionDuration() { + return nativeGetDefaultTransitionDuration(mNativeMapViewPtr); + } + + public void setDefaultTransitionDuration(long milliseconds) { + if (milliseconds < 0) { + throw new IllegalArgumentException( + "milliseconds cannot be negative."); + } + + nativeSetDefaultTransitionDuration(mNativeMapViewPtr, + milliseconds); + } + + public void setStyleUrl(String url) { + nativeSetStyleUrl(mNativeMapViewPtr, url); + } + + public void setStyleJson(String newStyleJson) { + setStyleJson(newStyleJson, ""); + } + + public void setStyleJson(String newStyleJson, String base) { + nativeSetStyleJson(mNativeMapViewPtr, newStyleJson, base); + } + + public String getStyleJson() { + return nativeGetStyleJson(mNativeMapViewPtr); + } + + public void setAccessToken(String accessToken) { + nativeSetAccessToken(mNativeMapViewPtr, accessToken); + } + + public String getAccessToken() { + return nativeGetAccessToken(mNativeMapViewPtr); + } + + public void cancelTransitions() { + nativeCancelTransitions(mNativeMapViewPtr); + } + + public void setGestureInProgress(boolean inProgress) { + nativeSetGestureInProgress(mNativeMapViewPtr, inProgress); + } + + public void moveBy(double dx, double dy) { + moveBy(dx, dy, 0); + } + + public void moveBy(double dx, double dy, long duration) { + nativeMoveBy(mNativeMapViewPtr, dx, dy, duration); + } + + public void setLatLng(LatLng latLng) { + setLatLng(latLng, 0); + } + + public void setLatLng(LatLng latLng, long duration) { + nativeSetLatLng(mNativeMapViewPtr, latLng, duration); + } + + public LatLng getLatLng() { + return nativeGetLatLng(mNativeMapViewPtr); + } + + public void resetPosition() { + nativeResetPosition(mNativeMapViewPtr); + } + + public void scaleBy(double ds) { + scaleBy(ds, -1.0, -1.0); + } + + public void scaleBy(double ds, double cx, double cy) { + scaleBy(ds, cx, cy, 0); + } + + public void scaleBy(double ds, double cx, double cy, long duration) { + nativeScaleBy(mNativeMapViewPtr, ds, cx, cy, duration); + } + + public void setScale(double scale) { + setScale(scale, -1.0, -1.0); + } + + public void setScale(double scale, double cx, double cy) { + setScale(scale, cx, cy, 0); + } + + public void setScale(double scale, double cx, double cy, long duration) { + nativeSetScale(mNativeMapViewPtr, scale, cx, cy, duration); + } + + public double getScale() { + return nativeGetScale(mNativeMapViewPtr); + } + + public void setZoom(double zoom) { + setZoom(zoom, 0); + } + + public void setZoom(double zoom, long duration) { + nativeSetZoom(mNativeMapViewPtr, zoom, duration); + } + + public double getZoom() { + return nativeGetZoom(mNativeMapViewPtr); + } + + public void setLatLngZoom(LatLngZoom latLngZoom) { + setLatLngZoom(latLngZoom, 0); + } + + public void setLatLngZoom(LatLngZoom latLngZoom, long duration) { + nativeSetLatLngZoom(mNativeMapViewPtr, latLngZoom, duration); + } + + public LatLngZoom getLatLngZoom() { + return nativeGetLatLngZoom(mNativeMapViewPtr); + } + + public void resetZoom() { + nativeResetZoom(mNativeMapViewPtr); + } + + public double getMinZoom() { + return nativeGetMinZoom(mNativeMapViewPtr); + } + + public double getMaxZoom() { + return nativeGetMaxZoom(mNativeMapViewPtr); + } + + public void rotateBy(double sx, double sy, double ex, double ey) { + rotateBy(sx, sy, ex, ey, 0); + } + + public void rotateBy(double sx, double sy, double ex, double ey, + long duration) { + nativeRotateBy(mNativeMapViewPtr, sx, sy, ex, ey, duration); + } + + public void setBearing(double degrees) { + setBearing(degrees, 0); + } + + public void setBearing(double degrees, long duration) { + nativeSetBearing(mNativeMapViewPtr, degrees, duration); + } + + public void setBearing(double degrees, double cx, double cy) { + nativeSetBearing(mNativeMapViewPtr, degrees, cx, cy); + } + + public double getBearing() { + return nativeGetBearing(mNativeMapViewPtr); + } + + public void resetNorth() { + nativeResetNorth(mNativeMapViewPtr); + } + + public long addMarker(Marker marker) { + return nativeAddMarker(mNativeMapViewPtr, marker); + } + + public long addPolyline(Polyline polyline) { + return nativeAddPolyline(mNativeMapViewPtr, polyline); + } + + public long addPolygon(Polygon polygon) { + return nativeAddPolygon(mNativeMapViewPtr, polygon); + } + + public long[] addPolygons(List polygon) { + return nativeAddPolygons(mNativeMapViewPtr, polygon); + } + + public void removeAnnotation(long id) { + nativeRemoveAnnotation(mNativeMapViewPtr, id); + } + + public void removeAnnotations(long[] ids) { + nativeRemoveAnnotations(mNativeMapViewPtr, ids); + } + + public void setSprite(String symbol, int width, int height, float scale, byte[] pixels) { + nativeSetSprite(mNativeMapViewPtr, symbol, width, height, scale, pixels); + } + + public void onLowMemory() { + nativeOnLowMemory(mNativeMapViewPtr); + } + + public void setDebug(boolean debug) { + nativeSetDebug(mNativeMapViewPtr, debug); + } + + public void toggleDebug() { + nativeToggleDebug(mNativeMapViewPtr); + } + + public boolean getDebug() { + return nativeGetDebug(mNativeMapViewPtr); + } + + public void setCollisionDebug(boolean debug) { + nativeSetCollisionDebug(mNativeMapViewPtr, debug); + } + + public void toggleCollisionDebug() { + nativeToggleCollisionDebug(mNativeMapViewPtr); + } + + public boolean getCollisionDebug() { + return nativeGetCollisionDebug(mNativeMapViewPtr); + } + + public boolean isFullyLoaded() { + return nativeIsFullyLoaded(mNativeMapViewPtr); + } + + public void setReachability(boolean status) { + nativeSetReachability(mNativeMapViewPtr, status); + } + + //public void (); + + //public void getWorldBoundsLatLng(); + + public double getMetersPerPixelAtLatitude(double lat, double zoom) { + return nativeGetMetersPerPixelAtLatitude(mNativeMapViewPtr, lat, zoom); + } + + public ProjectedMeters projectedMetersForLatLng(LatLng latLng) { + return nativeProjectedMetersForLatLng(mNativeMapViewPtr, latLng); + } + + public LatLng latLngForProjectedMeters(ProjectedMeters projectedMeters) { + return nativeLatLngForProjectedMeters(mNativeMapViewPtr, projectedMeters); + } + + public PointF pixelForLatLng(LatLng latLng) { + return nativePixelForLatLng(mNativeMapViewPtr, latLng); + } + + public LatLng latLngForPixel(PointF pixel) { + return nativeLatLngForPixel(mNativeMapViewPtr, pixel); + } + + // + // Callbacks + // + + protected void onInvalidate() { + mMapView.onInvalidate(); + } + + protected void onMapChanged() { + mMapView.onMapChanged(); + } + + protected void onFpsChanged(double fps) { + mMapView.onFpsChanged(fps); + } + + // + // JNI methods + // + + @Override + protected void finalize() throws Throwable { + nativeDestroy(mNativeMapViewPtr); + mNativeMapViewPtr = 0; + super.finalize(); + } + + private native long nativeCreate(String cachePath, String dataPath, String apkPath, float pixelRatio, int availableProcessors, long totalMemory); + + private native void nativeDestroy(long nativeMapViewPtr); + + private native void nativeInitializeDisplay(long nativeMapViewPtr); + + private native void nativeTerminateDisplay(long nativeMapViewPtr); + + private native void nativeInitializeContext(long nativeMapViewPtr); + + private native void nativeTerminateContext(long nativeMapViewPtr); + + private native void nativeCreateSurface(long nativeMapViewPtr, + Surface surface); + + private native void nativeDestroySurface(long nativeMapViewPtr); + + private native void nativePause(long nativeMapViewPtr); + + private native void nativeResume(long nativeMapViewPtr); + + private native void nativeUpdate(long nativeMapViewPtr); + + private native void nativeOnInvalidate(long nativeMapViewPtr); + + private native void nativeViewResize(long nativeMapViewPtr, int width, int height); + + private native void nativeFramebufferResize(long nativeMapViewPtr, int fbWidth, int fbHeight); + + private native void nativeAddClass(long nativeMapViewPtr, String clazz); + + private native void nativeRemoveClass(long nativeMapViewPtr, String clazz); + + private native boolean nativeHasClass(long nativeMapViewPtr, String clazz); + + private native void nativeSetClasses(long nativeMapViewPtr, + List classes); + + private native List nativeGetClasses(long nativeMapViewPtr); + + private native void nativeSetDefaultTransitionDuration( + long nativeMapViewPtr, long duration); + + private native long nativeGetDefaultTransitionDuration(long nativeMapViewPtr); + + private native void nativeSetStyleUrl(long nativeMapViewPtr, String url); + + private native void nativeSetStyleJson(long nativeMapViewPtr, + String newStyleJson, String base); + + private native String nativeGetStyleJson(long nativeMapViewPtr); + + private native void nativeSetAccessToken(long nativeMapViewPtr, String accessToken); + + private native String nativeGetAccessToken(long nativeMapViewPtr); + + private native void nativeCancelTransitions(long nativeMapViewPtr); + + private native void nativeSetGestureInProgress(long nativeMapViewPtr, boolean inProgress); + + private native void nativeMoveBy(long nativeMapViewPtr, double dx, + double dy, long duration); + + private native void nativeSetLatLng(long nativeMapViewPtr, LatLng latLng, + long duration); + + private native LatLng nativeGetLatLng(long nativeMapViewPtr); + + private native void nativeResetPosition(long nativeMapViewPtr); + + private native void nativeScaleBy(long nativeMapViewPtr, double ds, + double cx, double cy, long duration); + + private native void nativeSetScale(long nativeMapViewPtr, double scale, + double cx, double cy, long duration); + + private native double nativeGetScale(long nativeMapViewPtr); + + private native void nativeSetZoom(long nativeMapViewPtr, double zoom, + long duration); + + private native double nativeGetZoom(long nativeMapViewPtr); + + private native void nativeSetLatLngZoom(long nativeMapViewPtr, + LatLngZoom lonLatZoom, long duration); + + private native LatLngZoom nativeGetLatLngZoom(long nativeMapViewPtr); + + private native void nativeResetZoom(long nativeMapViewPtr); + + private native double nativeGetMinZoom(long nativeMapViewPtr); + + private native double nativeGetMaxZoom(long nativeMapViewPtr); + + private native void nativeRotateBy(long nativeMapViewPtr, double sx, + double sy, double ex, double ey, long duration); + + private native void nativeSetBearing(long nativeMapViewPtr, double degrees, + long duration); + + private native void nativeSetBearing(long nativeMapViewPtr, double degrees, + double cx, double cy); + + private native double nativeGetBearing(long nativeMapViewPtr); + + private native void nativeResetNorth(long nativeMapViewPtr); + + private native long nativeAddMarker(long nativeMapViewPtr, Marker marker); + + private native long nativeAddPolyline(long nativeMapViewPtr, Polyline polyline); + + private native long nativeAddPolygon(long mNativeMapViewPtr, Polygon polygon); + + private native long[] nativeAddPolygons(long mNativeMapViewPtr, List polygon); + + private native void nativeRemoveAnnotation(long nativeMapViewPtr, long id); + + private native void nativeRemoveAnnotations(long nativeMapViewPtr, long[] id); + + private native void nativeSetSprite(long nativeMapViewPtr, String symbol, + int width, int height, float scale, byte[] pixels); + + private native void nativeOnLowMemory(long nativeMapViewPtr); + + private native void nativeSetDebug(long nativeMapViewPtr, boolean debug); + + private native void nativeToggleDebug(long nativeMapViewPtr); + + private native boolean nativeGetDebug(long nativeMapViewPtr); + + private native void nativeSetCollisionDebug(long nativeMapViewPtr, boolean debug); + + private native void nativeToggleCollisionDebug(long nativeMapViewPtr); + + private native boolean nativeGetCollisionDebug(long nativeMapViewPtr); + + private native boolean nativeIsFullyLoaded(long nativeMapViewPtr); + + private native void nativeSetReachability(long nativeMapViewPtr, boolean status); + + //private native void nativeGetWorldBoundsMeters(long nativeMapViewPtr); + + //private native void nativeGetWorldBoundsLatLng(long nativeMapViewPtr); + + private native double nativeGetMetersPerPixelAtLatitude(long nativeMapViewPtr, double lat, double zoom); + + private native ProjectedMeters nativeProjectedMetersForLatLng(long nativeMapViewPtr, LatLng latLng); + + private native LatLng nativeLatLngForProjectedMeters(long nativeMapViewPtr, ProjectedMeters projectedMeters); + + private native PointF nativePixelForLatLng(long nativeMapViewPtr, LatLng latLng); + + private native LatLng nativeLatLngForPixel(long nativeMapViewPtr, PointF pixel); +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/location_marker.png b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/location_marker.png new file mode 100644 index 000000000..f3a57845b Binary files /dev/null and b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/location_marker.png differ diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/drawable-ldpi/location_marker.png b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-ldpi/location_marker.png new file mode 100644 index 000000000..94a783781 Binary files /dev/null and b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-ldpi/location_marker.png differ diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/compass.png b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/compass.png new file mode 100644 index 000000000..58e7e08d2 Binary files /dev/null and b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/compass.png differ diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/location_marker.png b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/location_marker.png new file mode 100644 index 000000000..d8c156388 Binary files /dev/null and b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/location_marker.png differ diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/location_marker.png b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/location_marker.png new file mode 100644 index 000000000..157c48ade Binary files /dev/null and b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/location_marker.png differ diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/compass.png b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/compass.png new file mode 100644 index 000000000..58e7e08d2 Binary files /dev/null and b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/compass.png differ diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/location_marker.png b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/location_marker.png new file mode 100644 index 000000000..ccc56f660 Binary files /dev/null and b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/location_marker.png differ diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/location_marker.png b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/location_marker.png new file mode 100644 index 000000000..2318f1b7c Binary files /dev/null and b/android/java/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/location_marker.png differ diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/android/java/MapboxGLAndroidSDK/src/main/res/values/attrs.xml new file mode 100644 index 000000000..7148429db --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/res/values/attrs.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/values/strings.xml b/android/java/MapboxGLAndroidSDK/src/main/res/values/strings.xml new file mode 100644 index 000000000..df022a467 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Map compass. Click to reset the map rotation to North. + diff --git a/android/java/MapboxGLAndroidSDKTestApp/build.gradle b/android/java/MapboxGLAndroidSDKTestApp/build.gradle new file mode 100644 index 000000000..72dfdaa0c --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/build.gradle @@ -0,0 +1,108 @@ +buildscript { + repositories { + mavenCentral() + maven { url 'https://maven.fabric.io/public' } + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.0' + classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' + classpath 'io.fabric.tools:gradle:1.+' + } +} + +apply plugin: 'android-sdk-manager' +apply plugin: 'com.android.application' +apply plugin: 'io.fabric' + +repositories { + maven { url 'https://maven.fabric.io/public' } +} + +apply plugin: 'checkstyle' + +task accessToken { + def rawDir = new File("MapboxGLAndroidSDKTestApp/src/main/res/raw") + rawDir.mkdirs() + def tokenFile = new File("MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt") + if (!tokenFile.exists()) { + String token = "$System.env.MAPBOX_ACCESS_TOKEN" + if (token == null) { + throw new InvalidUserDataException("You must set the MAPBOX_ACCESS_TOKEN environment variable.") + } + tokenFile.write(token) + } +} + +gradle.projectsEvaluated { + preBuild.dependsOn('accessToken') +} + +android { + compileSdkVersion 23 + buildToolsVersion "23" + + repositories { + mavenCentral() + } + + defaultConfig { + applicationId "com.mapbox.mapboxgl.testapp" + minSdkVersion 8 + targetSdkVersion 23 + versionCode 4 + versionName "0.1.3" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + packagingOptions { + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + } + + lintOptions { + checkAllWarnings true + warningsAsErrors true + disable 'IconDensities' + disable 'InvalidPackage' + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { + compile(project(':MapboxGLAndroidSDK')) { + transitive = true + } + compile 'com.android.support:support-annotations:23.0.0' + compile 'com.android.support:support-v4:23.0.0' + compile 'com.android.support:appcompat-v7:23.0.0' + compile 'com.android.support:design:23.0.0' + compile('com.crashlytics.sdk.android:crashlytics:2.5.1@aar') { + transitive = true; + } +} + +checkstyle { + configFile project.file('../checks.xml') + showViolations true +} + +android.applicationVariants.all { variant -> + def name = variant.buildType.name + def checkstyle = project.tasks.create "checkstyle${name.capitalize()}", Checkstyle + checkstyle.dependsOn variant.javaCompile + checkstyle.source variant.javaCompile.source + checkstyle.classpath = project.fileTree(variant.javaCompile.destinationDir) + checkstyle.exclude('**/BuildConfig.java') + checkstyle.exclude('**/R.java') + project.tasks.getByName("check").dependsOn checkstyle +} diff --git a/android/java/MapboxGLAndroidSDKTestApp/lint.xml b/android/java/MapboxGLAndroidSDKTestApp/lint.xml new file mode 100644 index 000000000..94058fd4d --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/lint.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml new file mode 100644 index 000000000..85be72bb7 --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/assets/small_line.geojson b/android/java/MapboxGLAndroidSDKTestApp/src/main/assets/small_line.geojson new file mode 100644 index 000000000..ef76eaf56 --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/assets/small_line.geojson @@ -0,0 +1 @@ +{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"LineString","coordinates":[[-121.3714599609375,38.64583568648869],[-121.48681640624999,38.64047263931154],[-121.53076171875,38.61579745317875],[-121.56509399414061,38.57823196583313],[-121.75186157226561,38.533127435052776],[-121.97021484374999,38.35350340353833],[-122.08007812499999,38.24680876017446],[-122.16796875,38.19718009396176],[-122.23800659179686,38.09457899232253],[-122.27371215820312,38.01455819225337],[-122.33551025390625,37.94094845586459],[-122.27371215820312,37.81846319511331],[-122.4151611328125,37.7652868250379]]}}]} \ No newline at end of file diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/assets/small_poly.geojson b/android/java/MapboxGLAndroidSDKTestApp/src/main/assets/small_poly.geojson new file mode 100644 index 000000000..ec61303c7 --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/assets/small_poly.geojson @@ -0,0 +1 @@ +{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-122.28813171386719,38.617406963286136],[-122.26959228515624,38.6833657775237],[-122.18238830566406,38.55568323796419],[-122.10617065429688,38.51378825951165],[-122.11509704589845,38.50465406475561],[-122.18307495117188,38.542795073979015],[-122.19955444335938,38.496593518947556],[-122.28813171386719,38.617406963286136]]]}}]} \ No newline at end of file diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java new file mode 100644 index 000000000..a4358c773 --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java @@ -0,0 +1,453 @@ +package com.mapbox.mapboxgl.testapp; + +import android.Manifest; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.graphics.PointF; +import android.location.Location; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.NavigationView; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.GestureDetector; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.widget.TextView; +import com.crashlytics.android.Crashlytics; +import com.mapbox.mapboxgl.annotations.MarkerOptions; +import com.mapbox.mapboxgl.annotations.PolygonOptions; +import com.mapbox.mapboxgl.annotations.PolylineOptions; +import com.mapbox.mapboxgl.geometry.LatLng; +import com.mapbox.mapboxgl.views.MapView; +import io.fabric.sdk.android.Fabric; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; + +public class MainActivity extends AppCompatActivity { + + private static final String TAG = "MainActivity"; + + // + // Static members + // + + // Used for saving instance state + private static final String STATE_IS_ANNOTATIONS_ON = "isAnnotationsOn"; + private static final String STATE_SELECTED_STYLE = "selectedStyle"; + + // Used for permissions requests + private static final int PERMISSIONS_LOCATION = 0; + + // + // Instance members + // + + // Used for the UI + private DrawerLayout mDrawerLayout; + private MapView mMapView; + private TextView mFpsTextView; + private int mSelectedStyle = R.id.actionStyleMapboxStreets; + NavigationView mNavigationView; + + // Used for GPS + private FloatingActionButton mLocationFAB; + + // Used for Annotations + private boolean mIsAnnotationsOn = false; + + // + // Lifecycle events + // + + // Called when activity is created + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Fabric.with(this, new Crashlytics()); + + // Load the layout + setContentView(R.layout.activity_main); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + final ActionBar ab = getSupportActionBar(); + if (ab != null) { + ab.setHomeAsUpIndicator(R.drawable.ic_menu); + ab.setDisplayHomeAsUpEnabled(true); + } + + mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); + + mNavigationView = (NavigationView) findViewById(R.id.nav_view); + if (mNavigationView != null) { + setupDrawerContent(mNavigationView); + } + + mMapView = (MapView) findViewById(R.id.mainMapView); + // Load the access token + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.token))); + String line = reader.readLine(); + mMapView.setAccessToken(line); + } catch (IOException e) { + Log.e(TAG, "Error loading access token from token.txt: " + e.toString()); + } + + mMapView.onCreate(savedInstanceState); + mMapView.setOnFpsChangedListener(new MyOnFpsChangedListener()); + + final GestureDetector gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() { + public void onLongPress(final MotionEvent e) { + float x = e.getX(); + float y = e.getY(); + + // flip y direction vertically to match core GL + y = mMapView.getHeight() - y; + + LatLng position = mMapView.fromScreenLocation(new PointF(x, y)); + + mMapView.addMarker(new MarkerOptions() + .position(position) + .title("Dropped Pin") + .sprite("default_marker")); + } + }); + + mMapView.setOnTouchListener(new View.OnTouchListener() { + public boolean onTouch(View v, MotionEvent event) { + return gestureDetector.onTouchEvent(event); + } + }); + + mFpsTextView = (TextView) findViewById(R.id.view_fps); + mFpsTextView.setText(""); + + mLocationFAB = (FloatingActionButton)findViewById(R.id.locationFAB); + mLocationFAB.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Toggle GPS position updates + toggleGps(!mMapView.isMyLocationEnabled()); + if (mMapView.isMyLocationEnabled()) { + Location location = mMapView.getMyLocation(); + if (location != null) { + mMapView.setZoomLevel(8); + mMapView.setCenterCoordinate(new LatLng(location)); + } + } + } + }); + + // Restore saved state + if (savedInstanceState != null) { + mIsAnnotationsOn = savedInstanceState.getBoolean(STATE_IS_ANNOTATIONS_ON); + mSelectedStyle = savedInstanceState.getInt(STATE_SELECTED_STYLE); + } + + // Set default UI state + mNavigationView.getMenu().findItem(R.id.action_compass).setChecked(mMapView.isCompassEnabled()); + mNavigationView.getMenu().findItem(R.id.action_debug).setChecked(mMapView.isDebugActive()); + mNavigationView.getMenu().findItem(R.id.action_markers).setChecked(mIsAnnotationsOn); + changeMapStyle(mSelectedStyle); + toggleGps(mMapView.isMyLocationEnabled()); + } + + /** + * Dispatch onStart() to all fragments. Ensure any created loaders are + * now started. + */ + @Override + protected void onStart() { + super.onStart(); + mMapView.onStart(); + } + + @Override + protected void onStop() { + super.onStop(); + mMapView.onStop(); + } + + // Called when our app goes into the background + @Override + public void onPause() { + super.onPause(); + + mMapView.onPause(); + } + + // Called when our app comes into the foreground + @Override + public void onResume() { + super.onResume(); + + mMapView.onResume(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mMapView.onDestroy(); + } + + // Called when we need to save instance state + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + mMapView.onSaveInstanceState(outState); + outState.putBoolean(STATE_IS_ANNOTATIONS_ON, mIsAnnotationsOn); + outState.putInt(STATE_SELECTED_STYLE, mSelectedStyle); + } + + // Called when the system is running low on memory + @Override + public void onLowMemory() { + super.onLowMemory(); + + mMapView.onLowMemory(); + } + + // + // Other events + // + + // Called when pressing action bar items + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + mDrawerLayout.openDrawer(GravityCompat.START); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { + switch (requestCode) { + case PERMISSIONS_LOCATION: { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + enableGps(); + } + } + } + } + + private void setupDrawerContent(NavigationView navigationView) { + navigationView.setNavigationItemSelectedListener( + new NavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(MenuItem menuItem) { + mDrawerLayout.closeDrawers(); + + // Respond To Selection + switch (menuItem.getItemId()) { + + case R.id.action_debug: + // Toggle debug mode + mMapView.toggleDebug(); + toggleFpsCounter(mMapView.isDebugActive()); + menuItem.setChecked(mMapView.isDebugActive()); + return true; + + case R.id.action_markers: + // Toggle markers + toggleAnnotations(!mIsAnnotationsOn); + menuItem.setChecked(mIsAnnotationsOn); + return true; + + case R.id.action_compass: + // Toggle compass + mMapView.setCompassEnabled(!mMapView.isCompassEnabled()); + menuItem.setChecked(mMapView.isCompassEnabled()); + return true; + +/* + case R.id.followNone: + mMapView.setUserLocationTrackingMode(MapView.UserLocationTrackingMode.NONE); + return true; + + case R.id.followFollow: + mMapView.setUserLocationTrackingMode(MapView.UserLocationTrackingMode.FOLLOW); + return true; + + case R.id.followBearing: + mMapView.setUserLocationTrackingMode(MapView.UserLocationTrackingMode.FOLLOW_BEARING); + return true; +*/ + default: + return changeMapStyle(menuItem.getItemId()); + } + } + }); + } + + private void toggleFpsCounter(boolean enableFps) { + // Show the FPS counter + if (enableFps) { + mFpsTextView.setVisibility(View.VISIBLE); + mFpsTextView.setText(getResources().getString(R.string.label_fps)); + } else { + mFpsTextView.setVisibility(View.INVISIBLE); + } + } + + private boolean changeMapStyle(int id) { + switch (id) { + case R.id.actionStyleMapboxStreets: + mMapView.setStyleUrl(getString(R.string.styleURLMapboxStreets)); + mNavigationView.getMenu().findItem(id).setChecked(true); + mSelectedStyle = id; + return true; + + case R.id.actionStyleEmerald: + mMapView.setStyleUrl(getString(R.string.styleURLEmerald)); + mNavigationView.getMenu().findItem(id).setChecked(true); + mSelectedStyle = id; + return true; + + case R.id.actionStyleLight: + mMapView.setStyleUrl(getString(R.string.styleURLLight)); + mNavigationView.getMenu().findItem(id).setChecked(true); + mSelectedStyle = id; + return true; + + case R.id.actionStyleDark: + mMapView.setStyleUrl(getString(R.string.styleURLDark)); + mNavigationView.getMenu().findItem(id).setChecked(true); + mSelectedStyle = id; + return true; + + case R.id.actionStyleSatellite: + mMapView.setStyleUrl(getString(R.string.styleURLSatellite)); + mNavigationView.getMenu().findItem(id).setChecked(true); + mSelectedStyle = id; + return true; + + default: + return false; + } + } + + /** + * Enabled / Disable GPS location updates along with updating the UI + * @param enableGps true if GPS is to be enabled, false if GPS is to be disabled + */ + private void toggleGps(boolean enableGps) { + if (enableGps) { + if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) || + (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) + { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION); + } else { + enableGps(); + } + } else { + mMapView.setMyLocationEnabled(false); + mLocationFAB.setColorFilter(Color.TRANSPARENT); + } + } + + private void enableGps() { + mMapView.setMyLocationEnabled(true); + mLocationFAB.setColorFilter(ContextCompat.getColor(this, R.color.primary)); + } + + /** + * Enable / Disable Annotations. + * + * @param enableAnnotations True to display, False to hide + */ + private void toggleAnnotations(boolean enableAnnotations) { + if (enableAnnotations) { + if (!mIsAnnotationsOn) { + mIsAnnotationsOn = true; + addMarkers(); + addPolyline(); + addPolygon(); + mMapView.setZoomLevel(7); + mMapView.setCenterCoordinate(new LatLng(38.11727, -122.22839)); + } + } else { + if (mIsAnnotationsOn) { + mIsAnnotationsOn = false; + removeAnnotations(); + } + } + } + + private void addMarkers() { + LatLng backLot = new LatLng(38.649441, -121.369064); + mMapView.addMarker(new MarkerOptions() + .position(backLot) + .title("Back Lot") + .snippet("The back lot behind my house")); + + LatLng cheeseRoom = new LatLng(38.531577,-122.010646); + mMapView.addMarker(new MarkerOptions() + .position(cheeseRoom) + .sprite("dog-park-15") + .title("Cheese Room") + .snippet("The only air conditioned room on the property!")); + } + + private void addPolyline() { + try { + String geojsonStr = Util.loadStringFromAssets(this, "small_line.geojson"); + LatLng[] latLngs = Util.parseGeoJSONCoordinates(geojsonStr); + MapView map = mMapView; + map.addPolyline(new PolylineOptions() + .add(latLngs) + .width(2) + .color(Color.RED)); + } catch (Exception e) { + Log.e(TAG, "Error adding Polyline: "+ e); + e.printStackTrace(); + } + } + + private void addPolygon() { + try { + String geojsonStr = Util.loadStringFromAssets(this, "small_poly.geojson"); + LatLng[] latLngs = Util.parseGeoJSONCoordinates(geojsonStr); + MapView map = mMapView; + ArrayList opts = new ArrayList<>(); + opts.add(new PolygonOptions() + .add(latLngs) + .strokeColor(Color.MAGENTA) + .fillColor(Color.BLUE)); + map.addPolygons(opts).get(0); + } catch (Exception e) { + Log.e(TAG, "Error adding Polygon: "+ e); + e.printStackTrace(); + } + } + + private void removeAnnotations() { + mMapView.removeAnnotations(); + } + + // Called when FPS changes + private class MyOnFpsChangedListener implements MapView.OnFpsChangedListener { + + @Override + public void onFpsChanged(double fps) { + mFpsTextView.setText(getResources().getString(R.string.label_fps) + String.format(" %4.2f", fps)); + } + } + +} diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MapFragment.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MapFragment.java new file mode 100644 index 000000000..7883dbae4 --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MapFragment.java @@ -0,0 +1,116 @@ +package com.mapbox.mapboxgl.testapp; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.mapbox.mapboxgl.views.MapView; + +public class MapFragment extends Fragment { + + // + // Static members + // + + // Tag used for logging + private static final String TAG = "MapFragment"; + + // + // Instance members + // + + // The map + private MapView mMap; + + // + // Lifecycle events + // + + // Called when the fragment is created + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + Log.v(TAG, "onCreateView"); + + // Create the map + mMap = (MapView) inflater.inflate(R.layout.fragment_main, container, true); + + // Need to pass on any saved state to the map + mMap.onCreate(savedInstanceState); + + // Return the map as the root view + return mMap; + } + + // Called when the fragment is destroyed + @Override + public void onDestroyView() { + super.onDestroyView(); + Log.v(TAG, "onDestroyView"); + + // Need to pass on to view + mMap.onDestroy(); + mMap = null; + } + + // Called when the fragment is visible + @Override + public void onStart() { + super.onStart(); + Log.v(TAG, "onStart"); + + // Need to pass on to view + mMap.onStart(); + } + + // Called when the fragment is invisible + @Override + public void onStop() { + super.onStop(); + Log.v(TAG, "onStop"); + + // Need to pass on to view + mMap.onStop(); + } + + // Called when the fragment is in the background + @Override + public void onPause() { + super.onPause(); + Log.v(TAG, "onPause"); + + // Need to pass on to view + mMap.onPause(); + } + + // Called when the fragment is no longer in the background + @Override + public void onResume() { + super.onResume(); + Log.v(TAG, "onResume"); + + // Need to pass on to view + mMap.onResume(); + } + + // Called before fragment is destroyed + @Override + public void onSaveInstanceState(Bundle outState) { + Log.v(TAG, "onSaveInstanceState"); + + // Need to retrieve any saved state from the map + mMap.onSaveInstanceState(outState); + super.onSaveInstanceState(outState); + } + + // + // Property methods + // + + public MapView getMap() { + return mMap; + } +} diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/Util.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/Util.java new file mode 100644 index 000000000..74b909cec --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/Util.java @@ -0,0 +1,61 @@ +package com.mapbox.mapboxgl.testapp; + +import android.content.Context; +import android.text.TextUtils; + +import com.mapbox.mapboxgl.geometry.LatLng; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +public class Util { + + public static String loadStringFromAssets(final Context context, final String fileName) throws IOException { + if (TextUtils.isEmpty(fileName)) { + throw new NullPointerException("No GeoJSON File Name passed in."); + } + InputStream is = context.getAssets().open(fileName); + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + return readAll(rd); + } + + public static LatLng[] parseGeoJSONCoordinates(String geojsonStr) throws JSONException { + JSONObject jsonObject = new JSONObject(geojsonStr); + JSONArray features = jsonObject.getJSONArray("features"); + JSONObject feature = features.getJSONObject(0); + JSONObject geometry = feature.getJSONObject("geometry"); + String type = geometry.getString("type"); + JSONArray coordinates; + if (type.equals("Polygon")) { + coordinates = geometry.getJSONArray("coordinates").getJSONArray(0); + } else { + coordinates = geometry.getJSONArray("coordinates"); + } + int len = coordinates.length(); + LatLng[] latLngs = new LatLng[coordinates.length()]; + for (int i = 0; i < len; ++i) { + JSONArray coord = coordinates.getJSONArray(i); + double lng = coord.getDouble(0); + double lat = coord.getDouble(1); + latLngs[i] = new LatLng(lat, lng); + } + return latLngs; + } + + private static String readAll(Reader rd) throws IOException { + StringBuilder sb = new StringBuilder(); + int cp; + while ((cp = rd.read()) != -1) { + sb.append((char) cp); + } + return sb.toString(); + } +} diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_menu.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_menu.png new file mode 100644 index 000000000..8962cbd91 Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_menu.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_my_location_black_24dp.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_my_location_black_24dp.png new file mode 100644 index 000000000..85e38726d Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_my_location_black_24dp.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon.png new file mode 100644 index 000000000..f9875161d Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon_burned.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon_burned.png new file mode 100644 index 000000000..f9875161d Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon_burned.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_menu.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_menu.png new file mode 100644 index 000000000..c62db8c86 Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_menu.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_my_location_black_24dp.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_my_location_black_24dp.png new file mode 100644 index 000000000..5684aa7dc Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_my_location_black_24dp.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon.png new file mode 100644 index 000000000..3c0cc701a Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon_burned.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon_burned.png new file mode 100644 index 000000000..3c0cc701a Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon_burned.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_menu.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_menu.png new file mode 100644 index 000000000..36859f094 Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_menu.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_my_location_black_24dp.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_my_location_black_24dp.png new file mode 100644 index 000000000..7faa3455f Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_my_location_black_24dp.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon.png new file mode 100644 index 000000000..0cbf59936 Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon_burned.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon_burned.png new file mode 100644 index 000000000..0cbf59936 Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon_burned.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_menu.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_menu.png new file mode 100644 index 000000000..1a5109828 Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_menu.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_my_location_black_24dp.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_my_location_black_24dp.png new file mode 100644 index 000000000..d3a1ab08c Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_my_location_black_24dp.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon.png new file mode 100644 index 000000000..6ac3191eb Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon_burned.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon_burned.png new file mode 100644 index 000000000..6ac3191eb Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon_burned.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_menu.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_menu.png new file mode 100644 index 000000000..c15d63467 Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_menu.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_my_location_black_24dp.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_my_location_black_24dp.png new file mode 100644 index 000000000..0812b0e31 Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_my_location_black_24dp.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon.png new file mode 100644 index 000000000..987e6b024 Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon_burned.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon_burned.png new file mode 100644 index 000000000..987e6b024 Binary files /dev/null and b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon_burned.png differ diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..292f77c3a --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_main.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_main.xml new file mode 100644 index 000000000..642a5e7d3 --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_main.xml @@ -0,0 +1,6 @@ + + diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml new file mode 100644 index 000000000..a374ab18d --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_main.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_main.xml new file mode 100644 index 000000000..014fa25d6 --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_main.xml @@ -0,0 +1,3 @@ + + + diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml new file mode 100644 index 000000000..ac3b4fc30 --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml @@ -0,0 +1,7 @@ + + + #1E8CAB + #166B83 + #E55E5E + #FFFFFF + diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml new file mode 100644 index 000000000..f76eef07c --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml @@ -0,0 +1,4 @@ + + + 16dp + diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml new file mode 100644 index 000000000..81ba6e1cc --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml @@ -0,0 +1,33 @@ + + + + Mapbox GL + + Toggle GPS location + Disable tracking + Use follow tracking mode + Use bearing tracking mode tracking + Toggle compass + Toggle debug mode + Toggle point annotations + + FPS: + + Mapbox Streets + Emerald + Light + Dark + Satellite + + asset://styles/mapbox-streets-v7.json + asset://styles/emerald-v7.json + asset://styles/light-v7.json + asset://styles/dark-v7.json + asset://styles/satellite-v7.json + + + Day + Night + + + diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml new file mode 100644 index 000000000..9248bc7d0 --- /dev/null +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/android/java/build.gradle b/android/java/build.gradle new file mode 100644 index 000000000..b1f4c8d08 --- /dev/null +++ b/android/java/build.gradle @@ -0,0 +1,4 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +task wrapper(type: Wrapper) { + gradleVersion = '2.5' +} diff --git a/android/java/checks.xml b/android/java/checks.xml new file mode 100644 index 000000000..0ee271678 --- /dev/null +++ b/android/java/checks.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/java/gradle/wrapper/gradle-wrapper.jar b/android/java/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..30d399d8d Binary files /dev/null and b/android/java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/java/gradle/wrapper/gradle-wrapper.properties b/android/java/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..3212d53fb --- /dev/null +++ b/android/java/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Aug 07 10:13:04 AEST 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip diff --git a/android/java/gradlew b/android/java/gradlew new file mode 100755 index 000000000..91a7e269e --- /dev/null +++ b/android/java/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/android/java/gradlew.bat b/android/java/gradlew.bat new file mode 100644 index 000000000..8a0b282aa --- /dev/null +++ b/android/java/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/java/settings.gradle b/android/java/settings.gradle new file mode 100644 index 000000000..71a8f1a9a --- /dev/null +++ b/android/java/settings.gradle @@ -0,0 +1,2 @@ +include ':MapboxGLAndroidSDK' +include ':MapboxGLAndroidSDKTestApp' diff --git a/android/mapboxgl-app.gypi b/android/mapboxgl-app.gypi new file mode 100644 index 000000000..e3db1269d --- /dev/null +++ b/android/mapboxgl-app.gypi @@ -0,0 +1,89 @@ +{ + 'includes': [ + '../gyp/common.gypi', + ], + 'targets': [ + { 'target_name': 'android-lib', + 'product_name': 'mapbox-gl', + 'type': 'shared_library', + 'hard_dependency': 1, + + 'dependencies': [ + '../mbgl.gyp:core', + '../mbgl.gyp:platform-<(platform_lib)', + '../mbgl.gyp:http-<(http_lib)', + '../mbgl.gyp:asset-<(asset_lib)', + '../mbgl.gyp:cache-<(cache_lib)', + ], + + 'sources': [ + './cpp/native_map_view.cpp', + './cpp/jni.cpp', + ], + + 'cflags_cc': [ + '<@(boost_cflags)', + ], + 'libraries': [ + '<@(libpng_static_libs)', + '<@(jpeg_static_libs)', + '<@(sqlite_static_libs)', + '<@(libuv_static_libs)', + '<@(nunicode_static_libs)', + '<@(libzip_static_libs)', + ], + 'variables': { + 'ldflags': [ + '-llog', + '-landroid', + '-lEGL', + '-lGLESv2', + '-lstdc++', + '-latomic', + '<@(libpng_ldflags)', + '<@(jpeg_ldflags)', + '<@(sqlite_ldflags)', + '<@(zlib_ldflags)', + '<@(libzip_ldflags)', + ], + }, + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'OTHER_LDFLAGS': [ '<@(ldflags)' ], + } + }, { + 'libraries': [ '<@(ldflags)' ], + }] + ], + }, + + + { 'target_name': 'androidapp', + 'type': 'none', + 'hard_dependency': 1, + + 'variables': { + 'pwd': ' +#include +#include +#include + +#include +#include +#include +#include +#include + +#pragma GCC diagnostic push +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#pragma GCC diagnostic ignored "-Wshadow" +#endif +#include +#pragma GCC diagnostic pop + +namespace po = boost::program_options; + +#include + +#include +#include +#include + +int main(int argc, char *argv[]) { + std::string style_path; + double lat = 0, lon = 0; + double zoom = 0; + double bearing = 0; + + int width = 512; + int height = 512; + double pixelRatio = 1.0; + static std::string output = "out.png"; + std::string cache_file = "cache.sqlite"; + std::vector classes; + std::string token; + bool debug = false; + + po::options_description desc("Allowed options"); + desc.add_options() + ("style,s", po::value(&style_path)->required()->value_name("json"), "Map stylesheet") + ("lon,x", po::value(&lon)->value_name("degrees")->default_value(lon), "Longitude") + ("lat,y", po::value(&lat)->value_name("degrees")->default_value(lat), "Latitude in degrees") + ("zoom,z", po::value(&zoom)->value_name("number")->default_value(zoom), "Zoom level") + ("bearing,b", po::value(&bearing)->value_name("degrees")->default_value(bearing), "Bearing") + ("width,w", po::value(&width)->value_name("pixels")->default_value(width), "Image width") + ("height,h", po::value(&height)->value_name("pixels")->default_value(height), "Image height") + ("class,c", po::value(&classes)->value_name("name"), "Class name") + ("token,t", po::value(&token)->value_name("key")->default_value(token), "Mapbox access token") + ("debug", po::bool_switch(&debug)->default_value(debug), "Debug mode") + ("output,o", po::value(&output)->value_name("file")->default_value(output), "Output file name") + ("cache,d", po::value(&cache_file)->value_name("file")->default_value(cache_file), "Cache database file name") + ; + + try { + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + } catch(std::exception& e) { + std::cout << "Error: " << e.what() << std::endl << desc; + exit(1); + } + + std::string style = mbgl::util::read_file(style_path); + + using namespace mbgl; + + mbgl::SQLiteCache cache(cache_file); + mbgl::DefaultFileSource fileSource(&cache); + + // Try to load the token from the environment. + if (!token.size()) { + const char *token_ptr = getenv("MAPBOX_ACCESS_TOKEN"); + if (token_ptr) { + token = token_ptr; + } + } + + // Set access token if present + if (token.size()) { + fileSource.setAccessToken(std::string(token)); + } + + HeadlessView view(pixelRatio, width, height); + Map map(view, fileSource, MapMode::Still); + + map.setStyleJSON(style, "."); + map.setClasses(classes); + + map.setLatLngZoom({ lat, lon }, zoom); + map.setBearing(bearing); + + if (debug) { + map.setDebug(debug); + } + + uv_async_t *async = new uv_async_t; + uv_async_init(uv_default_loop(), async, [](uv_async_t *as, int) { + std::unique_ptr image(reinterpret_cast(as->data)); + uv_close(reinterpret_cast(as), [](uv_handle_t *handle) { + delete reinterpret_cast(handle); + }); + + const std::string png = util::compress_png(image->width, image->height, image->pixels.get()); + util::write_file(output, png); + }); + + map.renderStill([async](std::exception_ptr error, std::unique_ptr image) { + try { + if (error) { + std::rethrow_exception(error); + } + } catch(std::exception& e) { + std::cout << "Error: " << e.what() << std::endl; + exit(1); + } + + async->data = const_cast(image.release()); + uv_async_send(async); + }); + + // This loop will terminate once the async was fired. + uv_run(uv_default_loop(), UV_RUN_DEFAULT); +} diff --git a/bin/render.gypi b/bin/render.gypi new file mode 100644 index 000000000..45c9ebb0e --- /dev/null +++ b/bin/render.gypi @@ -0,0 +1,59 @@ +{ + 'includes': [ + '../gyp/common.gypi', + ], + 'targets': [ + { 'target_name': 'mbgl-render', + 'product_name': 'mbgl-render', + 'type': 'executable', + + 'dependencies': [ + '../mbgl.gyp:core', + '../mbgl.gyp:platform-<(platform_lib)', + '../mbgl.gyp:headless-<(headless_lib)', + '../mbgl.gyp:http-<(http_lib)', + '../mbgl.gyp:asset-<(asset_lib)', + '../mbgl.gyp:cache-<(cache_lib)', + '../mbgl.gyp:copy_certificate_bundle', + ], + + 'include_dirs': [ + '../src', + ], + + 'sources': [ + './render.cpp', + ], + + 'variables' : { + 'cflags_cc': [ + '<@(glfw_cflags)', + '<@(libuv_cflags)', + '<@(boost_cflags)', + ], + 'ldflags': [ + '<@(glfw_ldflags)', + '<@(libuv_ldflags)', + ], + 'libraries': [ + '<@(glfw_static_libs)', + '<@(libuv_static_libs)', + '<@(boost_libprogram_options_static_libs)' + ], + }, + + 'conditions': [ + ['OS == "mac"', { + 'libraries': [ '<@(libraries)' ], + 'xcode_settings': { + 'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ], + 'OTHER_LDFLAGS': [ '<@(ldflags)' ], + } + }, { + 'cflags_cc': [ '<@(cflags_cc)' ], + 'libraries': [ '<@(libraries)', '<@(ldflags)' ], + }] + ], + }, + ], +} diff --git a/common/ca-bundle.crt b/common/ca-bundle.crt new file mode 100644 index 000000000..9794dfb70 --- /dev/null +++ b/common/ca-bundle.crt @@ -0,0 +1,3866 @@ +## +## ca-bundle.crt -- Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Tue Apr 22 08:29:31 2014 +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## http://mxr.mozilla.org/mozilla-release/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## + + +GTE CyberTrust Global Root +========================== +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg +Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG +A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz +MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL +Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 +IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u +sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql +HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID +AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW +M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF +NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- + +Thawte Server CA +================ +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE +AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j +b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV +BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u +c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG +A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 +ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl +/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 +1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J +GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ +GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- + +Thawte Premium Server CA +======================== +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE +AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl +ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT +AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU +VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 +aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ +cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 +aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh +Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ +qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm +SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf +8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t +UCemDaYj+bvLpgcUQg== +-----END CERTIFICATE----- + +Equifax Secure CA +================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE +ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT +B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR +fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW +8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE +CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS +spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 +zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB +BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 +70+sB3c4 +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA +TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah +WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf +Tqj/ZA1k +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO +FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 +lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB +MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT +1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD +Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 +-----END CERTIFICATE----- + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +======================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 +ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp +s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN +S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL +TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C +ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i +YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN +BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp +9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu +01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 +9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +ValiCert Class 1 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy +MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi +GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm +DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG +lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX +icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP +Orf1LXLI +-----END CERTIFICATE----- + +ValiCert Class 2 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC +CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf +ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ +SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV +UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 +W9ViH0Pd +-----END CERTIFICATE----- + +RSA Root Certificate 1 +====================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td +3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H +BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs +3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF +V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r +on+jjBXu +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 +EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc +cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw +EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj +055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f +j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 +xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa +t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +Verisign Class 4 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS +tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM +8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW +Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX +Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt +mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd +RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG +UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- + +Entrust.net Secure Server CA +============================ +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg +cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl +ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG +A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi +eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p +dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ +aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 +gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw +ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw +CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l +dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF +bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu +dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw +NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow +HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA +BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN +Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 +n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ +KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy +T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT +J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e +nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Equifax Secure Global eBusiness CA +================================== +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp +bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx +HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds +b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV +PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN +qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn +hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs +MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN +I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY +NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 1 +============================= +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB +LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE +ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz +IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ +1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a +IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk +MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW +Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF +AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 +lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ +KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- + +AddTrust Low-Value Services Root +================================ +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU +cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw +CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO +ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 +54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr +oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 +Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui +GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w +HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw +HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt +ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph +iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr +mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj +ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- + +AddTrust External Root +====================== +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD +VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw +NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU +cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg +Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 ++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw +Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo +aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy +2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 +7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL +VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk +VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl +j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 +e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u +G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +AddTrust Public Services Root +============================= +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU +cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ +BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l +dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu +nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i +d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG +Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw +HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G +A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G +A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 +JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL ++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 +Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H +EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- + +AddTrust Qualified Certificates Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU +cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx +CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ +IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx +64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 +KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o +L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR +wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU +MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE +BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y +azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG +GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze +RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB +iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +RSA Security 2048 v3 +==================== +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK +ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy +MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb +BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 +Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb +WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH +KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP ++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E +FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY +v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj +0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj +VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 +nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA +pKnXwiJPZ9d37CAFYd4= +-----END CERTIFICATE----- + +GeoTrust Global CA +================== +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw +MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo +BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet +8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc +T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU +vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q +zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 +d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 +mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p +XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm +Mw== +-----END CERTIFICATE----- + +GeoTrust Global CA 2 +==================== +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw +MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ +NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k +LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA +Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b +HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH +K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 +srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh +ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL +OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC +x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF +H4z1Ir+rzoPz4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +GeoTrust Universal CA +===================== +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 +MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu +Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t +JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e +RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs +7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d +8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V +qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga +Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB +Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu +KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 +ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 +XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB +hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 +qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL +oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK +xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF +KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 +DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK +xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU +p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI +P/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +GeoTrust Universal CA 2 +======================= +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 +MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg +SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 +DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 +j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q +JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a +QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 +WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP +20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn +ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC +SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG +8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 ++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E +BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ +4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ +mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq +A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg +Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP +pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d +FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp +gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm +X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +America Online Root Certification Authority 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG +v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z +DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh +sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP +8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z +o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf +GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF +VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft +3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g +Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds +sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- + +America Online Root Certification Authority 2 +============================================= +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en +fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 +f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO +qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN +RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 +gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn +6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid +FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 +Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj +B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op +aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY +T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p ++DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg +JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy +zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO +ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh +1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf +GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff +Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP +cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= +-----END CERTIFICATE----- + +Visa eCommerce Root +=================== +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG +EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug +QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 +WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm +VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL +F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b +RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 +TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI +/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs +GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc +CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW +YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz +zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu +YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- + +Certum Root CA +============== +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK +ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla +Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u +by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x +wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL +kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ +89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K +Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P +NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ +GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg +GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ +0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS +qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +Comodo Secure Services root +=========================== +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw +MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu +Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi +BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP +9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc +rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC +oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V +p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E +FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj +YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm +aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm +4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL +DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw +pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H +RR3B7Hzs/Sk= +-----END CERTIFICATE----- + +Comodo Trusted Services root +============================ +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw +MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h +bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw +IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 +3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y +/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 +juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS +ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud +DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp +ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl +cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw +uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA +BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l +R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O +9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- + +QuoVadis Root CA +================ +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE +ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz +MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp +cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD +EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk +J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL +F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL +YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen +AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w +PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y +ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 +MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj +YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs +ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW +Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu +BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw +FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 +tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo +fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul +LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x +gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi +5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi +5nrQNiOKSnQ2+Q== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx +ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 +XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk +lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB +lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy +lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt +66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn +wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh +D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy +BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie +J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud +DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU +a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv +Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 +UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm +VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK ++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW +IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 +WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X +f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II +4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 +VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx +OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg +DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij +KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K +DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv +BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp +p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 +nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX +MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM +Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz +uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT +BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB +BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 +ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE +AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV +qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s +hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z +POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 +Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp +8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC +bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu +g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p +vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr +qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +Security Communication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw +8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM +DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX +5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd +DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 +JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g +0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a +mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ +s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ +6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- + +Sonera Class 2 Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG +U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw +NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh +IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 +/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT +dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG +f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P +tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH +nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT +XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt +0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI +cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph +Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx +EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH +llpwrN9M +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA +============================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE +ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w +HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh +bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt +vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P +jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca +C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth +vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 +22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV +HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v +dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN +BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR +EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw +MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y +nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR +iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- + +TDC Internet Root CA +==================== +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE +ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx +NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu +ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j +xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL +znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc +5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6 +otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI +AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM +VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM +MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC +AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe +UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G +CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m +gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ +2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb +O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU +Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l +-----END CERTIFICATE----- + +UTN DATACorp SGC Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ +BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa +MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w +HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy +dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys +raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo +wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA +9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv +33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud +DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 +BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD +LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 +DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 +I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx +EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP +DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- + +UTN USERFirst Hardware Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd +BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx +OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 +eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz +ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI +wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd +tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 +i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf +Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw +gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF +lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF +UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF +BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW +XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 +lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn +iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 +nfhmqA== +-----END CERTIFICATE----- + +Camerfirma Chambers of Commerce Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx +NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp +cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn +MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU +xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH +NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW +DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV +d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud +EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v +cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P +AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh +bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD +VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi +fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD +L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN +UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n +ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 +erfutGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- + +Camerfirma Global Chambersign Root +================================== +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx +NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt +YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg +MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw +ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J +1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O +by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl +6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c +8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ +BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j +aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B +Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj +aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y +ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA +PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y +gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ +PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 +IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes +t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- + +NetLock Notary (Class A) Root +============================= +-----BEGIN CERTIFICATE----- +MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI +EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j +ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX +DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH +EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD +VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz +cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM +D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ +z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC +/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 +tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 +4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG +A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC +Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv +bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu +IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn +LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 +ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz +IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh +IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu +b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh +bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg +Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp +bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 +ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP +ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB +CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr +KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM +8CgHrTwXZoi1/baI +-----END CERTIFICATE----- + +NetLock Business (Class B) Root +=============================== +-----BEGIN CERTIFICATE----- +MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg +VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD +VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv +bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg +VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S +o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr +1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV +HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ +RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh +dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 +ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv +c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg +YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh +c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz +Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA +bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl +IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 +YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj +cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM +43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR +stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI +-----END CERTIFICATE----- + +NetLock Express (Class C) Root +============================== +-----BEGIN CERTIFICATE----- +MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD +KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ +BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j +ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z +W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 +euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw +DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN +RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn +YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB +IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i +aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 +ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs +ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo +dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y +emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k +IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ +UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg +YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 +xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW +gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj +YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH +AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw +Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg +U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 +LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh +cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT +dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC +AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh +3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm +vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk +fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 +fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ +EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl +1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ +lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro +g14= +-----END CERTIFICATE----- + +Taiwan GRCA +=========== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG +EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X +DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv +dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN +w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 +BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O +1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO +htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov +J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 +Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t +B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB +O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 +lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV +HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 +09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj +Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 +Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU +D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz +DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk +Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk +7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ +CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy ++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS +-----END CERTIFICATE----- + +Swisscom Root CA 1 +================== +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG +EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy +dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 +MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln +aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM +MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF +NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe +AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC +b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn +7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN +cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp +WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 +haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY +MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw +HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j +BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 +MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn +jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ +MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H +VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl +vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl +OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 +1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq +nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy +x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW +NY6E0F/6MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +Certplus Class 2 Primary CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE +BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN +OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy +dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR +5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ +Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO +YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e +e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME +CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ +YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t +L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD +P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R +TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ +7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW +//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- + +DST Root CA X3 +============== +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK +ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X +DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 +cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT +rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 +UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy +xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d +utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ +MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug +dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE +GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw +RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS +fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +DST ACES CA X6 +============== +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT +MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha +MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE +CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI +DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa +pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow +GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy +MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu +Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy +dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU +CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 +5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t +Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs +vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 +oKfN5XozNmr6mis= +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 1 +============================================== +-----BEGIN CERTIFICATE----- +MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP +MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 +acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx +MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg +U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB +TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC +aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX +yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i +Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ +8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 +W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME +BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 +sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE +q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy +B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY +nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2 +============================================== +-----BEGIN CERTIFICATE----- +MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN +MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr +dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G +A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls +acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe +LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI +x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g +QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr +5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB +AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt +Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 +Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ +hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P +9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 +UrbnBEI= +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X +DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 +aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 +N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm ++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH +6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu +MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h +qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 +FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs +ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc +celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X +CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB +tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P +4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F +kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L +3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx +/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa +DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP +e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu +WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ +DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub +DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ +cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN +b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 +nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge +RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt +tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI +hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K +Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN +NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa +Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG +1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +thawte Primary Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 +MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg +SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv +KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT +FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs +oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ +1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc +q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K +aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p +afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF +AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE +uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 +jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH +z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G5 +============================================================ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh +dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz +j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD +Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r +fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv +Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG +SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ +X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE +KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC +Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE +ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +======================================= +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG +EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr +IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx +MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx +jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT +aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT +crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc +/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB +AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv +bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA +A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q +4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ +GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD +ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +WellsSecure Public Root Certificate Authority +============================================= +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM +F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw +NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl +bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD +VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 +iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 +i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 +bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB +K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB +AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu +cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm +lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB +i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww +GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI +K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 +bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj +qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es +E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ +tylv2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +IGC/A +===== +-----BEGIN CERTIFICATE----- +MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD +VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE +Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy +MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI +EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT +STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 +TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW +So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy +HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd +frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ +tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB +egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC +iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK +q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q +MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg +Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI +lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF +0mBWWg== +-----END CERTIFICATE----- + +Security Communication EV RootCA1 +================================= +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE +BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl +Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO +/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX +WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z +ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 +bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK +9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm +iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG +Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW +mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW +T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GA CA +=============================== +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE +BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG +A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH +bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD +VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw +IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 +IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 +Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg +Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD +d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ +/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R +LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm +MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 ++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY +okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE +BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL +EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 +MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz +dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT +GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG +d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N +oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc +QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ +PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb +MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG +IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD +VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 +LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A +dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn +AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA +4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg +AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA +egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 +Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO +PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv +c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h +cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw +IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT +WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV +MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER +MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp +Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal +HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT +nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE +aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a +86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK +yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB +S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. +====================================== +-----BEGIN CERTIFICATE----- +MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT +AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg +LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w +HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+ +U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh +IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN +yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU +2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3 +4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP +2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm +8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf +HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa +Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK +5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b +czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g +ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF +BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug +cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf +AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX +EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v +/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3 +MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4 +3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk +eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f +/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h +RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU +Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 2 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw +MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw +IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 +xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ +Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u +SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G +dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ +KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj +TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP +JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk +vQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 3 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw +MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W +yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo +6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ +uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk +2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE +O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 +yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 +IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal +092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc +5A== +-----END CERTIFICATE----- + +TC TrustCenter Universal CA I +============================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN +MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg +VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw +JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC +qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv +xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw +ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O +gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j +BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG +1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy +vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 +ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT +ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a +7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY +-----END CERTIFICATE----- + +Deutsche Telekom Root CA 2 +========================== +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT +RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG +A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 +MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G +A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS +b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 +bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI +KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY +AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK +Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV +jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV +HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr +E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy +zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 +rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G +dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +ComSign Secured CA +================== +-----BEGIN CERTIFICATE----- +MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE +AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w +NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD +QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs +49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH +7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB +kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 +9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw +AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t +U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA +j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC +AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a +BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp +FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP +51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz +OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== +-----END CERTIFICATE----- + +Cybertrust Global Root +====================== +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li +ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 +MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD +ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW +0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL +AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin +89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT +8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 +MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G +A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO +lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi +5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 +hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T +X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 +============================================================================================================================= +-----BEGIN CERTIFICATE----- +MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH +DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q +aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry +b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV +BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg +S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 +MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl +IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF +n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl +IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft +dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl +cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO +Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 +xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR +6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL +hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd +BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 +N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT +y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh +LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M +dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= +-----END CERTIFICATE----- + +Buypass Class 2 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 +MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M +cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 +0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 +0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R +uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV +1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt +7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 +fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w +wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho +-----END CERTIFICATE----- + +Buypass Class 3 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 +MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx +ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 +n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia +AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c +1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 +pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA +EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 +htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj +el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 +-----END CERTIFICATE----- + +EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 +========================================================================== +-----BEGIN CERTIFICATE----- +MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg +QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe +Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p +ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt +IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by +X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b +gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr +eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ +TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy +Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn +uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI +qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm +ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0 +Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW +Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t +FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm +zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k +XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT +bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU +RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK +1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt +2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ +Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9 +AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +CNNIC ROOT +========== +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE +ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw +OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD +o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz +VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT +VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or +czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK +y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC +wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S +lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 +Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM +O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 +BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 +G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m +mxE= +-----END CERTIFICATE----- + +ApplicationCA - Japanese Government +=================================== +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT +SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw +MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl +cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 +fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN +wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE +jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu +nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU +WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV +BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD +vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs +o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g +/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD +io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW +dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL +rosot4LKGAfmt1t06SAZf7IbiVQ= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G3 +============================================= +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz +NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo +YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT +LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j +K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE +c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C +IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu +dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr +2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 +cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE +Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s +t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +thawte Primary Root CA - G2 +=========================== +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC +VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu +IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg +Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV +MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG +b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt +IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS +LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 +8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU +mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN +G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K +rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +thawte Primary Root CA - G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w +ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD +VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG +A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At +P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC ++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY +7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW +vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ +KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK +A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC +8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm +er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G2 +============================================= +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 +OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl +b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG +BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc +KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ +EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m +ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 +npaqBA+K +-----END CERTIFICATE----- + +VeriSign Universal Root Certification Authority +=============================================== +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj +1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP +MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 +9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I +AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR +tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G +CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O +a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 +Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx +Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx +P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P +wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 +mJO37M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G4 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC +VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 +b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz +ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo +b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 +Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz +rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw +HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u +Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD +A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx +AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +============================================ +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G2 +================================== +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC +TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l +ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ +5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn +vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj +CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil +e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR +OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI +CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 +48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi +trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 +qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB +AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC +ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA +A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz ++51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj +f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN +kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk +CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF +URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb +CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h +oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV +IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm +66+KAQ== +-----END CERTIFICATE----- + +CA Disig +======== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK +QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw +MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz +bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm +GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD +Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo +hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt +ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w +gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P +AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz +aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff +ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa +BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t +WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 +mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ +CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K +ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA +4Z7CRneC9VkGjCFMhwnN5ag= +-----END CERTIFICATE----- + +Juur-SK +======= +-----BEGIN CERTIFICATE----- +MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA +c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw +DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG +SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy +aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf +TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC ++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw +UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa +Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF +MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD +HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh +AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA +cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr +AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw +cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE +FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G +A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo +ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL +abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 +IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh +Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 +yyqcjg== +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +======================= +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT +DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx +NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n +IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 +ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr +auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh +qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY +V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV +HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i +h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio +l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei +IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps +T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT +c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +ACEDICOM Root +============= +-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD +T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4 +MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG +A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk +WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD +YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew +MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb +m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk +HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT +xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2 +3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9 +2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq +TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz +4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU +9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv +bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg +aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP +eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk +zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1 +ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI +KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq +nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE +I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp +MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o +tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky +CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX +bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/ +D/xwzoiQ +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi +=================================================== +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz +ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 +MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 +cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u +aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY +8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y +jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI +JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk +9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG +SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d +F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq +D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 +Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq +fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud +EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH +DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA +bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx +ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx +51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk +R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP +T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f +Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl +osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR +crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR +saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD +KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi +6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG +EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz +MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu +QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ +03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK +ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU ++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC +PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT +OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK +F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK +0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ +0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB +leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID +AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ +SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG +NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l +Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga +kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q +hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs +g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 +aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 +nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC +ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo +Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z +WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Chambers of Commerce Root - 2008 +================================ +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy +Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl +ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF +EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl +cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA +XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj +h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ +ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk +NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g +D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 +lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ +0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 +EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI +G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ +BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh +bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh +bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC +CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH +AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 +wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH +3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU +RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 +M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 +YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF +9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK +zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG +nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ +-----END CERTIFICATE----- + +Global Chambersign Root - 2008 +============================== +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx +NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg +Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ +QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf +VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf +XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 +ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB +/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA +TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M +H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe +Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF +HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB +AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT +BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE +BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm +aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm +aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp +1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 +dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG +/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 +ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s +dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg +9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH +foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du +qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr +P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq +c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +Certinomis - Autorité Racine +============================= +-----BEGIN CERTIFICATE----- +MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK +Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg +LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG +A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw +JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa +wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly +Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw +2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N +jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q +c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC +lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb +xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g +530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna +4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ +KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x +WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva +R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 +nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B +CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv +JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE +qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b +WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE +wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ +vgt2Fl43N+bYdJeimUV5 +-----END CERTIFICATE----- + +Root CA Generalitat Valenciana +============================== +-----BEGIN CERTIFICATE----- +MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE +ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 +IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 +WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE +CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 +F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B +ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ +D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte +JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB +AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n +dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB +ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl +AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA +YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy +AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA +aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt +AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA +YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu +AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA +OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 +dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV +BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G +A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S +b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh +TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz +Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 +NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH +iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt ++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= +-----END CERTIFICATE----- + +A-Trust-nQual-03 +================ +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE +Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy +a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R +dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw +RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 +ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 +c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA +zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n +yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE +SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 +iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V +cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV +eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 +ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr +sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd +JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS +mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 +ahq97BvIxYSazQ== +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +====== +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE +BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w +ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD +VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE +CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT +BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 +MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt +SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl +Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh +cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK +w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT +ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 +HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a +E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw +0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD +VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 +Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l +dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ +lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa +Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe +l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 +E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D +5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +======================================================= +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT +O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y +aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT +AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo +IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI +1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa +71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u +8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH +3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ +MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 +MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu +b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt +XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD +/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N +7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Trustis FPS Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 +IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV +BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ +RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk +H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa +cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt +o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA +AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd +BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c +GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC +yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P +8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV +l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl +iB6XzCGcKQENZetX2fNXlrtIzYE= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ +Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 +dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu +c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv +bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 +aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t +L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG +cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 +fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm +N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN +Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T +tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX +e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA +2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs +HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE +JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib +D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= +-----END CERTIFICATE----- + +StartCom Certification Authority G2 +=================================== +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE +ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O +o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG +4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi +Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul +Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs +O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H +vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L +nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS +FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa +z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ +KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K +2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk +J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ +JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG +/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc +nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld +blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc +l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm +7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm +obp573PYtlNXLfbQ4ddI +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +EE Certification Centre Root CA +=============================== +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy +dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw +MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB +UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy +ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM +TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 +rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw +93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN +P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ +MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF +BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj +xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM +lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU +3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM +dcGWxZ0= +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2007 +================================================= +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X +DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl +a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN +BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp +bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N +YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv +KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya +KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT +rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC +AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s +Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I +aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO +Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb +BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK +poRq0Tl9 +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +PSCProcert +========== +-----BEGIN CERTIFICATE----- +MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk +ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ +MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz +dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl +cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw +IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw +MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w +DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD +ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp +Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC +wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA +3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh +RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO +EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2 +0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH +0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU +td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw +Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp +r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/ +AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz +Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId +xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp +ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH +EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h +Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k +ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG +9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG +MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG +LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52 +ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy +YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v +Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o +dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq +T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN +g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q +uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1 +n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn +FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo +5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq +3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5 +poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y +eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km +-----END CERTIFICATE----- + +China Internet Network Information Center EV Certificates Root +============================================================== +-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D +aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg +Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG +A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM +PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl +cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y +jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV +98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H +klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23 +KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC +7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD +glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5 +0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM +7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws +ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0 +5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8= +-----END CERTIFICATE----- + +Swisscom Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG +EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy +dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2 +MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln +aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM +LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo +ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ +wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH +Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a +SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS +NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab +mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY +Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3 +qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw +HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O +BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu +MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO +v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ +82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz +o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs +a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx +OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW +mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o ++sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC +rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX +5OfNeOI5wSsSnqaeG8XmDtkx2Q== +-----END CERTIFICATE----- + +Swisscom Root EV CA 2 +===================== +-----BEGIN CERTIFICATE----- +MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE +BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl +cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN +MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT +HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg +Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz +o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy +Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti +GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li +qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH +Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG +alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa +m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox +bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi +xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED +MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB +bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL +j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU +wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7 +XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH +59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/ +23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq +J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA +HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi +uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW +l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc= +-----END CERTIFICATE----- + +CA Disig Root R1 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy +3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8 +u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2 +m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk +CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa +YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6 +vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL +LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX +ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is +XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ +04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR +xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B +LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM +CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb +VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85 +YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS +ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix +lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N +UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ +a7+h89n07eLw4+1knj0vllJPgFOL +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +====================== +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE +CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 +MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW +VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ +6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA +3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k +B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn +Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH +oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 +F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ +oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 +gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc +TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB +AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW +DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm +zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW +pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV +G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc +c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT +JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 +qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 +Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems +WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +E-Tugra Certification Authority +=============================== +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w +DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls +ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw +NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx +QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl +cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD +DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd +hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K +CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g +ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ +BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 +E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz +rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq +jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 +dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB +/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG +MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK +kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO +XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 +VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo +a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc +dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV +KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT +Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 +8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G +C7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx +MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ +SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F +vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 +2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV +WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy +YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 +r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf +vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR +3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +===================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU +cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 +MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG +A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV +hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr +54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ +DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 +HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR +z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R +l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ +bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h +k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh +TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 +61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G +3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- diff --git a/common/icon.png b/common/icon.png new file mode 100644 index 000000000..fdee900aa Binary files /dev/null and b/common/icon.png differ diff --git a/configure b/configure new file mode 100755 index 000000000..6fbaa9f7f --- /dev/null +++ b/configure @@ -0,0 +1,103 @@ +#!/usr/bin/env bash + +set -euo pipefail + +CONFIG_FILE=$1 + +if [ -z ${CONFIG_FILE} ]; then + abort 'You need to specify an output path for the configuration file' +fi + +# Make sure we clear all colors +trap '>&2 echo -en "\033[0m"' TERM INT + +function abort { >&2 echo -e "\033[1m\033[31m$1\033[0m"; exit 1; } +function info { >&2 echo -e "\033[1m\033[33m$1\033[0m"; } +function warn { >&2 echo -e "\033[1m\033[33m$1\033[0m"; } + +# Install mason +export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason" + +# You can override the function for a particular set of flags by defining a +# print_XXX_flags function in your dependencies.sh file +function print_flags { + local NAME=$1; shift + if [ "$(type -t print_${NAME}_flags)" = 'function' ]; then + print_${NAME}_flags + else + local VERSION=`echo "${NAME}_VERSION" | tr "[:lower:]" "[:upper:]"` + if [ ! -z ${!VERSION:-} ] ; then + mason install ${NAME} ${!VERSION} + for FLAGS in "$@" ; do + CONFIG+=" '${NAME}_${FLAGS}%': $(quote_flags $(mason ${FLAGS} ${NAME} ${!VERSION})),"$LN + done + else + warn "* Not using ${NAME}" + fi + fi +} + +function print_default_flags { + : +} + +function print_opengl_flags { + CONFIG+=" 'opengl_cflags%': [],"$LN + CONFIG+=" 'opengl_ldflags%': [],"$LN +} + +# Load dependencies +source scripts/${MASON_PLATFORM}/configure.sh +if [ -e scripts/${MASON_PLATFORM}/${MASON_PLATFORM_VERSION}/configure.sh ]; then + source scripts/${MASON_PLATFORM}/${MASON_PLATFORM_VERSION}/configure.sh +fi + +PYTHON=`which python || abort 'Cannot find python'` + +>&2 echo -en "\033[1m\033[32m* Using " +>&2 ${PYTHON} --version +>&2 echo -en "\033[0m"; + +function quote_flags { + ${PYTHON} -c "import sys, re; print filter(None, re.split('(? ${CONFIG_FILE} +cat ${CONFIG_FILE} diff --git a/deps/gtest/gtest-all.cc b/deps/gtest/gtest-all.cc new file mode 100644 index 000000000..a9a03b2e3 --- /dev/null +++ b/deps/gtest/gtest-all.cc @@ -0,0 +1,9592 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// Google C++ Testing Framework (Google Test) +// +// Sometimes it's desirable to build Google Test by compiling a single file. +// This file serves this purpose. + +// This line ensures that gtest.h can be compiled on its own, even +// when it's fused. +#include "gtest/gtest.h" + +// The following lines pull in the real gtest *.cc files. +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) + +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Utilities for testing Google Test itself and code that uses Google Test +// (e.g. frameworks built on top of Google Test). + +#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + + +namespace testing { + +// This helper class can be used to mock out Google Test failure reporting +// so that we can test Google Test or code that builds on Google Test. +// +// An object of this class appends a TestPartResult object to the +// TestPartResultArray object given in the constructor whenever a Google Test +// failure is reported. It can either intercept only failures that are +// generated in the same thread that created this object or it can intercept +// all generated failures. The scope of this mock object can be controlled with +// the second argument to the two arguments constructor. +class GTEST_API_ ScopedFakeTestPartResultReporter + : public TestPartResultReporterInterface { + public: + // The two possible mocking modes of this object. + enum InterceptMode { + INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. + INTERCEPT_ALL_THREADS // Intercepts all failures. + }; + + // The c'tor sets this object as the test part result reporter used + // by Google Test. The 'result' parameter specifies where to report the + // results. This reporter will only catch failures generated in the current + // thread. DEPRECATED + explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); + + // Same as above, but you can choose the interception scope of this object. + ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, + TestPartResultArray* result); + + // The d'tor restores the previous test part result reporter. + virtual ~ScopedFakeTestPartResultReporter(); + + // Appends the TestPartResult object to the TestPartResultArray + // received in the constructor. + // + // This method is from the TestPartResultReporterInterface + // interface. + virtual void ReportTestPartResult(const TestPartResult& result); + private: + void Init(); + + const InterceptMode intercept_mode_; + TestPartResultReporterInterface* old_reporter_; + TestPartResultArray* const result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); +}; + +namespace internal { + +// A helper class for implementing EXPECT_FATAL_FAILURE() and +// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +class GTEST_API_ SingleFailureChecker { + public: + // The constructor remembers the arguments. + SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr); + ~SingleFailureChecker(); + private: + const TestPartResultArray* const results_; + const TestPartResult::Type type_; + const string substr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); +}; + +} // namespace internal + +} // namespace testing + +// A set of macros for testing Google Test assertions or code that's expected +// to generate Google Test fatal failures. It verifies that the given +// statement will cause exactly one fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_FATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - 'statement' cannot reference local non-static variables or +// non-static members of the current object. +// - 'statement' cannot return a value. +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. The AcceptsMacroThatExpandsToUnprotectedComma test in +// gtest_unittest.cc will fail to compile if we do that. +#define EXPECT_FATAL_FAILURE(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ALL_THREADS, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +// A macro for testing Google Test assertions or code that's expected to +// generate Google Test non-fatal failures. It asserts that the given +// statement will cause exactly one non-fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// 'statement' is allowed to reference local variables and members of +// the current object. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. If we do that, the code won't compile when the user gives +// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that +// expands to code containing an unprotected comma. The +// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc +// catches that. +// +// For the same reason, we have to write +// if (::testing::internal::AlwaysTrue()) { statement; } +// instead of +// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) +// to avoid an MSVC warning on unreachable code. +#define EXPECT_NONFATAL_FAILURE(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ + >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include // NOLINT +#include +#include + +#if GTEST_OS_LINUX + +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +# include // NOLINT +# include // NOLINT +# include // NOLINT +// Declares vsnprintf(). This header is not available on Windows. +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include + +#elif GTEST_OS_SYMBIAN +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +#elif GTEST_OS_ZOS +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +// On z/OS we additionally need strings.h for strcasecmp. +# include // NOLINT + +#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. + +# include // NOLINT + +#elif GTEST_OS_WINDOWS // We are on Windows proper. + +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT + +# if GTEST_OS_WINDOWS_MINGW +// MinGW has gettimeofday() but not _ftime64(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +// TODO(kenton@google.com): There are other ways to get the time on +// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW +// supports these. consider using them instead. +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT +# endif // GTEST_OS_WINDOWS_MINGW + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT + +#else + +// Assume other platforms have gettimeofday(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT +# include // NOLINT + +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +#endif + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility functions and classes used by the Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This file contains purely Google Test's internal implementation. Please +// DO NOT #INCLUDE IT IN A USER PROGRAM. + +#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ +#define GTEST_SRC_GTEST_INTERNAL_INL_H_ + +// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is +// part of Google Test's implementation; otherwise it's undefined. +#if !GTEST_IMPLEMENTATION_ +// A user is trying to include this from his code - just say no. +# error "gtest-internal-inl.h is part of Google Test's internal implementation." +# error "It must not be included except by Google Test itself." +#endif // GTEST_IMPLEMENTATION_ + +#ifndef _WIN32_WCE +# include +#endif // !_WIN32_WCE +#include +#include // For strtoll/_strtoul64/malloc/free. +#include // For memmove. + +#include +#include +#include + + +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +#endif + +#if GTEST_OS_WINDOWS +# include // NOLINT +#endif // GTEST_OS_WINDOWS + + +namespace testing { + +// Declares the flags. +// +// We don't want the users to modify this flag in the code, but want +// Google Test's own unit tests to be able to access it. Therefore we +// declare it here as opposed to in gtest.h. +GTEST_DECLARE_bool_(death_test_use_fork); + +namespace internal { + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; + +// Names of the flags (needed for parsing Google Test flags). +const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; +const char kBreakOnFailureFlag[] = "break_on_failure"; +const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kColorFlag[] = "color"; +const char kFilterFlag[] = "filter"; +const char kListTestsFlag[] = "list_tests"; +const char kOutputFlag[] = "output"; +const char kPrintTimeFlag[] = "print_time"; +const char kRandomSeedFlag[] = "random_seed"; +const char kRepeatFlag[] = "repeat"; +const char kShuffleFlag[] = "shuffle"; +const char kStackTraceDepthFlag[] = "stack_trace_depth"; +const char kStreamResultToFlag[] = "stream_result_to"; +const char kThrowOnFailureFlag[] = "throw_on_failure"; + +// A valid random seed must be in [1, kMaxRandomSeed]. +const int kMaxRandomSeed = 99999; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +GTEST_API_ extern bool g_help_flag; + +// Returns the current time in milliseconds. +GTEST_API_ TimeInMillis GetTimeInMillis(); + +// Returns true iff Google Test should use colors in the output. +GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); + +// Formats the given time in milliseconds as seconds. +GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); + +// Converts the given time in milliseconds to a date string in the ISO 8601 +// format, without the timezone information. N.B.: due to the use the +// non-reentrant localtime() function, this function is not thread safe. Do +// not use it in any code that can be called from multiple threads. +GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); + +// Parses a string for an Int32 flag, in the form of "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +GTEST_API_ bool ParseInt32Flag( + const char* str, const char* flag, Int32* value); + +// Returns a random seed in range [1, kMaxRandomSeed] based on the +// given --gtest_random_seed flag value. +inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { + const unsigned int raw_seed = (random_seed_flag == 0) ? + static_cast(GetTimeInMillis()) : + static_cast(random_seed_flag); + + // Normalizes the actual seed to range [1, kMaxRandomSeed] such that + // it's easy to type. + const int normalized_seed = + static_cast((raw_seed - 1U) % + static_cast(kMaxRandomSeed)) + 1; + return normalized_seed; +} + +// Returns the first valid random seed after 'seed'. The behavior is +// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is +// considered to be 1. +inline int GetNextRandomSeed(int seed) { + GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) + << "Invalid random seed " << seed << " - must be in [1, " + << kMaxRandomSeed << "]."; + const int next_seed = seed + 1; + return (next_seed > kMaxRandomSeed) ? 1 : next_seed; +} + +// This class saves the values of all Google Test flags in its c'tor, and +// restores them in its d'tor. +class GTestFlagSaver { + public: + // The c'tor. + GTestFlagSaver() { + also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); + break_on_failure_ = GTEST_FLAG(break_on_failure); + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + color_ = GTEST_FLAG(color); + death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); + filter_ = GTEST_FLAG(filter); + internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); + list_tests_ = GTEST_FLAG(list_tests); + output_ = GTEST_FLAG(output); + print_time_ = GTEST_FLAG(print_time); + random_seed_ = GTEST_FLAG(random_seed); + repeat_ = GTEST_FLAG(repeat); + shuffle_ = GTEST_FLAG(shuffle); + stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); + stream_result_to_ = GTEST_FLAG(stream_result_to); + throw_on_failure_ = GTEST_FLAG(throw_on_failure); + } + + // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. + ~GTestFlagSaver() { + GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; + GTEST_FLAG(break_on_failure) = break_on_failure_; + GTEST_FLAG(catch_exceptions) = catch_exceptions_; + GTEST_FLAG(color) = color_; + GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; + GTEST_FLAG(filter) = filter_; + GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; + GTEST_FLAG(list_tests) = list_tests_; + GTEST_FLAG(output) = output_; + GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(random_seed) = random_seed_; + GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(shuffle) = shuffle_; + GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; + GTEST_FLAG(stream_result_to) = stream_result_to_; + GTEST_FLAG(throw_on_failure) = throw_on_failure_; + } + + private: + // Fields for saving the original values of flags. + bool also_run_disabled_tests_; + bool break_on_failure_; + bool catch_exceptions_; + std::string color_; + std::string death_test_style_; + bool death_test_use_fork_; + std::string filter_; + std::string internal_run_death_test_; + bool list_tests_; + std::string output_; + bool print_time_; + internal::Int32 random_seed_; + internal::Int32 repeat_; + bool shuffle_; + internal::Int32 stack_trace_depth_; + std::string stream_result_to_; + bool throw_on_failure_; +} GTEST_ATTRIBUTE_UNUSED_; + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted +// to "(Invalid Unicode 0xXXXXXXXX)". +GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded(); + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (e.g., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +GTEST_API_ bool ShouldShard(const char* total_shards_str, + const char* shard_index_str, + bool in_subprocess_for_death_test); + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error and +// and aborts. +GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +GTEST_API_ bool ShouldRunTestOnShard( + int total_shards, int shard_index, int test_id); + +// STL container utilities. + +// Returns the number of elements in the given container that satisfy +// the given predicate. +template +inline int CountIf(const Container& c, Predicate predicate) { + // Implemented as an explicit loop since std::count_if() in libCstd on + // Solaris has a non-standard signature. + int count = 0; + for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { + if (predicate(*it)) + ++count; + } + return count; +} + +// Applies a function/functor to each element in the container. +template +void ForEach(const Container& c, Functor functor) { + std::for_each(c.begin(), c.end(), functor); +} + +// Returns the i-th element of the vector, or default_value if i is not +// in range [0, v.size()). +template +inline E GetElementOr(const std::vector& v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; +} + +// Performs an in-place shuffle of a range of the vector's elements. +// 'begin' and 'end' are element indices as an STL-style range; +// i.e. [begin, end) are shuffled, where 'end' == size() means to +// shuffle to the end of the vector. +template +void ShuffleRange(internal::Random* random, int begin, int end, + std::vector* v) { + const int size = static_cast(v->size()); + GTEST_CHECK_(0 <= begin && begin <= size) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size << "]."; + GTEST_CHECK_(begin <= end && end <= size) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = begin + random->Generate(range_width); + std::swap((*v)[selected], (*v)[last_in_range]); + } +} + +// Performs an in-place shuffle of the vector's elements. +template +inline void Shuffle(internal::Random* random, std::vector* v) { + ShuffleRange(random, 0, static_cast(v->size()), v); +} + +// A function for deleting an object. Handy for being used as a +// functor. +template +static void Delete(T* x) { + delete x; +} + +// A predicate that checks the key of a TestProperty against a known key. +// +// TestPropertyKeyIs is copyable. +class TestPropertyKeyIs { + public: + // Constructor. + // + // TestPropertyKeyIs has NO default constructor. + explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} + + // Returns true iff the test name of test property matches on key_. + bool operator()(const TestProperty& test_property) const { + return test_property.key() == key_; + } + + private: + std::string key_; +}; + +// Class UnitTestOptions. +// +// This class contains functions for processing options the user +// specifies when running the tests. It has only static members. +// +// In most cases, the user can specify an option using either an +// environment variable or a command line flag. E.g. you can set the +// test filter using either GTEST_FILTER or --gtest_filter. If both +// the variable and the flag are present, the latter overrides the +// former. +class GTEST_API_ UnitTestOptions { + public: + // Functions for processing the gtest_output flag. + + // Returns the output format, or "" for normal printed output. + static std::string GetOutputFormat(); + + // Returns the absolute path of the requested output file, or the + // default (test_detail.xml in the original working directory) if + // none was explicitly specified. + static std::string GetAbsolutePathToOutputFile(); + + // Functions for processing the gtest_filter flag. + + // Returns true iff the wildcard pattern matches the string. The + // first ':' or '\0' character in pattern marks the end of it. + // + // This recursive algorithm isn't very efficient, but is clear and + // works well enough for matching test names, which are short. + static bool PatternMatchesString(const char *pattern, const char *str); + + // Returns true iff the user-specified filter matches the test case + // name and the test name. + static bool FilterMatchesTest(const std::string &test_case_name, + const std::string &test_name); + +#if GTEST_OS_WINDOWS + // Function for supporting the gtest_catch_exception flag. + + // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the + // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // This function is useful as an __except condition. + static int GTestShouldProcessSEH(DWORD exception_code); +#endif // GTEST_OS_WINDOWS + + // Returns true if "name" matches the ':' separated list of glob-style + // filters in "filter". + static bool MatchesFilter(const std::string& name, const char* filter); +}; + +// Returns the current application's name, removing directory path if that +// is present. Used by UnitTestOptions::GetOutputFile. +GTEST_API_ FilePath GetCurrentExecutableName(); + +// The role interface for getting the OS stack trace as a string. +class OsStackTraceGetterInterface { + public: + OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface() {} + + // Returns the current OS stack trace as an std::string. Parameters: + // + // max_depth - the maximum number of stack frames to be included + // in the trace. + // skip_count - the number of top frames to be skipped; doesn't count + // against max_depth. + virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; + + // UponLeavingGTest() should be called immediately before Google Test calls + // user code. It saves some information about the current stack that + // CurrentStackTrace() will use to find and hide Google Test stack frames. + virtual void UponLeavingGTest() = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); +}; + +// A working implementation of the OsStackTraceGetterInterface interface. +class OsStackTraceGetter : public OsStackTraceGetterInterface { + public: + OsStackTraceGetter() : caller_frame_(NULL) {} + + virtual string CurrentStackTrace(int max_depth, int skip_count) + GTEST_LOCK_EXCLUDED_(mutex_); + + virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); + + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + + private: + Mutex mutex_; // protects all internal state + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to CurrentStackTrace() from within the user code. + void* caller_frame_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); +}; + +// Information about a Google Test trace point. +struct TraceInfo { + const char* file; + int line; + std::string message; +}; + +// This is the default global test part result reporter used in UnitTestImpl. +// This class should only be used by UnitTestImpl. +class DefaultGlobalTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. Reports the test part + // result in the current test. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); +}; + +// This is the default per thread test part result reporter used in +// UnitTestImpl. This class should only be used by UnitTestImpl. +class DefaultPerThreadTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. The implementation just + // delegates to the current global test part result reporter of *unit_test_. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); +}; + +// The private implementation of the UnitTest class. We don't protect +// the methods under a mutex, as this class is not accessible by a +// user and the UnitTest class that delegates work to this class does +// proper locking. +class GTEST_API_ UnitTestImpl { + public: + explicit UnitTestImpl(UnitTest* parent); + virtual ~UnitTestImpl(); + + // There are two different ways to register your own TestPartResultReporter. + // You can register your own repoter to listen either only for test results + // from the current thread or for results from all threads. + // By default, each per-thread test result repoter just passes a new + // TestPartResult to the global test result reporter, which registers the + // test part result for the currently running test. + + // Returns the global test part result reporter. + TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); + + // Sets the global test part result reporter. + void SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter); + + // Returns the test part result reporter for the current thread. + TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + + // Sets the test part result reporter for the current thread. + void SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter); + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the time of the test program start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const { return !Failed(); } + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const { + return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[i]; + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i) { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[index]; + } + + // Provides access to the event listener list. + TestEventListeners* listeners() { return &listeners_; } + + // Returns the TestResult for the test that's currently running, or + // the TestResult for the ad hoc test if no test is running. + TestResult* current_test_result(); + + // Returns the TestResult for the ad hoc test. + const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } + + // Sets the OS stack trace getter. + // + // Does nothing if the input and the current OS stack trace getter + // are the same; otherwise, deletes the old getter and makes the + // input the current getter. + void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + + // Returns the current OS stack trace getter if it is not NULL; + // otherwise, creates an OsStackTraceGetter, makes it the current + // getter, and returns it. + OsStackTraceGetterInterface* os_stack_trace_getter(); + + // Returns the current OS stack trace as an std::string. + // + // The maximum number of stack frames to be included is specified by + // the gtest_stack_trace_depth flag. The skip_count parameter + // specifies the number of top frames to be skipped, which doesn't + // count against the number of frames to be included. + // + // For example, if Foo() calls Bar(), which in turn calls + // CurrentOsStackTraceExceptTop(1), Foo() will be included in the + // trace but Bar() and CurrentOsStackTraceExceptTop() won't. + std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; + + // Finds and returns a TestCase with the given name. If one doesn't + // exist, creates one and returns it. + // + // Arguments: + // + // test_case_name: name of the test case + // type_param: the name of the test's type parameter, or NULL if + // this is not a typed or a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase* GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Adds a TestInfo to the unit test. + // + // Arguments: + // + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + // test_info: the TestInfo object + void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + TestInfo* test_info) { + // In order to support thread-safe death tests, we need to + // remember the original working directory when the test program + // was first invoked. We cannot do this in RUN_ALL_TESTS(), as + // the user may have changed the current directory before calling + // RUN_ALL_TESTS(). Therefore we capture the current directory in + // AddTestInfo(), which is called to register a TEST or TEST_F + // before main() is reached. + if (original_working_dir_.IsEmpty()) { + original_working_dir_.Set(FilePath::GetCurrentDir()); + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; + } + + GetTestCase(test_info->test_case_name(), + test_info->type_param(), + set_up_tc, + tear_down_tc)->AddTestInfo(test_info); + } + +#if GTEST_HAS_PARAM_TEST + // Returns ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + return parameterized_test_registry_; + } +#endif // GTEST_HAS_PARAM_TEST + + // Sets the TestCase object for the test that's currently running. + void set_current_test_case(TestCase* a_current_test_case) { + current_test_case_ = a_current_test_case; + } + + // Sets the TestInfo object for the test that's currently running. If + // current_test_info is NULL, the assertion results will be stored in + // ad_hoc_test_result_. + void set_current_test_info(TestInfo* a_current_test_info) { + current_test_info_ = a_current_test_info; + } + + // Registers all parameterized tests defined using TEST_P and + // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has guards + // protecting from registering the tests more then once. If + // value-parameterized tests are disabled, RegisterParameterizedTests is + // present but does nothing. + void RegisterParameterizedTests(); + + // Runs all tests in this UnitTest object, prints the result, and + // returns true if all tests are successful. If any exception is + // thrown during a test, this test is considered to be failed, but + // the rest of the tests will still be run. + bool RunAllTests(); + + // Clears the results of all tests, except the ad hoc tests. + void ClearNonAdHocTestResult() { + ForEach(test_cases_, TestCase::ClearTestCaseResult); + } + + // Clears the results of ad-hoc test assertions. + void ClearAdHocTestResult() { + ad_hoc_test_result_.Clear(); + } + + // Adds a TestProperty to the current TestResult object when invoked in a + // context of a test or a test case, or to the global property set. If the + // result already contains a property with the same key, the value will be + // updated. + void RecordProperty(const TestProperty& test_property); + + enum ReactionToSharding { + HONOR_SHARDING_PROTOCOL, + IGNORE_SHARDING_PROTOCOL + }; + + // Matches the full name of each test against the user-specified + // filter to decide whether the test should run, then records the + // result in each TestCase and TestInfo object. + // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests + // based on sharding variables in the environment. + // Returns the number of tests that should run. + int FilterTests(ReactionToSharding shard_tests); + + // Prints the names of the tests matching the user-specified filter flag. + void ListTestsMatchingFilter(); + + const TestCase* current_test_case() const { return current_test_case_; } + TestInfo* current_test_info() { return current_test_info_; } + const TestInfo* current_test_info() const { return current_test_info_; } + + // Returns the vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector& environments() { return environments_; } + + // Getters for the per-thread Google Test trace stack. + std::vector& gtest_trace_stack() { + return *(gtest_trace_stack_.pointer()); + } + const std::vector& gtest_trace_stack() const { + return gtest_trace_stack_.get(); + } + +#if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } + // Returns a pointer to the parsed --gtest_internal_run_death_test + // flag, or NULL if that flag was not specified. + // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. + const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + return internal_run_death_test_flag_.get(); + } + + // Returns a pointer to the current death test factory. + internal::DeathTestFactory* death_test_factory() { + return death_test_factory_.get(); + } + + void SuppressTestEventsIfInSubprocess(); + + friend class ReplaceDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Initializes the event listener for streaming test results to a socket. + // Must not be called before InitGoogleTest. + void ConfigureStreamingOutput(); +#endif + + // Performs initialization dependent upon flag values obtained in + // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to + // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest + // this function is also called from RunAllTests. Since this function can be + // called more than once, it has to be idempotent. + void PostFlagParsingInit(); + + // Gets the random seed used at the start of the current test iteration. + int random_seed() const { return random_seed_; } + + // Gets the random number generator. + internal::Random* random() { return &random_; } + + // Shuffles all test cases, and the tests within each test case, + // making sure that death tests are still run first. + void ShuffleTests(); + + // Restores the test cases and tests to their order before the first shuffle. + void UnshuffleTests(); + + // Returns the value of GTEST_FLAG(catch_exceptions) at the moment + // UnitTest::Run() starts. + bool catch_exceptions() const { return catch_exceptions_; } + + private: + friend class ::testing::UnitTest; + + // Used by UnitTest::Run() to capture the state of + // GTEST_FLAG(catch_exceptions) at the moment it starts. + void set_catch_exceptions(bool value) { catch_exceptions_ = value; } + + // The UnitTest object that owns this implementation object. + UnitTest* const parent_; + + // The working directory when the first TEST() or TEST_F() was + // executed. + internal::FilePath original_working_dir_; + + // The default test part result reporters. + DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; + DefaultPerThreadTestPartResultReporter + default_per_thread_test_part_result_reporter_; + + // Points to (but doesn't own) the global test part result reporter. + TestPartResultReporterInterface* global_test_part_result_repoter_; + + // Protects read and write access to global_test_part_result_reporter_. + internal::Mutex global_test_part_result_reporter_mutex_; + + // Points to (but doesn't own) the per-thread test part result reporter. + internal::ThreadLocal + per_thread_test_part_result_reporter_; + + // The vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector environments_; + + // The vector of TestCases in their original order. It owns the + // elements in the vector. + std::vector test_cases_; + + // Provides a level of indirection for the test case list to allow + // easy shuffling and restoring the test case order. The i-th + // element of this vector is the index of the i-th test case in the + // shuffled order. + std::vector test_case_indices_; + +#if GTEST_HAS_PARAM_TEST + // ParameterizedTestRegistry object used to register value-parameterized + // tests. + internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + + // Indicates whether RegisterParameterizedTests() has been called already. + bool parameterized_tests_registered_; +#endif // GTEST_HAS_PARAM_TEST + + // Index of the last death test case registered. Initially -1. + int last_death_test_case_; + + // This points to the TestCase for the currently running test. It + // changes as Google Test goes through one test case after another. + // When no test is running, this is set to NULL and Google Test + // stores assertion results in ad_hoc_test_result_. Initially NULL. + TestCase* current_test_case_; + + // This points to the TestInfo for the currently running test. It + // changes as Google Test goes through one test after another. When + // no test is running, this is set to NULL and Google Test stores + // assertion results in ad_hoc_test_result_. Initially NULL. + TestInfo* current_test_info_; + + // Normally, a user only writes assertions inside a TEST or TEST_F, + // or inside a function called by a TEST or TEST_F. Since Google + // Test keeps track of which test is current running, it can + // associate such an assertion with the test it belongs to. + // + // If an assertion is encountered when no TEST or TEST_F is running, + // Google Test attributes the assertion result to an imaginary "ad hoc" + // test, and records the result in ad_hoc_test_result_. + TestResult ad_hoc_test_result_; + + // The list of event listeners that can be used to track events inside + // Google Test. + TestEventListeners listeners_; + + // The OS stack trace getter. Will be deleted when the UnitTest + // object is destructed. By default, an OsStackTraceGetter is used, + // but the user can set this field to use a custom getter if that is + // desired. + OsStackTraceGetterInterface* os_stack_trace_getter_; + + // True iff PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + + // The random number seed used at the beginning of the test run. + int random_seed_; + + // Our random number generator. + internal::Random random_; + + // The time of the test program start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp_; + + // How long the test took to run, in milliseconds. + TimeInMillis elapsed_time_; + +#if GTEST_HAS_DEATH_TEST + // The decomposed components of the gtest_internal_run_death_test flag, + // parsed when RUN_ALL_TESTS is called. + internal::scoped_ptr internal_run_death_test_flag_; + internal::scoped_ptr death_test_factory_; +#endif // GTEST_HAS_DEATH_TEST + + // A per-thread stack of traces created by the SCOPED_TRACE() macro. + internal::ThreadLocal > gtest_trace_stack_; + + // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() + // starts. + bool catch_exceptions_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); +}; // class UnitTestImpl + +// Convenience function for accessing the global UnitTest +// implementation object. +inline UnitTestImpl* GetUnitTestImpl() { + return UnitTest::GetInstance()->impl(); +} + +#if GTEST_USES_SIMPLE_RE + +// Internal helper functions for implementing the simple regular +// expression matcher. +GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsAsciiDigit(char ch); +GTEST_API_ bool IsAsciiPunct(char ch); +GTEST_API_ bool IsRepeat(char ch); +GTEST_API_ bool IsAsciiWhiteSpace(char ch); +GTEST_API_ bool IsAsciiWordChar(char ch); +GTEST_API_ bool IsValidEscape(char ch); +GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); +GTEST_API_ bool ValidateRegex(const char* regex); +GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead( + bool escaped, char ch, char repeat, const char* regex, const char* str); +GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); + +#endif // GTEST_USES_SIMPLE_RE + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); + +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +GTEST_API_ std::string GetLastErrnoDescription(); + +# if GTEST_OS_WINDOWS +// Provides leak-safe Windows kernel handle ownership. +class AutoHandle { + public: + AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} + explicit AutoHandle(HANDLE handle) : handle_(handle) {} + + ~AutoHandle() { Reset(); } + + HANDLE Get() const { return handle_; } + void Reset() { Reset(INVALID_HANDLE_VALUE); } + void Reset(HANDLE handle) { + if (handle != handle_) { + if (handle_ != INVALID_HANDLE_VALUE) + ::CloseHandle(handle_); + handle_ = handle; + } + } + + private: + HANDLE handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; +# endif // GTEST_OS_WINDOWS + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !IsDigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. + +# if GTEST_OS_WINDOWS && !defined(__GNUC__) + + // MSVC and C++ Builder define __int64 instead of the standard long long. + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); + +# else + + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); + +# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + + const bool parse_success = *end == '\0' && errno == 0; + + // TODO(vladl@google.com): Convert this to compile time assertion when it is + // available. + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast(parsed); + if (parse_success && static_cast(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + +// TestResult contains some private methods that should be hidden from +// Google Test user but are required for testing. This class allow our tests +// to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class TestResultAccessor { + public: + static void RecordProperty(TestResult* test_result, + const std::string& xml_element, + const TestProperty& property) { + test_result->RecordProperty(xml_element, property); + } + + static void ClearTestPartResults(TestResult* test_result) { + test_result->ClearTestPartResults(); + } + + static const std::vector& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + +#if GTEST_CAN_STREAM_RESULTS_ + +// Streams test results to the given port on the given host machine. +class StreamingListener : public EmptyTestEventListener { + public: + // Abstract base class for writing strings to a socket. + class AbstractSocketWriter { + public: + virtual ~AbstractSocketWriter() {} + + // Sends a string to the socket. + virtual void Send(const string& message) = 0; + + // Closes the socket. + virtual void CloseConnection() {} + + // Sends a string and a newline to the socket. + void SendLn(const string& message) { + Send(message + "\n"); + } + }; + + // Concrete class for actually writing strings to a socket. + class SocketWriter : public AbstractSocketWriter { + public: + SocketWriter(const string& host, const string& port) + : sockfd_(-1), host_name_(host), port_num_(port) { + MakeConnection(); + } + + virtual ~SocketWriter() { + if (sockfd_ != -1) + CloseConnection(); + } + + // Sends a string to the socket. + virtual void Send(const string& message) { + GTEST_CHECK_(sockfd_ != -1) + << "Send() can be called only when there is a connection."; + + const int len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != len) { + GTEST_LOG_(WARNING) + << "stream_result_to: failed to stream to " + << host_name_ << ":" << port_num_; + } + } + + private: + // Creates a client socket and connects to the server. + void MakeConnection(); + + // Closes the socket. + void CloseConnection() { + GTEST_CHECK_(sockfd_ != -1) + << "CloseConnection() can be called only when there is a connection."; + + close(sockfd_); + sockfd_ = -1; + } + + int sockfd_; // socket file descriptor + const string host_name_; + const string port_num_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); + }; // class SocketWriter + + // Escapes '=', '&', '%', and '\n' characters in str as "%xx". + static string UrlEncode(const char* str); + + StreamingListener(const string& host, const string& port) + : socket_writer_(new SocketWriter(host, port)) { Start(); } + + explicit StreamingListener(AbstractSocketWriter* socket_writer) + : socket_writer_(socket_writer) { Start(); } + + void OnTestProgramStart(const UnitTest& /* unit_test */) { + SendLn("event=TestProgramStart"); + } + + void OnTestProgramEnd(const UnitTest& unit_test) { + // Note that Google Test current only report elapsed time for each + // test iteration, not for the entire test program. + SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); + + // Notify the streaming server to stop. + socket_writer_->CloseConnection(); + } + + void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + SendLn("event=TestIterationStart&iteration=" + + StreamableToString(iteration)); + } + + void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + SendLn("event=TestIterationEnd&passed=" + + FormatBool(unit_test.Passed()) + "&elapsed_time=" + + StreamableToString(unit_test.elapsed_time()) + "ms"); + } + + void OnTestCaseStart(const TestCase& test_case) { + SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); + } + + void OnTestCaseEnd(const TestCase& test_case) { + SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + + "ms"); + } + + void OnTestStart(const TestInfo& test_info) { + SendLn(std::string("event=TestStart&name=") + test_info.name()); + } + + void OnTestEnd(const TestInfo& test_info) { + SendLn("event=TestEnd&passed=" + + FormatBool((test_info.result())->Passed()) + + "&elapsed_time=" + + StreamableToString((test_info.result())->elapsed_time()) + "ms"); + } + + void OnTestPartResult(const TestPartResult& test_part_result) { + const char* file_name = test_part_result.file_name(); + if (file_name == NULL) + file_name = ""; + SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + + "&line=" + StreamableToString(test_part_result.line_number()) + + "&message=" + UrlEncode(test_part_result.message())); + } + + private: + // Sends the given message and a newline to the socket. + void SendLn(const string& message) { socket_writer_->SendLn(message); } + + // Called at the start of streaming to notify the receiver what + // protocol we are using. + void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } + + string FormatBool(bool value) { return value ? "1" : "0"; } + + const scoped_ptr socket_writer_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); +}; // class StreamingListener + +#endif // GTEST_CAN_STREAM_RESULTS_ + +} // namespace internal +} // namespace testing + +#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ +#undef GTEST_IMPLEMENTATION_ + +#if GTEST_OS_WINDOWS +# define vsnprintf _vsnprintf +#endif // GTEST_OS_WINDOWS + +namespace testing { + +using internal::CountIf; +using internal::ForEach; +using internal::GetElementOr; +using internal::Shuffle; + +// Constants. + +// A test whose test case name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test case whose name matches this filter is considered a death +// test case and will be run before test cases whose name doesn't +// match this filter. +static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; + +// A test filter that matches everything. +static const char kUniversalFilter[] = "*"; + +// The default output file for XML output. +static const char kDefaultOutputFile[] = "test_detail.xml"; + +// The environment variable name for the test shard index. +static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; +// The environment variable name for the total number of test shards. +static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; +// The environment variable name for the test shard status file. +static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; + +namespace internal { + +// The text used in failure messages to indicate the start of the +// stack trace. +const char kStackTraceMarker[] = "\nStack trace:\n"; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +bool g_help_flag = false; + +} // namespace internal + +static const char* GetDefaultFilter() { + return kUniversalFilter; +} + +GTEST_DEFINE_bool_( + also_run_disabled_tests, + internal::BoolFromGTestEnv("also_run_disabled_tests", false), + "Run disabled tests too, in addition to the tests normally being run."); + +GTEST_DEFINE_bool_( + break_on_failure, + internal::BoolFromGTestEnv("break_on_failure", false), + "True iff a failed assertion should be a debugger break-point."); + +GTEST_DEFINE_bool_( + catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True iff " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); + +GTEST_DEFINE_string_( + color, + internal::StringFromGTestEnv("color", "auto"), + "Whether to use colors in the output. Valid values: yes, no, " + "and auto. 'auto' means to use colors if the output is " + "being sent to a terminal and the TERM environment variable " + "is set to a terminal type that supports colors."); + +GTEST_DEFINE_string_( + filter, + internal::StringFromGTestEnv("filter", GetDefaultFilter()), + "A colon-separated list of glob (not regex) patterns " + "for filtering the tests to run, optionally followed by a " + "'-' and a : separated list of negative patterns (tests to " + "exclude). A test is run if it matches one of the positive " + "patterns and does not match any of the negative patterns."); + +GTEST_DEFINE_bool_(list_tests, false, + "List all tests without running them."); + +GTEST_DEFINE_string_( + output, + internal::StringFromGTestEnv("output", ""), + "A format (currently must be \"xml\"), optionally followed " + "by a colon and an output file name or directory. A directory " + "is indicated by a trailing pathname separator. " + "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " + "If a directory is specified, output files will be created " + "within that directory, with file-names based on the test " + "executable's name and, if necessary, made unique by adding " + "digits."); + +GTEST_DEFINE_bool_( + print_time, + internal::BoolFromGTestEnv("print_time", true), + "True iff " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_int32_( + random_seed, + internal::Int32FromGTestEnv("random_seed", 0), + "Random number seed to use when shuffling test orders. Must be in range " + "[1, 99999], or 0 to use a seed based on the current time."); + +GTEST_DEFINE_int32_( + repeat, + internal::Int32FromGTestEnv("repeat", 1), + "How many times to repeat each test. Specify a negative number " + "for repeating forever. Useful for shaking out flaky tests."); + +GTEST_DEFINE_bool_( + show_internal_stack_frames, false, + "True iff " GTEST_NAME_ " should include internal stack frames when " + "printing test failure stack traces."); + +GTEST_DEFINE_bool_( + shuffle, + internal::BoolFromGTestEnv("shuffle", false), + "True iff " GTEST_NAME_ + " should randomize tests' order on every run."); + +GTEST_DEFINE_int32_( + stack_trace_depth, + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + "The maximum number of stack frames to print when an " + "assertion fails. The valid range is 0 through 100, inclusive."); + +GTEST_DEFINE_string_( + stream_result_to, + internal::StringFromGTestEnv("stream_result_to", ""), + "This flag specifies the host name and the port number on which to stream " + "test results. Example: \"localhost:555\". The flag is effective only on " + "Linux."); + +GTEST_DEFINE_bool_( + throw_on_failure, + internal::BoolFromGTestEnv("throw_on_failure", false), + "When this flag is specified, a failed assertion will throw an exception " + "if exceptions are enabled or exit the program with a non-zero code " + "otherwise."); + +namespace internal { + +// Generates a random number from [0, range), using a Linear +// Congruential Generator (LCG). Crashes if 'range' is 0 or greater +// than kMaxRange. +UInt32 Random::Generate(UInt32 range) { + // These constants are the same as are used in glibc's rand(3). + state_ = (1103515245U*state_ + 12345U) % kMaxRange; + + GTEST_CHECK_(range > 0) + << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range <= kMaxRange) + << "Generation of a number in [0, " << range << ") was requested, " + << "but this can only generate numbers in [0, " << kMaxRange << ")."; + + // Converting via modulus introduces a bit of downward bias, but + // it's simple, and a linear congruential generator isn't too good + // to begin with. + return state_ % range; +} + +// GTestIsInitialized() returns true iff the user has initialized +// Google Test. Useful for catching the user mistake of not initializing +// Google Test before calling RUN_ALL_TESTS(). +// +// A user must call testing::InitGoogleTest() to initialize Google +// Test. g_init_gtest_count is set to the number of times +// InitGoogleTest() has been called. We don't protect this variable +// under a mutex as it is only accessed in the main thread. +GTEST_API_ int g_init_gtest_count = 0; +static bool GTestIsInitialized() { return g_init_gtest_count != 0; } + +// Iterates over a vector of TestCases, keeping a running sum of the +// results of calling a given int-returning method on each. +// Returns the sum. +static int SumOverTestCaseList(const std::vector& case_list, + int (TestCase::*method)() const) { + int sum = 0; + for (size_t i = 0; i < case_list.size(); i++) { + sum += (case_list[i]->*method)(); + } + return sum; +} + +// Returns true iff the test case passed. +static bool TestCasePassed(const TestCase* test_case) { + return test_case->should_run() && test_case->Passed(); +} + +// Returns true iff the test case failed. +static bool TestCaseFailed(const TestCase* test_case) { + return test_case->should_run() && test_case->Failed(); +} + +// Returns true iff test_case contains at least one test that should +// run. +static bool ShouldRunTestCase(const TestCase* test_case) { + return test_case->should_run(); +} + +// AssertHelper constructor. +AssertHelper::AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message) + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; +} + +// Message assignment, for assertion streaming support. +void AssertHelper::operator=(const Message& message) const { + UnitTest::GetInstance()-> + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), + UnitTest::GetInstance()->impl() + ->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT +} + +// Mutex for linked pointers. +GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// Application pathname gotten in InitGoogleTest. +std::string g_executable_path; + +// Returns the current application's name, removing directory path if that +// is present. +FilePath GetCurrentExecutableName() { + FilePath result; + +#if GTEST_OS_WINDOWS + result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#else + result.Set(FilePath(g_executable_path)); +#endif // GTEST_OS_WINDOWS + + return result.RemoveDirectoryName(); +} + +// Functions for processing the gtest_output flag. + +// Returns the output format, or "" for normal printed output. +std::string UnitTestOptions::GetOutputFormat() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) return std::string(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + return (colon == NULL) ? + std::string(gtest_output_flag) : + std::string(gtest_output_flag, colon - gtest_output_flag); +} + +// Returns the name of the requested output file, or the default if none +// was explicitly specified. +std::string UnitTestOptions::GetAbsolutePathToOutputFile() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) + return ""; + + const char* const colon = strchr(gtest_output_flag, ':'); + if (colon == NULL) + return internal::FilePath::ConcatPaths( + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile)).string(); + + internal::FilePath output_name(colon + 1); + if (!output_name.IsAbsolutePath()) + // TODO(wan@google.com): on Windows \some\path is not an absolute + // path (as its meaning depends on the current drive), yet the + // following logic for turning it into an absolute path is wrong. + // Fix it. + output_name = internal::FilePath::ConcatPaths( + internal::FilePath(UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(colon + 1)); + + if (!output_name.IsDirectory()) + return output_name.string(); + + internal::FilePath result(internal::FilePath::GenerateUniqueFileName( + output_name, internal::GetCurrentExecutableName(), + GetOutputFormat().c_str())); + return result.string(); +} + +// Returns true iff the wildcard pattern matches the string. The +// first ':' or '\0' character in pattern marks the end of it. +// +// This recursive algorithm isn't very efficient, but is clear and +// works well enough for matching test names, which are short. +bool UnitTestOptions::PatternMatchesString(const char *pattern, + const char *str) { + switch (*pattern) { + case '\0': + case ':': // Either ':' or '\0' marks the end of the pattern. + return *str == '\0'; + case '?': // Matches any single character. + return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); + case '*': // Matches any string (possibly empty) of characters. + return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || + PatternMatchesString(pattern + 1, str); + default: // Non-special character. Matches itself. + return *pattern == *str && + PatternMatchesString(pattern + 1, str + 1); + } +} + +bool UnitTestOptions::MatchesFilter( + const std::string& name, const char* filter) { + const char *cur_pattern = filter; + for (;;) { + if (PatternMatchesString(cur_pattern, name.c_str())) { + return true; + } + + // Finds the next pattern in the filter. + cur_pattern = strchr(cur_pattern, ':'); + + // Returns if no more pattern can be found. + if (cur_pattern == NULL) { + return false; + } + + // Skips the pattern separater (the ':' character). + cur_pattern++; + } +} + +// Returns true iff the user-specified filter matches the test case +// name and the test name. +bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, + const std::string &test_name) { + const std::string& full_name = test_case_name + "." + test_name.c_str(); + + // Split --gtest_filter at '-', if there is one, to separate into + // positive filter and negative filter portions + const char* const p = GTEST_FLAG(filter).c_str(); + const char* const dash = strchr(p, '-'); + std::string positive; + std::string negative; + if (dash == NULL) { + positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter + negative = ""; + } else { + positive = std::string(p, dash); // Everything up to the dash + negative = std::string(dash + 1); // Everything after the dash + if (positive.empty()) { + // Treat '-test1' as the same as '*-test1' + positive = kUniversalFilter; + } + } + + // A filter is a colon-separated list of patterns. It matches a + // test if any pattern in it matches the test. + return (MatchesFilter(full_name, positive.c_str()) && + !MatchesFilter(full_name, negative.c_str())); +} + +#if GTEST_HAS_SEH +// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the +// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. +// This function is useful as an __except condition. +int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { + // Google Test should handle a SEH exception if: + // 1. the user wants it to, AND + // 2. this is not a breakpoint exception, AND + // 3. this is not a C++ exception (VC++ implements them via SEH, + // apparently). + // + // SEH exception code for C++ exceptions. + // (see http://support.microsoft.com/kb/185294 for more information). + const DWORD kCxxExceptionCode = 0xe06d7363; + + bool should_handle = true; + + if (!GTEST_FLAG(catch_exceptions)) + should_handle = false; + else if (exception_code == EXCEPTION_BREAKPOINT) + should_handle = false; + else if (exception_code == kCxxExceptionCode) + should_handle = false; + + return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} +#endif // GTEST_HAS_SEH + +} // namespace internal + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. Intercepts only failures from the current thread. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), + result_(result) { + Init(); +} + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + InterceptMode intercept_mode, TestPartResultArray* result) + : intercept_mode_(intercept_mode), + result_(result) { + Init(); +} + +void ScopedFakeTestPartResultReporter::Init() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + old_reporter_ = impl->GetGlobalTestPartResultReporter(); + impl->SetGlobalTestPartResultReporter(this); + } else { + old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); + impl->SetTestPartResultReporterForCurrentThread(this); + } +} + +// The d'tor restores the test part result reporter used by Google Test +// before. +ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + impl->SetGlobalTestPartResultReporter(old_reporter_); + } else { + impl->SetTestPartResultReporterForCurrentThread(old_reporter_); + } +} + +// Increments the test part result count and remembers the result. +// This method is from the TestPartResultReporterInterface interface. +void ScopedFakeTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + result_->Append(result); +} + +namespace internal { + +// Returns the type ID of ::testing::Test. We should always call this +// instead of GetTypeId< ::testing::Test>() to get the type ID of +// testing::Test. This is to work around a suspected linker bug when +// using Google Test as a framework on Mac OS X. The bug causes +// GetTypeId< ::testing::Test>() to return different values depending +// on whether the call is from the Google Test framework itself or +// from user test code. GetTestTypeId() is guaranteed to always +// return the same value, as it always calls GetTypeId<>() from the +// gtest.cc, which is within the Google Test framework. +TypeId GetTestTypeId() { + return GetTypeId(); +} + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); + +// This predicate-formatter checks that 'results' contains a test part +// failure of the given type and that the failure message contains the +// given substring. +AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const string& substr) { + const std::string expected(type == TestPartResult::kFatalFailure ? + "1 fatal failure" : + "1 non-fatal failure"); + Message msg; + if (results.size() != 1) { + msg << "Expected: " << expected << "\n" + << " Actual: " << results.size() << " failures"; + for (int i = 0; i < results.size(); i++) { + msg << "\n" << results.GetTestPartResult(i); + } + return AssertionFailure() << msg; + } + + const TestPartResult& r = results.GetTestPartResult(0); + if (r.type() != type) { + return AssertionFailure() << "Expected: " << expected << "\n" + << " Actual:\n" + << r; + } + + if (strstr(r.message(), substr.c_str()) == NULL) { + return AssertionFailure() << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; + } + + return AssertionSuccess(); +} + +// The constructor of SingleFailureChecker remembers where to look up +// test part results, what type of failure we expect, and what +// substring the failure message should contain. +SingleFailureChecker:: SingleFailureChecker( + const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr) + : results_(results), + type_(type), + substr_(substr) {} + +// The destructor of SingleFailureChecker verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +SingleFailureChecker::~SingleFailureChecker() { + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); +} + +DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultGlobalTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->current_test_result()->AddTestPartResult(result); + unit_test_->listeners()->repeater()->OnTestPartResult(result); +} + +DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); +} + +// Returns the global test part result reporter. +TestPartResultReporterInterface* +UnitTestImpl::GetGlobalTestPartResultReporter() { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + return global_test_part_result_repoter_; +} + +// Sets the global test part result reporter. +void UnitTestImpl::SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter) { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + global_test_part_result_repoter_ = reporter; +} + +// Returns the test part result reporter for the current thread. +TestPartResultReporterInterface* +UnitTestImpl::GetTestPartResultReporterForCurrentThread() { + return per_thread_test_part_result_reporter_.get(); +} + +// Sets the test part result reporter for the current thread. +void UnitTestImpl::SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter) { + per_thread_test_part_result_reporter_.set(reporter); +} + +// Gets the number of successful test cases. +int UnitTestImpl::successful_test_case_count() const { + return CountIf(test_cases_, TestCasePassed); +} + +// Gets the number of failed test cases. +int UnitTestImpl::failed_test_case_count() const { + return CountIf(test_cases_, TestCaseFailed); +} + +// Gets the number of all test cases. +int UnitTestImpl::total_test_case_count() const { + return static_cast(test_cases_.size()); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTestImpl::test_case_to_run_count() const { + return CountIf(test_cases_, ShouldRunTestCase); +} + +// Gets the number of successful tests. +int UnitTestImpl::successful_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); +} + +// Gets the number of failed tests. +int UnitTestImpl::failed_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); +} + +// Gets the number of disabled tests that will be reported in the XML report. +int UnitTestImpl::reportable_disabled_test_count() const { + return SumOverTestCaseList(test_cases_, + &TestCase::reportable_disabled_test_count); +} + +// Gets the number of disabled tests. +int UnitTestImpl::disabled_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); +} + +// Gets the number of tests to be printed in the XML report. +int UnitTestImpl::reportable_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); +} + +// Gets the number of all tests. +int UnitTestImpl::total_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); +} + +// Gets the number of tests that should run. +int UnitTestImpl::test_to_run_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); +} + +// Returns the current OS stack trace as an std::string. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// CurrentOsStackTraceExceptTop(1), Foo() will be included in the +// trace but Bar() and CurrentOsStackTraceExceptTop() won't. +std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { + (void)skip_count; + return ""; +} + +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis() { +#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) + // Difference between 1970-01-01 and 1601-01-01 in milliseconds. + // http://analogous.blogspot.com/2005/04/epoch.html + const TimeInMillis kJavaEpochToWinFileTimeDelta = + static_cast(116444736UL) * 100000UL; + const DWORD kTenthMicrosInMilliSecond = 10000; + + SYSTEMTIME now_systime; + FILETIME now_filetime; + ULARGE_INTEGER now_int64; + // TODO(kenton@google.com): Shouldn't this just use + // GetSystemTimeAsFileTime()? + GetSystemTime(&now_systime); + if (SystemTimeToFileTime(&now_systime, &now_filetime)) { + now_int64.LowPart = now_filetime.dwLowDateTime; + now_int64.HighPart = now_filetime.dwHighDateTime; + now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - + kJavaEpochToWinFileTimeDelta; + return now_int64.QuadPart; + } + return 0; +#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ + __timeb64 now; + +# ifdef _MSC_VER + + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 + // (deprecated function) there. + // TODO(kenton@google.com): Use GetTickCount()? Or use + // SystemTimeToFileTime() +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + _ftime64(&now); +# pragma warning(pop) // Restores the warning state. +# else + + _ftime64(&now); + +# endif // _MSC_VER + + return static_cast(now.time) * 1000 + now.millitm; +#elif GTEST_HAS_GETTIMEOFDAY_ + struct timeval now; + gettimeofday(&now, NULL); + return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; +#else +# error "Don't know how to get the current time on your system." +#endif +} + +// Utilities + +// class String. + +#if GTEST_OS_WINDOWS_MOBILE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return NULL; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, + NULL, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return NULL; + const int ansi_length = + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + NULL, 0, NULL, NULL); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + ansi, ansi_length, NULL, NULL); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +// Compares two C strings. Returns true iff they have the same content. +// +// Unlike strcmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CStringEquals(const char * lhs, const char * rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + + return strcmp(lhs, rhs) == 0; +} + +#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +// Converts an array of wide chars to a narrow string using the UTF-8 +// encoding, and streams the result to the given Message object. +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, + Message* msg) { + for (size_t i = 0; i != length; ) { // NOLINT + if (wstr[i] != L'\0') { + *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); + while (i != length && wstr[i] != L'\0') + i++; + } else { + *msg << '\0'; + i++; + } + } +} + +#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +} // namespace internal + +// Constructs an empty Message. +// We allocate the stringstream separately because otherwise each use of +// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's +// stack frame leading to huge stack frames in some cases; gcc does not reuse +// the stack space. +Message::Message() : ss_(new ::std::stringstream) { + // By default, we want there to be enough precision when printing + // a double to a Message. + *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); +} + +// These two overloads allow streaming a wide C string to a Message +// using the UTF-8 encoding. +Message& Message::operator <<(const wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); +} +Message& Message::operator <<(wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); +} + +#if GTEST_HAS_STD_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::std::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Gets the text streamed to this object so far as an std::string. +// Each '\0' character in the buffer is replaced with "\\0". +std::string Message::GetString() const { + return internal::StringStreamToString(ss_.get()); +} + +// AssertionResult constructors. +// Used in EXPECT_TRUE/FALSE(assertion_result). +AssertionResult::AssertionResult(const AssertionResult& other) + : success_(other.success_), + message_(other.message_.get() != NULL ? + new ::std::string(*other.message_) : + static_cast< ::std::string*>(NULL)) { +} + +// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. +AssertionResult AssertionResult::operator!() const { + AssertionResult negation(!success_); + if (message_.get() != NULL) + negation << *message_; + return negation; +} + +// Makes a successful assertion result. +AssertionResult AssertionSuccess() { + return AssertionResult(true); +} + +// Makes a failed assertion result. +AssertionResult AssertionFailure() { + return AssertionResult(false); +} + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << message. +AssertionResult AssertionFailure(const Message& message) { + return AssertionFailure() << message; +} + +namespace internal { + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const std::string& expected_value, + const std::string& actual_value, + bool ignoring_case) { + Message msg; + msg << "Value of: " << actual_expression; + if (actual_value != actual_expression) { + msg << "\n Actual: " << actual_value; + } + + msg << "\nExpected: " << expected_expression; + if (ignoring_case) { + msg << " (ignoring case)"; + } + if (expected_value != expected_expression) { + msg << "\nWhich is: " << expected_value; + } + + return AssertionFailure() << msg; +} + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +std::string GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { + const char* actual_message = assertion_result.message(); + Message msg; + msg << "Value of: " << expression_text + << "\n Actual: " << actual_predicate_value; + if (actual_message[0] != '\0') + msg << " (" << actual_message << ")"; + msg << "\nExpected: " << expected_predicate_value; + return msg.GetString(); +} + +// Helper function for implementing ASSERT_NEAR. +AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error) { + const double diff = fabs(val1 - val2); + if (diff <= abs_error) return AssertionSuccess(); + + // TODO(wan): do not print the value of an expression if it's + // already a literal. + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 + << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; +} + + +// Helper template for implementing FloatLE() and DoubleLE(). +template +AssertionResult FloatingPointLE(const char* expr1, + const char* expr2, + RawType val1, + RawType val2) { + // Returns success if val1 is less than val2, + if (val1 < val2) { + return AssertionSuccess(); + } + + // or if val1 is almost equal to val2. + const FloatingPoint lhs(val1), rhs(val2); + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + // Note that the above two checks will both fail if either val1 or + // val2 is NaN, as the IEEE floating-point standard requires that + // any predicate involving a NaN must return false. + + ::std::stringstream val1_ss; + val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val1; + + ::std::stringstream val2_ss; + val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val2; + + return AssertionFailure() + << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StringStreamToString(&val1_ss) << " vs " + << StringStreamToString(&val2_ss); +} + +} // namespace internal + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +namespace internal { + +// The helper function for {ASSERT|EXPECT}_EQ with int or enum +// arguments. +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + if (expected == actual) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here +// just to avoid copy-and-paste of similar code. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + BiggestInt val1, BiggestInt val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +} + +// Implements the helper function for {ASSERT|EXPECT}_NE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LT, < ) +// Implements the helper function for {ASSERT|EXPECT}_GE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GT, > ) + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + PrintToString(expected), + PrintToString(actual), + false); +} + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CaseInsensitiveCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + PrintToString(expected), + PrintToString(actual), + true); +} + +// The helper function for {ASSERT|EXPECT}_STRNE. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CaseInsensitiveCStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" + << s2_expression << ") (ignoring case), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +} // namespace internal + +namespace { + +// Helper functions for implementing IsSubString() and IsNotSubstring(). + +// This group of overloaded functions return true iff needle is a +// substring of haystack. NULL is considered a substring of itself +// only. + +bool IsSubstringPred(const char* needle, const char* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return strstr(haystack, needle) != NULL; +} + +bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return wcsstr(haystack, needle) != NULL; +} + +// StringType here can be either ::std::string or ::std::wstring. +template +bool IsSubstringPred(const StringType& needle, + const StringType& haystack) { + return haystack.find(needle) != StringType::npos; +} + +// This function implements either IsSubstring() or IsNotSubstring(), +// depending on the value of the expected_to_be_substring parameter. +// StringType here can be const char*, const wchar_t*, ::std::string, +// or ::std::wstring. +template +AssertionResult IsSubstringImpl( + bool expected_to_be_substring, + const char* needle_expr, const char* haystack_expr, + const StringType& needle, const StringType& haystack) { + if (IsSubstringPred(needle, haystack) == expected_to_be_substring) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(needle[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure() + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""; +} + +} // namespace + +// IsSubstring() and IsNotSubstring() check whether needle is a +// substring of haystack (NULL is considered a substring of itself +// only), and return an appropriate error message when they fail. + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +#if GTEST_HAS_STD_WSTRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +#if GTEST_OS_WINDOWS + +namespace { + +// Helper function for IsHRESULT{SuccessFailure} predicates +AssertionResult HRESULTFailureHelper(const char* expr, + const char* expected, + long hr) { // NOLINT +# if GTEST_OS_WINDOWS_MOBILE + + // Windows CE doesn't support FormatMessage. + const char error_text[] = ""; + +# else + + // Looks up the human-readable system message for the HRESULT code + // and since we're not passing any params to FormatMessage, we don't + // want inserts expanded. + const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kBufSize = 4096; + // Gets the system's human readable message string for this HRESULT. + char error_text[kBufSize] = { '\0' }; + DWORD message_length = ::FormatMessageA(kFlags, + 0, // no source, we're asking system + hr, // the error + 0, // no line width restrictions + error_text, // output buffer + kBufSize, // buf size + NULL); // no arguments for inserts + // Trims tailing white space (FormatMessage leaves a trailing CR-LF) + for (; message_length && IsSpace(error_text[message_length - 1]); + --message_length) { + error_text[message_length - 1] = '\0'; + } + +# endif // GTEST_OS_WINDOWS_MOBILE + + const std::string error_hex("0x" + String::FormatHexInt(hr)); + return ::testing::AssertionFailure() + << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << " " << error_text << "\n"; +} + +} // namespace + +AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT + if (SUCCEEDED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "succeeds", hr); +} + +AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT + if (FAILED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "fails", hr); +} + +#endif // GTEST_OS_WINDOWS + +// Utility functions for encoding Unicode text (wide strings) in +// UTF-8. + +// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// like this: +// +// Code-point length Encoding +// 0 - 7 bits 0xxxxxxx +// 8 - 11 bits 110xxxxx 10xxxxxx +// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx +// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +// The maximum code-point a one-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; + +// The maximum code-point a two-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; + +// The maximum code-point a three-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; + +// The maximum code-point a four-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; + +// Chops off the n lowest bits from a bit pattern. Returns the n +// lowest bits. As a side effect, the original bit pattern will be +// shifted to the right by n bits. +inline UInt32 ChopLowBits(UInt32* bits, int n) { + const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); + *bits >>= n; + return low_bits; +} + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted +// to "(Invalid Unicode 0xXXXXXXXX)". +std::string CodePointToUtf8(UInt32 code_point) { + if (code_point > kMaxCodePoint4) { + return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; + } + + char str[5]; // Big enough for the largest valid code point. + if (code_point <= kMaxCodePoint1) { + str[1] = '\0'; + str[0] = static_cast(code_point); // 0xxxxxxx + } else if (code_point <= kMaxCodePoint2) { + str[2] = '\0'; + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code_point); // 110xxxxx + } else if (code_point <= kMaxCodePoint3) { + str[3] = '\0'; + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code_point); // 1110xxxx + } else { // code_point <= kMaxCodePoint4 + str[4] = '\0'; + str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code_point); // 11110xxx + } + return str; +} + +// The following two functions only make sense if the the system +// uses UTF-16 for wide string encoding. All supported systems +// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. + +// Determines if the arguments constitute UTF-16 surrogate pair +// and thus should be combined into a single Unicode code point +// using CreateCodePointFromUtf16SurrogatePair. +inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { + return sizeof(wchar_t) == 2 && + (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; +} + +// Creates a Unicode code point from UTF16 surrogate pair. +inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const UInt32 mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) ? + (((first & mask) << 10) | (second & mask)) + 0x10000 : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + static_cast(first); +} + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +std::string WideStringToUtf8(const wchar_t* str, int num_chars) { + if (num_chars == -1) + num_chars = static_cast(wcslen(str)); + + ::std::stringstream stream; + for (int i = 0; i < num_chars; ++i) { + UInt32 unicode_code_point; + + if (str[i] == L'\0') { + break; + } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { + unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], + str[i + 1]); + i++; + } else { + unicode_code_point = static_cast(str[i]); + } + + stream << CodePointToUtf8(unicode_code_point); + } + return StringStreamToString(&stream); +} + +// Converts a wide C string to an std::string using the UTF-8 encoding. +// NULL will be converted to "(null)". +std::string String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == NULL) return "(null)"; + + return internal::WideStringToUtf8(wide_c_str, -1); +} + +// Compares two wide C strings. Returns true iff they have the same +// content. +// +// Unlike wcscmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + + return wcscmp(lhs, rhs) == 0; +} + +// Helper function for *_STREQ on wide strings. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual) { + if (String::WideCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + PrintToString(expected), + PrintToString(actual), + false); +} + +// Helper function for *_STRNE on wide strings. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2) { + if (!String::WideCStringEquals(s1, s2)) { + return AssertionSuccess(); + } + + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << PrintToString(s1) + << " vs " << PrintToString(s2); +} + +// Compares two C strings, ignoring case. Returns true iff they have +// the same content. +// +// Unlike strcasecmp(), this function can handle NULL argument(s). A +// NULL C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { + if (lhs == NULL) + return rhs == NULL; + if (rhs == NULL) + return false; + return posix::StrCaseCmp(lhs, rhs) == 0; +} + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + +#if GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID + return wcscasecmp(lhs, rhs) == 0; +#else + // Android, Mac OS X and Cygwin don't define wcscasecmp. + // Other unknown OSes may not define it either. + wint_t left, right; + do { + left = towlower(*lhs++); + right = towlower(*rhs++); + } while (left && left == right); + return left == right; +#endif // OS selector +} + +// Returns true iff str ends with the given suffix, ignoring case. +// Any string is considered to end with an empty suffix. +bool String::EndsWithCaseInsensitive( + const std::string& str, const std::string& suffix) { + const size_t str_len = str.length(); + const size_t suffix_len = suffix.length(); + return (str_len >= suffix_len) && + CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, + suffix.c_str()); +} + +// Formats an int value as "%02d". +std::string String::FormatIntWidth2(int value) { + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << value; + return ss.str(); +} + +// Formats an int value as "%X". +std::string String::FormatHexInt(int value) { + std::stringstream ss; + ss << std::hex << std::uppercase << value; + return ss.str(); +} + +// Formats a byte as "%02X". +std::string String::FormatByte(unsigned char value) { + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase + << static_cast(value); + return ss.str(); +} + +// Converts the buffer in a stringstream to an std::string, converting NUL +// bytes to "\\0" along the way. +std::string StringStreamToString(::std::stringstream* ss) { + const ::std::string& str = ss->str(); + const char* const start = str.c_str(); + const char* const end = start + str.length(); + + std::string result; + result.reserve(2 * (end - start)); + for (const char* ch = start; ch != end; ++ch) { + if (*ch == '\0') { + result += "\\0"; // Replaces NUL with "\\0"; + } else { + result += *ch; + } + } + + return result; +} + +// Appends the user-supplied message to the Google-Test-generated message. +std::string AppendUserMessage(const std::string& gtest_msg, + const Message& user_msg) { + // Appends the user message if it's non-empty. + const std::string user_msg_string = user_msg.GetString(); + if (user_msg_string.empty()) { + return gtest_msg; + } + + return gtest_msg + "\n" + user_msg_string; +} + +} // namespace internal + +// class TestResult + +// Creates an empty TestResult. +TestResult::TestResult() + : death_test_count_(0), + elapsed_time_(0) { +} + +// D'tor. +TestResult::~TestResult() { +} + +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) + internal::posix::Abort(); + return test_part_results_.at(i); +} + +// Returns the i-th test property. i can range from 0 to +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) + internal::posix::Abort(); + return test_properties_.at(i); +} + +// Clears the test part results. +void TestResult::ClearTestPartResults() { + test_part_results_.clear(); +} + +// Adds a test part result to the list. +void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { + test_part_results_.push_back(test_part_result); +} + +// Adds a test property to the list. If a property with the same key as the +// supplied property is already represented, the value of this test_property +// replaces the old value for that key. +void TestResult::RecordProperty(const std::string& xml_element, + const TestProperty& test_property) { + if (!ValidateTestProperty(xml_element, test_property)) { + return; + } + internal::MutexLock lock(&test_properites_mutex_); + const std::vector::iterator property_with_matching_key = + std::find_if(test_properties_.begin(), test_properties_.end(), + internal::TestPropertyKeyIs(test_property.key())); + if (property_with_matching_key == test_properties_.end()) { + test_properties_.push_back(test_property); + return; + } + property_with_matching_key->SetValue(test_property.value()); +} + +// The list of reserved attributes used in the element of XML +// output. +static const char* const kReservedTestSuitesAttributes[] = { + "disabled", + "errors", + "failures", + "name", + "random_seed", + "tests", + "time", + "timestamp" +}; + +// The list of reserved attributes used in the element of XML +// output. +static const char* const kReservedTestSuiteAttributes[] = { + "disabled", + "errors", + "failures", + "name", + "tests", + "time" +}; + +// The list of reserved attributes used in the element of XML output. +static const char* const kReservedTestCaseAttributes[] = { + "classname", + "name", + "status", + "time", + "type_param", + "value_param" +}; + +template +std::vector ArrayAsVector(const char* const (&array)[kSize]) { + return std::vector(array, array + kSize); +} + +static std::vector GetReservedAttributesForElement( + const std::string& xml_element) { + if (xml_element == "testsuites") { + return ArrayAsVector(kReservedTestSuitesAttributes); + } else if (xml_element == "testsuite") { + return ArrayAsVector(kReservedTestSuiteAttributes); + } else if (xml_element == "testcase") { + return ArrayAsVector(kReservedTestCaseAttributes); + } else { + GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; + } + // This code is unreachable but some compilers may not realizes that. + return std::vector(); +} + +static std::string FormatWordList(const std::vector& words) { + Message word_list; + for (size_t i = 0; i < words.size(); ++i) { + if (i > 0 && words.size() > 2) { + word_list << ", "; + } + if (i == words.size() - 1) { + word_list << "and "; + } + word_list << "'" << words[i] << "'"; + } + return word_list.GetString(); +} + +bool ValidateTestPropertyName(const std::string& property_name, + const std::vector& reserved_names) { + if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != + reserved_names.end()) { + ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name + << " (" << FormatWordList(reserved_names) + << " are reserved by " << GTEST_NAME_ << ")"; + return false; + } + return true; +} + +// Adds a failure if the key is a reserved attribute of the element named +// xml_element. Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const std::string& xml_element, + const TestProperty& test_property) { + return ValidateTestPropertyName(test_property.key(), + GetReservedAttributesForElement(xml_element)); +} + +// Clears the object. +void TestResult::Clear() { + test_part_results_.clear(); + test_properties_.clear(); + death_test_count_ = 0; + elapsed_time_ = 0; +} + +// Returns true iff the test failed. +bool TestResult::Failed() const { + for (int i = 0; i < total_part_count(); ++i) { + if (GetTestPartResult(i).failed()) + return true; + } + return false; +} + +// Returns true iff the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult& result) { + return result.fatally_failed(); +} + +// Returns true iff the test fatally failed. +bool TestResult::HasFatalFailure() const { + return CountIf(test_part_results_, TestPartFatallyFailed) > 0; +} + +// Returns true iff the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true iff the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; +} + +// Gets the number of all test parts. This is the sum of the number +// of successful test parts and the number of failed test parts. +int TestResult::total_part_count() const { + return static_cast(test_part_results_.size()); +} + +// Returns the number of the test properties. +int TestResult::test_property_count() const { + return static_cast(test_properties_.size()); +} + +// class Test + +// Creates a Test object. + +// The c'tor saves the values of all Google Test flags. +Test::Test() + : gtest_flag_saver_(new internal::GTestFlagSaver) { +} + +// The d'tor restores the values of all Google Test flags. +Test::~Test() { + delete gtest_flag_saver_; +} + +// Sets up the test fixture. +// +// A sub-class may override this. +void Test::SetUp() { +} + +// Tears down the test fixture. +// +// A sub-class may override this. +void Test::TearDown() { +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const std::string& key, const std::string& value) { + UnitTest::GetInstance()->RecordProperty(key, value); +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const std::string& key, int value) { + Message value_message; + value_message << value; + RecordProperty(key, value_message.GetString().c_str()); +} + +namespace internal { + +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const std::string& message) { + // This function is a friend of UnitTest and as such has access to + // AddTestPartResult. + UnitTest::GetInstance()->AddTestPartResult( + result_type, + NULL, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. + message, + ""); // No stack trace, either. +} + +} // namespace internal + +// Google Test requires all tests in the same test case to use the same test +// fixture class. This function checks if the current test has the +// same fixture class as the first test in the current test case. If +// yes, it returns true; otherwise it generates a Google Test failure and +// returns false. +bool Test::HasSameFixtureClass() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + const TestCase* const test_case = impl->current_test_case(); + + // Info about the first test in the current test case. + const TestInfo* const first_test_info = test_case->test_info_list()[0]; + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; + const char* const first_test_name = first_test_info->name(); + + // Info about the current test. + const TestInfo* const this_test_info = impl->current_test_info(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; + const char* const this_test_name = this_test_info->name(); + + if (this_fixture_id != first_fixture_id) { + // Is the first test defined using TEST? + const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); + // Is this test defined using TEST? + const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); + + if (first_is_TEST || this_is_TEST) { + // The user mixed TEST and TEST_F in this test case - we'll tell + // him/her how to fix it. + + // Gets the name of the TEST and the name of the TEST_F. Note + // that first_is_TEST and this_is_TEST cannot both be true, as + // the fixture IDs are different for the two tests. + const char* const TEST_name = + first_is_TEST ? first_test_name : this_test_name; + const char* const TEST_F_name = + first_is_TEST ? this_test_name : first_test_name; + + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test case is\n" + << "illegal. In test case " << this_test_info->test_case_name() + << ",\n" + << "test " << TEST_F_name << " is defined using TEST_F but\n" + << "test " << TEST_name << " is defined using TEST. You probably\n" + << "want to change the TEST to TEST_F or move it to another test\n" + << "case."; + } else { + // The user defined two fixture classes with the same name in + // two namespaces - we'll tell him/her how to fix it. + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " + << this_test_info->test_case_name() << ",\n" + << "you defined test " << first_test_name + << " and test " << this_test_name << "\n" + << "using two different test fixture classes. This can happen if\n" + << "the two classes are from different namespaces or translation\n" + << "units and have the same name. You should probably rename one\n" + << "of the classes to put the tests into different test cases."; + } + return false; + } + + return true; +} + +#if GTEST_HAS_SEH + +// Adds an "exception thrown" fatal failure to the current test. This +// function returns its result via an output parameter pointer because VC++ +// prohibits creation of objects with destructors on stack in functions +// using __try (see error C2712). +static std::string* FormatSehExceptionMessage(DWORD exception_code, + const char* location) { + Message message; + message << "SEH exception with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " thrown in " << location << "."; + + return new std::string(message.GetString()); +} + +#endif // GTEST_HAS_SEH + +namespace internal { + +#if GTEST_HAS_EXCEPTIONS + +// Adds an "exception thrown" fatal failure to the current test. +static std::string FormatCxxExceptionMessage(const char* description, + const char* location) { + Message message; + if (description != NULL) { + message << "C++ exception with description \"" << description << "\""; + } else { + message << "Unknown C++ exception"; + } + message << " thrown in " << location << "."; + + return message.GetString(); +} + +static std::string PrintTestPartResultToString( + const TestPartResult& test_part_result); + +GoogleTestFailureException::GoogleTestFailureException( + const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} + +#endif // GTEST_HAS_EXCEPTIONS + +// We put these helper functions in the internal namespace as IBM's xlC +// compiler rejects the code if they were declared static. + +// Runs the given method and handles SEH exceptions it throws, when +// SEH is supported; returns the 0-value for type Result in case of an +// SEH exception. (Microsoft compilers cannot handle SEH and C++ +// exceptions in the same function. Therefore, we provide a separate +// wrapper function for handling SEH exceptions.) +template +Result HandleSehExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { +#if GTEST_HAS_SEH + __try { + return (object->*method)(); + } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT + GetExceptionCode())) { + // We create the exception message on the heap because VC++ prohibits + // creation of objects with destructors on stack in functions using __try + // (see error C2712). + std::string* exception_message = FormatSehExceptionMessage( + GetExceptionCode(), location); + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + *exception_message); + delete exception_message; + return static_cast(0); + } +#else + (void)location; + return (object->*method)(); +#endif // GTEST_HAS_SEH +} + +// Runs the given method and catches and reports C++ and/or SEH-style +// exceptions, if they are supported; returns the 0-value for type +// Result in case of an SEH exception. +template +Result HandleExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { + // NOTE: The user code can affect the way in which Google Test handles + // exceptions by setting GTEST_FLAG(catch_exceptions), but only before + // RUN_ALL_TESTS() starts. It is technically possible to check the flag + // after the exception is caught and either report or re-throw the + // exception based on the flag's value: + // + // try { + // // Perform the test method. + // } catch (...) { + // if (GTEST_FLAG(catch_exceptions)) + // // Report the exception as failure. + // else + // throw; // Re-throws the original exception. + // } + // + // However, the purpose of this flag is to allow the program to drop into + // the debugger when the exception is thrown. On most platforms, once the + // control enters the catch block, the exception origin information is + // lost and the debugger will stop the program at the point of the + // re-throw in this function -- instead of at the point of the original + // throw statement in the code under test. For this reason, we perform + // the check early, sacrificing the ability to affect Google Test's + // exception handling in the method where the exception is thrown. + if (internal::GetUnitTestImpl()->catch_exceptions()) { +#if GTEST_HAS_EXCEPTIONS + try { + return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const internal::GoogleTestFailureException&) { // NOLINT + // This exception type can only be thrown by a failed Google + // Test assertion with the intention of letting another testing + // framework catch it. Therefore we just re-throw it. + throw; + } catch (const std::exception& e) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(e.what(), location)); + } catch (...) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(NULL, location)); + } + return static_cast(0); +#else + return HandleSehExceptionsInMethodIfSupported(object, method, location); +#endif // GTEST_HAS_EXCEPTIONS + } else { + return (object->*method)(); + } +} + +} // namespace internal + +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); + // We will run the test only if SetUp() was successful. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TestBody, "the test body"); + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TearDown, "TearDown()"); +} + +// Returns true iff the current test has a fatal failure. +bool Test::HasFatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); +} + +// Returns true iff the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + +// class TestInfo + +// Constructs a TestInfo object. It assumes ownership of the test factory +// object. +TestInfo::TestInfo(const std::string& a_test_case_name, + const std::string& a_name, + const char* a_type_param, + const char* a_value_param, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory) + : test_case_name_(a_test_case_name), + name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + value_param_(a_value_param ? new std::string(a_value_param) : NULL), + fixture_class_id_(fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory), + result_() {} + +// Destructs a TestInfo object. +TestInfo::~TestInfo() { delete factory_; } + +namespace internal { + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param: the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param: text representation of the test's value parameter, +// or NULL if this is not a value-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, + const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory) { + TestInfo* const test_info = + new TestInfo(test_case_name, name, type_param, value_param, + fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + return test_info; +} + +#if GTEST_HAS_PARAM_TEST +void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line) { + Message errors; + errors + << "Attempted redefinition of test case " << test_case_name << ".\n" + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " << test_case_name << ", you tried\n" + << "to define a test using a fixture class different from the one\n" + << "used earlier. This can happen if the two fixture classes are\n" + << "from different namespaces and have the same name. You should\n" + << "probably rename one of the classes to put the tests into different\n" + << "test cases."; + + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors.GetString().c_str()); +} +#endif // GTEST_HAS_PARAM_TEST + +} // namespace internal + +namespace { + +// A predicate that checks the test name of a TestInfo against a known +// value. +// +// This is used for implementation of the TestCase class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestNameIs is copyable. +class TestNameIs { + public: + // Constructor. + // + // TestNameIs has NO default constructor. + explicit TestNameIs(const char* name) + : name_(name) {} + + // Returns true iff the test name of test_info matches name_. + bool operator()(const TestInfo * test_info) const { + return test_info && test_info->name() == name_; + } + + private: + std::string name_; +}; + +} // namespace + +namespace internal { + +// This method expands all parameterized tests registered with macros TEST_P +// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// This will be done just once during the program runtime. +void UnitTestImpl::RegisterParameterizedTests() { +#if GTEST_HAS_PARAM_TEST + if (!parameterized_tests_registered_) { + parameterized_test_registry_.RegisterTests(); + parameterized_tests_registered_ = true; + } +#endif +} + +} // namespace internal + +// Creates the test object, runs it, records its result, and then +// deletes it. +void TestInfo::Run() { + if (!should_run_) return; + + // Tells UnitTest where to store test result. + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*this); + + const TimeInMillis start = internal::GetTimeInMillis(); + + impl->os_stack_trace_getter()->UponLeavingGTest(); + + // Creates the test object. + Test* const test = internal::HandleExceptionsInMethodIfSupported( + factory_, &internal::TestFactoryBase::CreateTest, + "the test fixture's constructor"); + + // Runs the test only if the test object was created and its + // constructor didn't generate a fatal failure. + if ((test != NULL) && !Test::HasFatalFailure()) { + // This doesn't throw as all user code that can throw are wrapped into + // exception handling code. + test->Run(); + } + + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); + + result_.set_elapsed_time(internal::GetTimeInMillis() - start); + + // Notifies the unit test event listener that a test has just finished. + repeater->OnTestEnd(*this); + + // Tells UnitTest to stop associating assertion results to this + // test. + impl->set_current_test_info(NULL); +} + +// class TestCase + +// Gets the number of successful tests in this test case. +int TestCase::successful_test_count() const { + return CountIf(test_info_list_, TestPassed); +} + +// Gets the number of failed tests in this test case. +int TestCase::failed_test_count() const { + return CountIf(test_info_list_, TestFailed); +} + +// Gets the number of disabled tests that will be reported in the XML report. +int TestCase::reportable_disabled_test_count() const { + return CountIf(test_info_list_, TestReportableDisabled); +} + +// Gets the number of disabled tests in this test case. +int TestCase::disabled_test_count() const { + return CountIf(test_info_list_, TestDisabled); +} + +// Gets the number of tests to be printed in the XML report. +int TestCase::reportable_test_count() const { + return CountIf(test_info_list_, TestReportable); +} + +// Get the number of tests in this test case that should run. +int TestCase::test_to_run_count() const { + return CountIf(test_info_list_, ShouldRunTest); +} + +// Gets the number of all tests. +int TestCase::total_test_count() const { + return static_cast(test_info_list_.size()); +} + +// Creates a TestCase with the given name. +// +// Arguments: +// +// name: name of the test case +// a_type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase::TestCase(const char* a_name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) + : name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + set_up_tc_(set_up_tc), + tear_down_tc_(tear_down_tc), + should_run_(false), + elapsed_time_(0) { +} + +// Destructor of TestCase. +TestCase::~TestCase() { + // Deletes every Test in the collection. + ForEach(test_info_list_, internal::Delete); +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +const TestInfo* TestCase::GetTestInfo(int i) const { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +TestInfo* TestCase::GetMutableTestInfo(int i) { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Adds a test to this test case. Will delete the test upon +// destruction of the TestCase object. +void TestCase::AddTestInfo(TestInfo * test_info) { + test_info_list_.push_back(test_info); + test_indices_.push_back(static_cast(test_indices_.size())); +} + +// Runs every test in this TestCase. +void TestCase::Run() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_case(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + repeater->OnTestCaseStart(*this); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); + + const internal::TimeInMillis start = internal::GetTimeInMillis(); + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->Run(); + } + elapsed_time_ = internal::GetTimeInMillis() - start; + + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + + repeater->OnTestCaseEnd(*this); + impl->set_current_test_case(NULL); +} + +// Clears the results of all tests in this test case. +void TestCase::ClearResult() { + ad_hoc_test_result_.Clear(); + ForEach(test_info_list_, TestInfo::ClearTestResult); +} + +// Shuffles the tests in this test case. +void TestCase::ShuffleTests(internal::Random* random) { + Shuffle(random, &test_indices_); +} + +// Restores the test order to before the first shuffle. +void TestCase::UnshuffleTests() { + for (size_t i = 0; i < test_indices_.size(); i++) { + test_indices_[i] = static_cast(i); + } +} + +// Formats a countable noun. Depending on its quantity, either the +// singular form or the plural form is used. e.g. +// +// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". +// FormatCountableNoun(5, "book", "books") returns "5 books". +static std::string FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { + return internal::StreamableToString(count) + " " + + (count == 1 ? singular_form : plural_form); +} + +// Formats the count of tests. +static std::string FormatTestCount(int test_count) { + return FormatCountableNoun(test_count, "test", "tests"); +} + +// Formats the count of test cases. +static std::string FormatTestCaseCount(int test_case_count) { + return FormatCountableNoun(test_case_count, "test case", "test cases"); +} + +// Converts a TestPartResult::Type enum to human-friendly string +// representation. Both kNonFatalFailure and kFatalFailure are translated +// to "Failure", as the user usually doesn't care about the difference +// between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResult::Type type) { + switch (type) { + case TestPartResult::kSuccess: + return "Success"; + + case TestPartResult::kNonFatalFailure: + case TestPartResult::kFatalFailure: +#ifdef _MSC_VER + return "error: "; +#else + return "Failure\n"; +#endif + default: + return "Unknown result type"; + } +} + +namespace internal { + +// Prints a TestPartResult to an std::string. +static std::string PrintTestPartResultToString( + const TestPartResult& test_part_result) { + return (Message() + << internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()) + << " " << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()).GetString(); +} + +// Prints a TestPartResult. +static void PrintTestPartResult(const TestPartResult& test_part_result) { + const std::string& result = + PrintTestPartResultToString(test_part_result); + printf("%s\n", result.c_str()); + fflush(stdout); + // If the test program runs in Visual Studio or a debugger, the + // following statements add the test part result message to the Output + // window such that the user can double-click on it to jump to the + // corresponding source code location; otherwise they do nothing. +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + // We don't call OutputDebugString*() on Windows Mobile, as printing + // to stdout is done by OutputDebugString() there already - we don't + // want the same message printed twice. + ::OutputDebugStringA(result.c_str()); + ::OutputDebugStringA("\n"); +#endif +} + +// class PrettyUnitTestResultPrinter + +enum GTestColor { + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW +}; + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns the character attribute for the given color. +WORD GetColorAttribute(GTestColor color) { + switch (color) { + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; + } +} + +#else + +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. +const char* GetAnsiColorCode(GTestColor color) { + switch (color) { + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + default: return NULL; + }; +} + +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns true iff Google Test should use colors in the output. +bool ShouldUseColor(bool stdout_is_tty) { + const char* const gtest_color = GTEST_FLAG(color).c_str(); + + if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { +#if GTEST_OS_WINDOWS + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return stdout_is_tty; +#else + // On non-Windows platforms, we rely on the TERM variable. + const char* const term = posix::GetEnv("TERM"); + const bool term_supports_color = + String::CStringEquals(term, "xterm") || + String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "screen") || + String::CStringEquals(term, "screen-256color") || + String::CStringEquals(term, "linux") || + String::CStringEquals(term, "cygwin"); + return stdout_is_tty && term_supports_color; +#endif // GTEST_OS_WINDOWS + } + + return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); + // We take "yes", "true", "t", and "1" as meaning "yes". If the + // value is neither one of these nor "auto", we treat it as "no" to + // be conservative. +} + +// Helpers for printing colored strings to stdout. Note that on Windows, we +// cannot simply emit special characters and have the terminal change colors. +// This routine must actually emit the characters rather than return a string +// that would be colored when printed, as can be done on Linux. +void ColoredPrintf(GTestColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS + const bool use_color = false; +#else + static const bool in_color_mode = + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + // The '!= 0' comparison is necessary to satisfy MSVC 7.1. + + if (!use_color) { + vprintf(fmt, args); + va_end(args); + return; + } + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, + GetColorAttribute(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + printf("\033[0;3%sm", GetAnsiColorCode(color)); + vprintf(fmt, args); + printf("\033[m"); // Resets the terminal to default. +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + va_end(args); +} + +// Text printed in Google Test's text output and --gunit_list_tests +// output to label the type parameter and value parameter for a test. +static const char kTypeParamLabel[] = "TypeParam"; +static const char kValueParamLabel[] = "GetParam()"; + +void PrintFullTestCommentIfPresent(const TestInfo& test_info) { + const char* const type_param = test_info.type_param(); + const char* const value_param = test_info.value_param(); + + if (type_param != NULL || value_param != NULL) { + printf(", where "); + if (type_param != NULL) { + printf("%s = %s", kTypeParamLabel, type_param); + if (value_param != NULL) + printf(" and "); + } + if (value_param != NULL) { + printf("%s = %s", kValueParamLabel, value_param); + } + } +} + +// This class implements the TestEventListener interface. +// +// Class PrettyUnitTestResultPrinter is copyable. +class PrettyUnitTestResultPrinter : public TestEventListener { + public: + PrettyUnitTestResultPrinter() {} + static void PrintTestName(const char * test_case, const char * test) { + printf("%s.%s", test_case, test); + } + + // The following methods override what's in the TestEventListener class. + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + + private: + static void PrintFailedTests(const UnitTest& unit_test); +}; + + // Fired before each iteration of tests starts. +void PrettyUnitTestResultPrinter::OnTestIterationStart( + const UnitTest& unit_test, int iteration) { + if (GTEST_FLAG(repeat) != 1) + printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); + + const char* const filter = GTEST_FLAG(filter).c_str(); + + // Prints the filter if it's not *. This reminds the user that some + // tests may be skipped. + if (!String::CStringEquals(filter, kUniversalFilter)) { + ColoredPrintf(COLOR_YELLOW, + "Note: %s filter = %s\n", GTEST_NAME_, filter); + } + + if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); + ColoredPrintf(COLOR_YELLOW, + "Note: This is test shard %d of %s.\n", + static_cast(shard_index) + 1, + internal::posix::GetEnv(kTestTotalShards)); + } + + if (GTEST_FLAG(shuffle)) { + ColoredPrintf(COLOR_YELLOW, + "Note: Randomizing tests' orders with a seed of %d .\n", + unit_test.random_seed()); + } + + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("Running %s from %s.\n", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { + const std::string counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_case.name()); + if (test_case.type_param() == NULL) { + printf("\n"); + } else { + printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_info.test_case_name(), test_info.name()); + printf("\n"); + fflush(stdout); +} + +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + // If the test part succeeded, we don't need to do anything. + if (result.type() == TestPartResult::kSuccess) + return; + + // Print failure message from the assertion (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + } + PrintTestName(test_info.test_case_name(), test_info.name()); + if (test_info.result()->Failed()) + PrintFullTestCommentIfPresent(test_info); + + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", internal::StreamableToString( + test_info.result()->elapsed_time()).c_str()); + } else { + printf("\n"); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { + if (!GTEST_FLAG(print_time)) return; + + const std::string counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", + counts.c_str(), test_case.name(), + internal::StreamableToString(test_case.elapsed_time()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + fflush(stdout); +} + +// Internal helper for printing the list of failed tests. +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { + const int failed_test_count = unit_test.failed_test_count(); + if (failed_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_case.total_test_count(); ++j) { + const TestInfo& test_info = *test_case.GetTestInfo(j); + if (!test_info.should_run() || test_info.result()->Passed()) { + continue; + } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s.%s", test_case.name(), test_info.name()); + PrintFullTestCommentIfPresent(test_info); + printf("\n"); + } + } +} + +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("%s from %s ran.", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(unit_test.elapsed_time()).c_str()); + } + printf("\n"); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + + int num_failures = unit_test.failed_test_count(); + if (!unit_test.Passed()) { + const int failed_test_count = unit_test.failed_test_count(); + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); + PrintFailedTests(unit_test); + printf("\n%2d FAILED %s\n", num_failures, + num_failures == 1 ? "TEST" : "TESTS"); + } + + int num_disabled = unit_test.reportable_disabled_test_count(); + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { + if (!num_failures) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(COLOR_YELLOW, + " YOU HAVE %d DISABLED %s\n\n", + num_disabled, + num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End PrettyUnitTestResultPrinter + +// class TestEventRepeater +// +// This class forwards events to other event listeners. +class TestEventRepeater : public TestEventListener { + public: + TestEventRepeater() : forwarding_enabled_(true) {} + virtual ~TestEventRepeater(); + void Append(TestEventListener *listener); + TestEventListener* Release(TestEventListener* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } + + virtual void OnTestProgramStart(const UnitTest& unit_test); + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& unit_test); + + private: + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + std::vector listeners_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); +}; + +TestEventRepeater::~TestEventRepeater() { + ForEach(listeners_, Delete); +} + +void TestEventRepeater::Append(TestEventListener *listener) { + listeners_.push_back(listener); +} + +// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { + for (size_t i = 0; i < listeners_.size(); ++i) { + if (listeners_[i] == listener) { + listeners_.erase(listeners_.begin() + i); + return listener; + } + } + + return NULL; +} + +// Since most methods are very similar, use macros to reduce boilerplate. +// This defines a member that forwards the call to all listeners. +#define GTEST_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} +// This defines a member that forwards the call to all listeners in reverse +// order. +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} + +GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) + +#undef GTEST_REPEATER_METHOD_ +#undef GTEST_REVERSE_REPEATER_METHOD_ + +void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnTestIterationStart(unit_test, iteration); + } + } +} + +void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { + listeners_[i]->OnTestIterationEnd(unit_test, iteration); + } + } +} + +// End TestEventRepeater + +// This class generates an XML output file. +class XmlUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit XmlUnitTestResultPrinter(const char* output_file); + + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + private: + // Is c a whitespace character that is normalized to a space character + // when it appears in an XML attribute value? + static bool IsNormalizableWhitespace(char c) { + return c == 0x9 || c == 0xA || c == 0xD; + } + + // May c appear in a well-formed XML document? + static bool IsValidXmlCharacter(char c) { + return IsNormalizableWhitespace(c) || c >= 0x20; + } + + // Returns an XML-escaped copy of the input string str. If + // is_attribute is true, the text is meant to appear as an attribute + // value, and normalizable whitespace is preserved by replacing it + // with character references. + static std::string EscapeXml(const std::string& str, bool is_attribute); + + // Returns the given string with all characters invalid in XML removed. + static std::string RemoveInvalidXmlCharacters(const std::string& str); + + // Convenience wrapper around EscapeXml when str is an attribute value. + static std::string EscapeXmlAttribute(const std::string& str) { + return EscapeXml(str, true); + } + + // Convenience wrapper around EscapeXml when str is not an attribute value. + static std::string EscapeXmlText(const char* str) { + return EscapeXml(str, false); + } + + // Verifies that the given attribute belongs to the given element and + // streams the attribute as XML. + static void OutputXmlAttribute(std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value); + + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. + static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + + // Streams an XML representation of a TestInfo object. + static void OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints an XML representation of a TestCase object + static void PrintXmlTestCase(::std::ostream* stream, + const TestCase& test_case); + + // Prints an XML summary of unit_test to output stream out. + static void PrintXmlUnitTest(::std::ostream* stream, + const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as space + // delimited XML attributes based on the property key="value" pairs. + // When the std::string is not empty, it includes a space at the beginning, + // to delimit this attribute from prior attributes. + static std::string TestPropertiesAsXmlAttributes(const TestResult& result); + + // The output file. + const std::string output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); +}; + +// Creates a new XmlUnitTestResultPrinter. +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.c_str() == NULL || output_file_.empty()) { + fprintf(stderr, "XML output file may not be null\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +// Called after the unit test ends. +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* xmlout = NULL; + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + xmlout = posix::FOpen(output_file_.c_str(), "w"); + } + if (xmlout == NULL) { + // TODO(wan): report the reason of the failure. + // + // We don't do it for now as: + // + // 1. There is no urgent need for it. + // 2. It's a bit involved to make the errno variable thread-safe on + // all three operating systems (Linux, Windows, and Mac OS). + // 3. To interpret the meaning of errno in a thread-safe way, + // we need the strerror_r() function, which is not available on + // Windows. + fprintf(stderr, + "Unable to open file \"%s\"\n", + output_file_.c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + std::stringstream stream; + PrintXmlUnitTest(&stream, unit_test); + fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); + fclose(xmlout); +} + +// Returns an XML-escaped copy of the input string str. If is_attribute +// is true, the text is meant to appear as an attribute value, and +// normalizable whitespace is preserved by replacing it with character +// references. +// +// Invalid XML characters in str, if any, are stripped from the output. +// It is expected that most, if not all, of the text processed by this +// module will consist of ordinary English text. +// If this module is ever modified to produce version 1.1 XML output, +// most invalid characters can be retained using character references. +// TODO(wan): It might be nice to have a minimally invasive, human-readable +// escaping scheme for invalid characters, rather than dropping them. +std::string XmlUnitTestResultPrinter::EscapeXml( + const std::string& str, bool is_attribute) { + Message m; + + for (size_t i = 0; i < str.size(); ++i) { + const char ch = str[i]; + switch (ch) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(ch)) { + if (is_attribute && IsNormalizableWhitespace(ch)) + m << "&#x" << String::FormatByte(static_cast(ch)) + << ";"; + else + m << ch; + } + break; + } + } + + return m.GetString(); +} + +// Returns the given string with all characters invalid in XML removed. +// Currently invalid characters are dropped from the string. An +// alternative is to replace them with certain characters such as . or ?. +std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( + const std::string& str) { + std::string output; + output.reserve(str.size()); + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) + if (IsValidXmlCharacter(*it)) + output.push_back(*it); + + return output; +} + +// The following routines generate an XML representation of a UnitTest +// object. +// +// This is how Google Test concepts map to the DTD: +// +// <-- corresponds to a UnitTest object +// <-- corresponds to a TestCase object +// <-- corresponds to a TestInfo object +// ... +// ... +// ... +// <-- individual assertion failures +// +// +// + +// Formats the given time in milliseconds as seconds. +std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { + ::std::stringstream ss; + ss << ms/1000.0; + return ss.str(); +} + +// Converts the given epoch time in milliseconds to a date string in the ISO +// 8601 format, without the timezone information. +std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { + // Using non-reentrant version as localtime_r is not portable. + time_t seconds = static_cast(ms / 1000); +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996 + // (function or variable may be unsafe). + const struct tm* const time_struct = localtime(&seconds); // NOLINT +# pragma warning(pop) // Restores the warning state again. +#else + const struct tm* const time_struct = localtime(&seconds); // NOLINT +#endif + if (time_struct == NULL) + return ""; // Invalid ms value + + // YYYY-MM-DDThh:mm:ss + return StreamableToString(time_struct->tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct->tm_mday) + "T" + + String::FormatIntWidth2(time_struct->tm_hour) + ":" + + String::FormatIntWidth2(time_struct->tm_min) + ":" + + String::FormatIntWidth2(time_struct->tm_sec); +} + +// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, + const char* data) { + const char* segment = data; + *stream << ""); + if (next_segment != NULL) { + stream->write( + segment, static_cast(next_segment - segment)); + *stream << "]]>]]>"); + } else { + *stream << segment; + break; + } + } + *stream << "]]>"; +} + +void XmlUnitTestResultPrinter::OutputXmlAttribute( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value) { + const std::vector& allowed_names = + GetReservedAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Attribute " << name << " is not allowed for element <" << element_name + << ">."; + + *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; +} + +// Prints an XML representation of a TestInfo object. +// TODO(wan): There is also value in printing properties with the plain printer. +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + const std::string kTestcase = "testcase"; + + *stream << " \n"; + } + const string location = internal::FormatCompilerIndependentFileLocation( + part.file_name(), part.line_number()); + const string summary = location + "\n" + part.summary(); + *stream << " "; + const string detail = location + "\n" + part.message(); + OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); + *stream << "\n"; + } + } + + if (failures == 0) + *stream << " />\n"; + else + *stream << " \n"; +} + +// Prints an XML representation of a TestCase object +void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, + const TestCase& test_case) { + const std::string kTestsuite = "testsuite"; + *stream << " <" << kTestsuite; + OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); + OutputXmlAttribute(stream, kTestsuite, "tests", + StreamableToString(test_case.reportable_test_count())); + OutputXmlAttribute(stream, kTestsuite, "failures", + StreamableToString(test_case.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuite, "disabled", + StreamableToString(test_case.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) + << ">\n"; + + for (int i = 0; i < test_case.total_test_count(); ++i) { + if (test_case.GetTestInfo(i)->is_reportable()) + OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + } + *stream << " \n"; +} + +// Prints an XML summary of unit_test to output stream out. +void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, + const UnitTest& unit_test) { + const std::string kTestsuites = "testsuites"; + + *stream << "\n"; + *stream << "<" << kTestsuites; + + OutputXmlAttribute(stream, kTestsuites, "tests", + StreamableToString(unit_test.reportable_test_count())); + OutputXmlAttribute(stream, kTestsuites, "failures", + StreamableToString(unit_test.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuites, "disabled", + StreamableToString(unit_test.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuites, "errors", "0"); + OutputXmlAttribute( + stream, kTestsuites, "timestamp", + FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); + OutputXmlAttribute(stream, kTestsuites, "time", + FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); + + if (GTEST_FLAG(shuffle)) { + OutputXmlAttribute(stream, kTestsuites, "random_seed", + StreamableToString(unit_test.random_seed())); + } + + *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); + + OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); + *stream << ">\n"; + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + if (unit_test.GetTestCase(i)->reportable_test_count() > 0) + PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); + } + *stream << "\n"; +} + +// Produces a string representing the test properties in a result as space +// delimited XML attributes based on the property key="value" pairs. +std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( + const TestResult& result) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << " " << property.key() << "=" + << "\"" << EscapeXmlAttribute(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End XmlUnitTestResultPrinter + +#if GTEST_CAN_STREAM_RESULTS_ + +// Checks if str contains '=', '&', '%' or '\n' characters. If yes, +// replaces them by "%xx" where xx is their hexadecimal value. For +// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) +// in both time and space -- important as the input str may contain an +// arbitrarily long test failure message and stack trace. +string StreamingListener::UrlEncode(const char* str) { + string result; + result.reserve(strlen(str) + 1); + for (char ch = *str; ch != '\0'; ch = *++str) { + switch (ch) { + case '%': + case '=': + case '&': + case '\n': + result.append("%" + String::FormatByte(static_cast(ch))); + break; + default: + result.push_back(ch); + break; + } + } + return result; +} + +void StreamingListener::SocketWriter::MakeConnection() { + GTEST_CHECK_(sockfd_ == -1) + << "MakeConnection() can't be called when there is already a connection."; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. + hints.ai_socktype = SOCK_STREAM; + addrinfo* servinfo = NULL; + + // Use the getaddrinfo() to get a linked list of IP addresses for + // the given host name. + const int error_num = getaddrinfo( + host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); + if (error_num != 0) { + GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " + << gai_strerror(error_num); + } + + // Loop through all the results and connect to the first we can. + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + cur_addr = cur_addr->ai_next) { + sockfd_ = socket( + cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); + if (sockfd_ != -1) { + // Connect the client socket to the server socket. + if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { + close(sockfd_); + sockfd_ = -1; + } + } + } + + freeaddrinfo(servinfo); // all done with this structure + + if (sockfd_ == -1) { + GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " + << host_name_ << ":" << port_num_; + } +} + +// End of class Streaming Listener +#endif // GTEST_CAN_STREAM_RESULTS__ + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message = message.GetString(); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +ScopedTrace::~ScopedTrace() + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + UnitTest::GetInstance()->PopGTestTrace(); +} + + +// class OsStackTraceGetter + +// Returns the current OS stack trace as an std::string. Parameters: +// +// max_depth - the maximum number of stack frames to be included +// in the trace. +// skip_count - the number of top frames to be skipped; doesn't count +// against max_depth. +// +string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, + int /* skip_count */) + GTEST_LOCK_EXCLUDED_(mutex_) { + return ""; +} + +void OsStackTraceGetter::UponLeavingGTest() + GTEST_LOCK_EXCLUDED_(mutex_) { +} + +const char* const +OsStackTraceGetter::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; + +// A helper class that creates the premature-exit file in its +// constructor and deletes the file in its destructor. +class ScopedPrematureExitFile { + public: + explicit ScopedPrematureExitFile(const char* premature_exit_filepath) + : premature_exit_filepath_(premature_exit_filepath) { + // If a path to the premature-exit file is specified... + if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { + // create the file with a single "0" character in it. I/O + // errors are ignored as there's nothing better we can do and we + // don't want to fail the test because of this. + FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); + fwrite("0", 1, 1, pfile); + fclose(pfile); + } + } + + ~ScopedPrematureExitFile() { + if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { + remove(premature_exit_filepath_); + } + } + + private: + const char* const premature_exit_filepath_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); +}; + +} // namespace internal + +// class TestEventListeners + +TestEventListeners::TestEventListeners() + : repeater_(new internal::TestEventRepeater()), + default_result_printer_(NULL), + default_xml_generator_(NULL) { +} + +TestEventListeners::~TestEventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void TestEventListeners::Append(TestEventListener* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +TestEventListener* TestEventListeners::Release(TestEventListener* listener) { + if (listener == default_result_printer_) + default_result_printer_ = NULL; + else if (listener == default_xml_generator_) + default_xml_generator_ = NULL; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the TestEventListener events to all +// subscribers. +TestEventListener* TestEventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool TestEventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void TestEventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + +// class UnitTest + +// Gets the singleton UnitTest object. The first time this method is +// called, a UnitTest object is constructed and returned. Consecutive +// calls will return the same object. +// +// We don't protect this under mutex_ as a user is not supposed to +// call this before main() starts, from which point on the return +// value will never change. +UnitTest* UnitTest::GetInstance() { + // When compiled with MSVC 7.1 in optimized mode, destroying the + // UnitTest object upon exiting the program messes up the exit code, + // causing successful tests to appear failed. We have to use a + // different implementation in this case to bypass the compiler bug. + // This implementation makes the compiler happy, at the cost of + // leaking the UnitTest object. + + // CodeGear C++Builder insists on a public destructor for the + // default implementation. Use this implementation to keep good OO + // design with private destructor. + +#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) + static UnitTest* const instance = new UnitTest; + return instance; +#else + static UnitTest instance; + return &instance; +#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +} + +// Gets the number of successful test cases. +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_case_count(); +} + +// Gets the number of failed test cases. +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_case_count(); +} + +// Gets the number of all test cases. +int UnitTest::total_test_case_count() const { + return impl()->total_test_case_count(); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTest::test_case_to_run_count() const { + return impl()->test_case_to_run_count(); +} + +// Gets the number of successful tests. +int UnitTest::successful_test_count() const { + return impl()->successful_test_count(); +} + +// Gets the number of failed tests. +int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } + +// Gets the number of disabled tests that will be reported in the XML report. +int UnitTest::reportable_disabled_test_count() const { + return impl()->reportable_disabled_test_count(); +} + +// Gets the number of disabled tests. +int UnitTest::disabled_test_count() const { + return impl()->disabled_test_count(); +} + +// Gets the number of tests to be printed in the XML report. +int UnitTest::reportable_test_count() const { + return impl()->reportable_test_count(); +} + +// Gets the number of all tests. +int UnitTest::total_test_count() const { return impl()->total_test_count(); } + +// Gets the number of tests that should run. +int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } + +// Gets the time of the test program start, in ms from the start of the +// UNIX epoch. +internal::TimeInMillis UnitTest::start_timestamp() const { + return impl()->start_timestamp(); +} + +// Gets the elapsed time, in milliseconds. +internal::TimeInMillis UnitTest::elapsed_time() const { + return impl()->elapsed_time(); +} + +// Returns true iff the unit test passed (i.e. all test cases passed). +bool UnitTest::Passed() const { return impl()->Passed(); } + +// Returns true iff the unit test failed (i.e. some test case failed +// or something outside of all tests failed). +bool UnitTest::Failed() const { return impl()->Failed(); } + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +const TestCase* UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} + +// Returns the TestResult containing information on test failures and +// properties logged outside of individual test cases. +const TestResult& UnitTest::ad_hoc_test_result() const { + return *impl()->ad_hoc_test_result(); +} + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +TestCase* UnitTest::GetMutableTestCase(int i) { + return impl()->GetMutableTestCase(i); +} + +// Returns the list of event listeners that can be used to track events +// inside Google Test. +TestEventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + +// Registers and returns a global test environment. When a test +// program is run, all global test environments will be set-up in the +// order they were registered. After all tests in the program have +// finished, all global test environments will be torn-down in the +// *reverse* order they were registered. +// +// The UnitTest object takes ownership of the given environment. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +Environment* UnitTest::AddEnvironment(Environment* env) { + if (env == NULL) { + return NULL; + } + + impl_->environments().push_back(env); + return env; +} + +// Adds a TestPartResult to the current TestResult object. All Google Test +// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call +// this to report their results. The user code should use the +// assertion macros instead of calling this directly. +void UnitTest::AddTestPartResult( + TestPartResult::Type result_type, + const char* file_name, + int line_number, + const std::string& message, + const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { + Message msg; + msg << message; + + internal::MutexLock lock(&mutex_); + if (impl_->gtest_trace_stack().size() > 0) { + msg << "\n" << GTEST_NAME_ << " trace:"; + + for (int i = static_cast(impl_->gtest_trace_stack().size()); + i > 0; --i) { + const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; + msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) + << " " << trace.message; + } + } + + if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + msg << internal::kStackTraceMarker << os_stack_trace; + } + + const TestPartResult result = + TestPartResult(result_type, file_name, line_number, + msg.GetString().c_str()); + impl_->GetTestPartResultReporterForCurrentThread()-> + ReportTestPartResult(result); + + if (result_type != TestPartResult::kSuccess) { + // gtest_break_on_failure takes precedence over + // gtest_throw_on_failure. This allows a user to set the latter + // in the code (perhaps in order to use Google Test assertions + // with another testing framework) and specify the former on the + // command line for debugging. + if (GTEST_FLAG(break_on_failure)) { +#if GTEST_OS_WINDOWS + // Using DebugBreak on Windows allows gtest to still break into a debugger + // when a failure happens and both the --gtest_break_on_failure and + // the --gtest_catch_exceptions flags are specified. + DebugBreak(); +#else + // Dereference NULL through a volatile pointer to prevent the compiler + // from removing. We use this rather than abort() or __builtin_trap() for + // portability: Symbian doesn't implement abort() well, and some debuggers + // don't correctly trap abort(). + *static_cast(NULL) = 1; +#endif // GTEST_OS_WINDOWS + } else if (GTEST_FLAG(throw_on_failure)) { +#if GTEST_HAS_EXCEPTIONS + throw internal::GoogleTestFailureException(result); +#else + // We cannot call abort() as it generates a pop-up in debug mode + // that cannot be suppressed in VC 7.1 or below. + exit(1); +#endif + } + } +} + +// Adds a TestProperty to the current TestResult object when invoked from +// inside a test, to current TestCase's ad_hoc_test_result_ when invoked +// from SetUpTestCase or TearDownTestCase, or to the global property set +// when invoked elsewhere. If the result already contains a property with +// the same key, the value will be updated. +void UnitTest::RecordProperty(const std::string& key, + const std::string& value) { + impl_->RecordProperty(TestProperty(key, value)); +} + +// Runs all tests in this UnitTest object and prints the result. +// Returns 0 if successful, or 1 otherwise. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +int UnitTest::Run() { + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).length() > 0; + + // Google Test implements this protocol for catching that a test + // program exits before returning control to Google Test: + // + // 1. Upon start, Google Test creates a file whose absolute path + // is specified by the environment variable + // TEST_PREMATURE_EXIT_FILE. + // 2. When Google Test has finished its work, it deletes the file. + // + // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before + // running a Google-Test-based test program and check the existence + // of the file at the end of the test execution to see if it has + // exited prematurely. + + // If we are in the child process of a death test, don't + // create/delete the premature exit file, as doing so is unnecessary + // and will confuse the parent process. Otherwise, create/delete + // the file upon entering/leaving this function. If the program + // somehow exits before this function has a chance to return, the + // premature-exit file will be left undeleted, causing a test runner + // that understands the premature-exit-file protocol to report the + // test as having failed. + const internal::ScopedPrematureExitFile premature_exit_file( + in_death_test_child_process ? + NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); + + // Captures the value of GTEST_FLAG(catch_exceptions). This value will be + // used for the duration of the program. + impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); + +#if GTEST_HAS_SEH + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected. + if (impl()->catch_exceptions() || in_death_test_child_process) { +# if !GTEST_OS_WINDOWS_MOBILE + // SetErrorMode doesn't exist on CE. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +# endif // !GTEST_OS_WINDOWS_MOBILE + +# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); +# endif + +# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. + // + // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. + // Users of prior VC versions shall suffer the agony and pain of + // clicking through the countless debug dialogs. + // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // debug mode when compiled with VC 7.1 or lower. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +# endif + } +#endif // GTEST_HAS_SEH + + return internal::HandleExceptionsInMethodIfSupported( + impl(), + &internal::UnitTestImpl::RunAllTests, + "auxiliary test code (environments or event listeners)") ? 0 : 1; +} + +// Returns the working directory when the first TEST() or TEST_F() was +// executed. +const char* UnitTest::original_working_dir() const { + return impl_->original_working_dir_.c_str(); +} + +// Returns the TestCase object for the test that's currently running, +// or NULL if no test is running. +const TestCase* UnitTest::current_test_case() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_case(); +} + +// Returns the TestInfo object for the test that's currently running, +// or NULL if no test is running. +const TestInfo* UnitTest::current_test_info() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_info(); +} + +// Returns the random seed used at the start of the current test run. +int UnitTest::random_seed() const { return impl_->random_seed(); } + +#if GTEST_HAS_PARAM_TEST +// Returns ParameterizedTestCaseRegistry object used to keep track of +// value-parameterized tests and instantiate and register them. +internal::ParameterizedTestCaseRegistry& + UnitTest::parameterized_test_registry() + GTEST_LOCK_EXCLUDED_(mutex_) { + return impl_->parameterized_test_registry(); +} +#endif // GTEST_HAS_PARAM_TEST + +// Creates an empty UnitTest. +UnitTest::UnitTest() { + impl_ = new internal::UnitTestImpl(this); +} + +// Destructor of UnitTest. +UnitTest::~UnitTest() { + delete impl_; +} + +// Pushes a trace defined by SCOPED_TRACE() on to the per-thread +// Google Test trace stack. +void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().push_back(trace); +} + +// Pops a trace from the per-thread Google Test trace stack. +void UnitTest::PopGTestTrace() + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().pop_back(); +} + +namespace internal { + +UnitTestImpl::UnitTestImpl(UnitTest* parent) + : parent_(parent), +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4355) // Temporarily disables warning 4355 + // (using this in initializer). + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +# pragma warning(pop) // Restores the warning state again. +#else + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#endif // _MSC_VER + global_test_part_result_repoter_( + &default_global_test_part_result_reporter_), + per_thread_test_part_result_reporter_( + &default_per_thread_test_part_result_reporter_), +#if GTEST_HAS_PARAM_TEST + parameterized_test_registry_(), + parameterized_tests_registered_(false), +#endif // GTEST_HAS_PARAM_TEST + last_death_test_case_(-1), + current_test_case_(NULL), + current_test_info_(NULL), + ad_hoc_test_result_(), + os_stack_trace_getter_(NULL), + post_flag_parse_init_performed_(false), + random_seed_(0), // Will be overridden by the flag before first use. + random_(0), // Will be reseeded before first use. + start_timestamp_(0), + elapsed_time_(0), +#if GTEST_HAS_DEATH_TEST + death_test_factory_(new DefaultDeathTestFactory), +#endif + // Will be overridden by the flag before first use. + catch_exceptions_(false) { + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); +} + +UnitTestImpl::~UnitTestImpl() { + // Deletes every TestCase. + ForEach(test_cases_, internal::Delete); + + // Deletes every Environment. + ForEach(environments_, internal::Delete); + + delete os_stack_trace_getter_; +} + +// Adds a TestProperty to the current TestResult object when invoked in a +// context of a test, to current test case's ad_hoc_test_result when invoke +// from SetUpTestCase/TearDownTestCase, or to the global property set +// otherwise. If the result already contains a property with the same key, +// the value will be updated. +void UnitTestImpl::RecordProperty(const TestProperty& test_property) { + std::string xml_element; + TestResult* test_result; // TestResult appropriate for property recording. + + if (current_test_info_ != NULL) { + xml_element = "testcase"; + test_result = &(current_test_info_->result_); + } else if (current_test_case_ != NULL) { + xml_element = "testsuite"; + test_result = &(current_test_case_->ad_hoc_test_result_); + } else { + xml_element = "testsuites"; + test_result = &ad_hoc_test_result_; + } + test_result->RecordProperty(xml_element, test_property); +} + +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != NULL) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const std::string& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } +} + +#if GTEST_CAN_STREAM_RESULTS_ +// Initializes event listeners for streaming test results in string form. +// Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureStreamingOutput() { + const std::string& target = GTEST_FLAG(stream_result_to); + if (!target.empty()) { + const size_t pos = target.find(':'); + if (pos != std::string::npos) { + listeners()->Append(new StreamingListener(target.substr(0, pos), + target.substr(pos+1))); + } else { + printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", + target.c_str()); + fflush(stdout); + } + } +} +#endif // GTEST_CAN_STREAM_RESULTS_ + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Configures listeners for streaming test results to the specified server. + ConfigureStreamingOutput(); +#endif // GTEST_CAN_STREAM_RESULTS_ + } +} + +// A predicate that checks the name of a TestCase against a known +// value. +// +// This is used for implementation of the UnitTest class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestCaseNameIs is copyable. +class TestCaseNameIs { + public: + // Constructor. + explicit TestCaseNameIs(const std::string& name) + : name_(name) {} + + // Returns true iff the name of test_case matches name_. + bool operator()(const TestCase* test_case) const { + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + } + + private: + std::string name_; +}; + +// Finds and returns a TestCase with the given name. If one doesn't +// exist, creates one and returns it. It's the CALLER'S +// RESPONSIBILITY to ensure that this function is only called WHEN THE +// TESTS ARE NOT SHUFFLED. +// +// Arguments: +// +// test_case_name: name of the test case +// type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) { + // Can we find a TestCase with the given name? + const std::vector::const_iterator test_case = + std::find_if(test_cases_.begin(), test_cases_.end(), + TestCaseNameIs(test_case_name)); + + if (test_case != test_cases_.end()) + return *test_case; + + // No. Let's create one. + TestCase* const new_test_case = + new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); + + // Is this a death test case? + if (internal::UnitTestOptions::MatchesFilter(test_case_name, + kDeathTestCaseFilter)) { + // Yes. Inserts the test case after the last death test case + // defined so far. This only works when the test cases haven't + // been shuffled. Otherwise we may end up running a death test + // after a non-death test. + ++last_death_test_case_; + test_cases_.insert(test_cases_.begin() + last_death_test_case_, + new_test_case); + } else { + // No. Appends to the end of the list. + test_cases_.push_back(new_test_case); + } + + test_case_indices_.push_back(static_cast(test_case_indices_.size())); + return new_test_case; +} + +// Helpers for setting up / tearing down the given environment. They +// are for use in the ForEach() function. +static void SetUpEnvironment(Environment* env) { env->SetUp(); } +static void TearDownEnvironment(Environment* env) { env->TearDown(); } + +// Runs all tests in this UnitTest object, prints the result, and +// returns true if all tests are successful. If any exception is +// thrown during a test, the test is considered to be failed, but the +// rest of the tests will still be run. +// +// When parameterized tests are enabled, it expands and registers +// parameterized tests first in RegisterParameterizedTests(). +// All other functions called from RunAllTests() may safely assume that +// parameterized tests are ready to be counted and run. +bool UnitTestImpl::RunAllTests() { + // Makes sure InitGoogleTest() was called. + if (!GTestIsInitialized()) { + printf("%s", + "\nThis test program did NOT call ::testing::InitGoogleTest " + "before calling RUN_ALL_TESTS(). Please fix it.\n"); + return false; + } + + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return true; + + // Repeats the call to the post-flag parsing initialization in case the + // user didn't call InitGoogleTest. + PostFlagParsingInit(); + + // Even if sharding is not on, test runners may want to use the + // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding + // protocol. + internal::WriteToShardStatusFileIfNeeded(); + + // True iff we are in a subprocess for running a thread-safe-style + // death test. + bool in_subprocess_for_death_test = false; + +#if GTEST_HAS_DEATH_TEST + in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +#endif // GTEST_HAS_DEATH_TEST + + const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, + in_subprocess_for_death_test); + + // Compares the full test names with the filter to decide which + // tests to run. + const bool has_tests_to_run = FilterTests(should_shard + ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; + + // Lists the tests and exits if the --gtest_list_tests flag was specified. + if (GTEST_FLAG(list_tests)) { + // This must be called *after* FilterTests() has been called. + ListTestsMatchingFilter(); + return true; + } + + random_seed_ = GTEST_FLAG(shuffle) ? + GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + + // True iff at least one test has failed. + bool failed = false; + + TestEventListener* repeater = listeners()->repeater(); + + start_timestamp_ = GetTimeInMillis(); + repeater->OnTestProgramStart(*parent_); + + // How many times to repeat the tests? We don't want to repeat them + // when we are inside the subprocess of a death test. + const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); + // Repeats forever if the repeat count is negative. + const bool forever = repeat < 0; + for (int i = 0; forever || i != repeat; i++) { + // We want to preserve failures generated by ad-hoc test + // assertions executed before RUN_ALL_TESTS(). + ClearNonAdHocTestResult(); + + const TimeInMillis start = GetTimeInMillis(); + + // Shuffles test cases and tests if requested. + if (has_tests_to_run && GTEST_FLAG(shuffle)) { + random()->Reseed(random_seed_); + // This should be done before calling OnTestIterationStart(), + // such that a test event listener can see the actual test order + // in the event. + ShuffleTests(); + } + + // Tells the unit test event listeners that the tests are about to start. + repeater->OnTestIterationStart(*parent_, i); + + // Runs each test case if there is at least one test to run. + if (has_tests_to_run) { + // Sets up all environments beforehand. + repeater->OnEnvironmentsSetUpStart(*parent_); + ForEach(environments_, SetUpEnvironment); + repeater->OnEnvironmentsSetUpEnd(*parent_); + + // Runs the tests only if there was no fatal failure during global + // set-up. + if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_case_count(); + test_index++) { + GetMutableTestCase(test_index)->Run(); + } + } + + // Tears down all environments in reverse order afterwards. + repeater->OnEnvironmentsTearDownStart(*parent_); + std::for_each(environments_.rbegin(), environments_.rend(), + TearDownEnvironment); + repeater->OnEnvironmentsTearDownEnd(*parent_); + } + + elapsed_time_ = GetTimeInMillis() - start; + + // Tells the unit test event listener that the tests have just finished. + repeater->OnTestIterationEnd(*parent_, i); + + // Gets the result and clears it. + if (!Passed()) { + failed = true; + } + + // Restores the original test order after the iteration. This + // allows the user to quickly repro a failure that happens in the + // N-th iteration without repeating the first (N - 1) iterations. + // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in + // case the user somehow changes the value of the flag somewhere + // (it's always safe to unshuffle the tests). + UnshuffleTests(); + + if (GTEST_FLAG(shuffle)) { + // Picks a new random seed for each iteration. + random_seed_ = GetNextRandomSeed(random_seed_); + } + } + + repeater->OnTestProgramEnd(*parent_); + + return !failed; +} + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded() { + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); + if (test_shard_file != NULL) { + FILE* const file = posix::FOpen(test_shard_file, "w"); + if (file == NULL) { + ColoredPrintf(COLOR_RED, + "Could not write to the test shard status file \"%s\" " + "specified by the %s environment variable.\n", + test_shard_file, kTestShardStatusFile); + fflush(stdout); + exit(EXIT_FAILURE); + } + fclose(file); + } +} + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (i.e., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_env, + const char* shard_index_env, + bool in_subprocess_for_death_test) { + if (in_subprocess_for_death_test) { + return false; + } + + const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + + if (total_shards == -1 && shard_index == -1) { + return false; + } else if (total_shards == -1 && shard_index != -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (total_shards != -1 && shard_index == -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (shard_index < 0 || shard_index >= total_shards) { + const Message msg = Message() + << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } + + return total_shards > 1; +} + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error +// and aborts. +Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { + const char* str_val = posix::GetEnv(var); + if (str_val == NULL) { + return default_val; + } + + Int32 result; + if (!ParseInt32(Message() << "The value of environment variable " << var, + str_val, &result)) { + exit(EXIT_FAILURE); + } + return result; +} + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { + return (test_id % total_shards) == shard_index; +} + +// Compares the name of each test with the user-specified filter to +// decide whether the test should be run, then records the result in +// each TestCase and TestInfo object. +// If shard_tests == true, further filters tests based on sharding +// variables in the environment - see +// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. +// Returns the number of tests that should run. +int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { + const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + + // num_runnable_tests are the number of tests that will + // run across all shards (i.e., match filter and are not disabled). + // num_selected_tests are the number of tests to be run on + // this shard. + int num_runnable_tests = 0; + int num_selected_tests = 0; + for (size_t i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_[i]; + const std::string &test_case_name = test_case->name(); + test_case->set_should_run(false); + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list()[j]; + const std::string test_name(test_info->name()); + // A test is disabled if test case name or test name matches + // kDisableTestFilter. + const bool is_disabled = + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); + test_info->is_disabled_ = is_disabled; + + const bool matches_filter = + internal::UnitTestOptions::FilterMatchesTest(test_case_name, + test_name); + test_info->matches_filter_ = matches_filter; + + const bool is_runnable = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + matches_filter; + + const bool is_selected = is_runnable && + (shard_tests == IGNORE_SHARDING_PROTOCOL || + ShouldRunTestOnShard(total_shards, shard_index, + num_runnable_tests)); + + num_runnable_tests += is_runnable; + num_selected_tests += is_selected; + + test_info->should_run_ = is_selected; + test_case->set_should_run(test_case->should_run() || is_selected); + } + } + return num_selected_tests; +} + +// Prints the given C-string on a single line by replacing all '\n' +// characters with string "\\n". If the output takes more than +// max_length characters, only prints the first max_length characters +// and "...". +static void PrintOnOneLine(const char* str, int max_length) { + if (str != NULL) { + for (int i = 0; *str != '\0'; ++str) { + if (i >= max_length) { + printf("..."); + break; + } + if (*str == '\n') { + printf("\\n"); + i += 2; + } else { + printf("%c", *str); + ++i; + } + } + } +} + +// Prints the names of the tests matching the user-specified filter flag. +void UnitTestImpl::ListTestsMatchingFilter() { + // Print at most this many characters for each type/value parameter. + const int kMaxParamLength = 250; + + for (size_t i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_[i]; + bool printed_test_case_name = false; + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + const TestInfo* const test_info = + test_case->test_info_list()[j]; + if (test_info->matches_filter_) { + if (!printed_test_case_name) { + printed_test_case_name = true; + printf("%s.", test_case->name()); + if (test_case->type_param() != NULL) { + printf(" # %s = ", kTypeParamLabel); + // We print the type parameter on a single line to make + // the output easy to parse by a program. + PrintOnOneLine(test_case->type_param(), kMaxParamLength); + } + printf("\n"); + } + printf(" %s", test_info->name()); + if (test_info->value_param() != NULL) { + printf(" # %s = ", kValueParamLabel); + // We print the value parameter on a single line to make the + // output easy to parse by a program. + PrintOnOneLine(test_info->value_param(), kMaxParamLength); + } + printf("\n"); + } + } + } + fflush(stdout); +} + +// Sets the OS stack trace getter. +// +// Does nothing if the input and the current OS stack trace getter are +// the same; otherwise, deletes the old getter and makes the input the +// current getter. +void UnitTestImpl::set_os_stack_trace_getter( + OsStackTraceGetterInterface* getter) { + if (os_stack_trace_getter_ != getter) { + delete os_stack_trace_getter_; + os_stack_trace_getter_ = getter; + } +} + +// Returns the current OS stack trace getter if it is not NULL; +// otherwise, creates an OsStackTraceGetter, makes it the current +// getter, and returns it. +OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == NULL) { + os_stack_trace_getter_ = new OsStackTraceGetter; + } + + return os_stack_trace_getter_; +} + +// Returns the TestResult for the test that's currently running, or +// the TestResult for the ad hoc test if no test is running. +TestResult* UnitTestImpl::current_test_result() { + return current_test_info_ ? + &(current_test_info_->result_) : &ad_hoc_test_result_; +} + +// Shuffles all test cases, and the tests within each test case, +// making sure that death tests are still run first. +void UnitTestImpl::ShuffleTests() { + // Shuffles the death test cases. + ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + + // Shuffles the non-death test cases. + ShuffleRange(random(), last_death_test_case_ + 1, + static_cast(test_cases_.size()), &test_case_indices_); + + // Shuffles the tests inside each test case. + for (size_t i = 0; i < test_cases_.size(); i++) { + test_cases_[i]->ShuffleTests(random()); + } +} + +// Restores the test cases and tests to their order before the first shuffle. +void UnitTestImpl::UnshuffleTests() { + for (size_t i = 0; i < test_cases_.size(); i++) { + // Unshuffles the tests in each test case. + test_cases_[i]->UnshuffleTests(); + // Resets the index of each test case. + test_case_indices_[i] = static_cast(i); + } +} + +// Returns the current OS stack trace as an std::string. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to +// suppress unreachable code warnings. +namespace { +class ClassUniqueToAlwaysTrue {}; +} + +bool IsTrue(bool condition) { return condition; } + +bool AlwaysTrue() { +#if GTEST_HAS_EXCEPTIONS + // This condition is always false so AlwaysTrue() never actually throws, + // but it makes the compiler think that it may throw. + if (IsTrue(false)) + throw ClassUniqueToAlwaysTrue(); +#endif // GTEST_HAS_EXCEPTIONS + return true; +} + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +const char* ParseFlagValue(const char* str, + const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == NULL || flag == NULL) return NULL; + + // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. + const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return NULL; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true as long as it does +// not start with '0', 'f', or 'F'. +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + return ParseInt32(Message() << "The value of flag --" << flag, + value_str, value); +} + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, std::string* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// Determines whether a string has a prefix that Google Test uses for its +// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. +// If Google Test detects that a command line flag has its prefix but is not +// recognized, it will print its help message. Flags starting with +// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test +// internal flags and do not trigger the help message. +static bool HasGoogleTestFlagPrefix(const char* str) { + return (SkipPrefix("--", &str) || + SkipPrefix("-", &str) || + SkipPrefix("/", &str)) && + !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && + (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || + SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); +} + +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +// TODO(wan@google.com): Write tests for this once we add stdout +// capturing to Google Test. +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == NULL) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", std::string(str, p).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +"\n" +"Test Execution:\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" +" Randomize tests' orders on every iteration.\n" +" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" +" Random number seed to use for shuffling test orders (between 1 and\n" +" 99999, or 0 to use a seed based on the current time).\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" +" Don't print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate an XML report in the given directory or with the given file\n" +" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +#if GTEST_CAN_STREAM_RESULTS_ +" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" +" Stream test results to the given server.\n" +#endif // GTEST_CAN_STREAM_RESULTS_ +"\n" +"Assertion Behavior:\n" +#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" +" Set the default death test style.\n" +#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions.\n" +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" +" Do not report exceptions as test failures. Instead, allow them\n" +" to crash the program or throw a pop-up (on Windows).\n" +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "color=no@D or set\n" +"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. The type parameter CharType can be +// instantiated to either char or wchar_t. +template +void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { + for (int i = 1; i < *argc; i++) { + const std::string arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + using internal::ParseBoolFlag; + using internal::ParseInt32Flag; + using internal::ParseStringFlag; + + // Do we see a Google Test flag? + if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)) + ) { + // Yes. Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } +} + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + g_init_gtest_count++; + + // We don't want to run the initialization code twice. + if (g_init_gtest_count != 1) return; + + if (*argc <= 0) return; + + internal::g_executable_path = internal::StreamableToString(argv[0]); + +#if GTEST_HAS_DEATH_TEST + + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } + +#endif // GTEST_HAS_DEATH_TEST + + ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); +} + +} // namespace internal + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +void InitGoogleTest(int* argc, char** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleTest(int* argc, wchar_t** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +} // namespace testing +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) +// +// This file implements death tests. + + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_OS_MAC +# include +# endif // GTEST_OS_MAC + +# include +# include +# include + +# if GTEST_OS_LINUX +# include +# endif // GTEST_OS_LINUX + +# include + +# if GTEST_OS_WINDOWS +# include +# else +# include +# include +# endif // GTEST_OS_WINDOWS + +# if GTEST_OS_QNX +# include +# endif // GTEST_OS_QNX + +#endif // GTEST_HAS_DEATH_TEST + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +// Constants. + +// The default death test style. +static const char kDefaultDeathTestStyle[] = "fast"; + +GTEST_DEFINE_string_( + death_test_style, + internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), + "Indicates how to run a death test in a forked child process: " + "\"threadsafe\" (child process re-executes the test binary " + "from the beginning, running only the specific death test) or " + "\"fast\" (child process runs the death test immediately " + "after forking)."); + +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Ignored and always uses fork() on POSIX systems where clone() is not " + "implemented. Useful when running under valgrind or similar tools if " + "those do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + +namespace internal { +GTEST_DEFINE_string_( + internal_run_death_test, "", + "Indicates the file, line number, temporal index of " + "the single death test to run, and a file descriptor to " + "which a success code may be sent, all separated by " + "the '|' characters. This flag is specified if and only if the current " + "process is a sub-process launched for running a thread-safe " + "death test. FOR INTERNAL USE ONLY."); +} // namespace internal + +#if GTEST_HAS_DEATH_TEST + +namespace internal { + +// Valid only for fast death tests. Indicates the code is running in the +// child process of a fast style death test. +static bool g_in_fast_death_test_child = false; + +// Returns a Boolean value indicating whether the caller is currently +// executing in the context of the death test child process. Tools such as +// Valgrind heap checkers may need this to modify their behavior in death +// tests. IMPORTANT: This is an internal utility. Using it may break the +// implementation of death tests. User code MUST NOT use it. +bool InDeathTestChild() { +# if GTEST_OS_WINDOWS + + // On Windows, death tests are thread-safe regardless of the value of the + // death_test_style flag. + return !GTEST_FLAG(internal_run_death_test).empty(); + +# else + + if (GTEST_FLAG(death_test_style) == "threadsafe") + return !GTEST_FLAG(internal_run_death_test).empty(); + else + return g_in_fast_death_test_child; +#endif +} + +} // namespace internal + +// ExitedWithCode constructor. +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { +} + +// ExitedWithCode function-call operator. +bool ExitedWithCode::operator()(int exit_status) const { +# if GTEST_OS_WINDOWS + + return exit_status == exit_code_; + +# else + + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; + +# endif // GTEST_OS_WINDOWS +} + +# if !GTEST_OS_WINDOWS +// KilledBySignal constructor. +KilledBySignal::KilledBySignal(int signum) : signum_(signum) { +} + +// KilledBySignal function-call operator. +bool KilledBySignal::operator()(int exit_status) const { + return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; +} +# endif // !GTEST_OS_WINDOWS + +namespace internal { + +// Utilities needed for death tests. + +// Generates a textual description of a given exit code, in the format +// specified by wait(2). +static std::string ExitSummary(int exit_code) { + Message m; + +# if GTEST_OS_WINDOWS + + m << "Exited with exit status " << exit_code; + +# else + + if (WIFEXITED(exit_code)) { + m << "Exited with exit status " << WEXITSTATUS(exit_code); + } else if (WIFSIGNALED(exit_code)) { + m << "Terminated by signal " << WTERMSIG(exit_code); + } +# ifdef WCOREDUMP + if (WCOREDUMP(exit_code)) { + m << " (core dumped)"; + } +# endif +# endif // GTEST_OS_WINDOWS + + return m.GetString(); +} + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +bool ExitedUnsuccessfully(int exit_status) { + return !ExitedWithCode(0)(exit_status); +} + +# if !GTEST_OS_WINDOWS +// Generates a textual failure message when a death test finds more than +// one thread running, or cannot determine the number of threads, prior +// to executing the given statement. It is the responsibility of the +// caller not to pass a thread_count of 1. +static std::string DeathTestThreadWarning(size_t thread_count) { + Message msg; + msg << "Death tests use fork(), which is unsafe particularly" + << " in a threaded context. For this test, " << GTEST_NAME_ << " "; + if (thread_count == 0) + msg << "couldn't detect the number of threads."; + else + msg << "detected " << thread_count << " threads."; + return msg.GetString(); +} +# endif // !GTEST_OS_WINDOWS + +// Flag characters for reporting a death test that did not die. +static const char kDeathTestLived = 'L'; +static const char kDeathTestReturned = 'R'; +static const char kDeathTestThrew = 'T'; +static const char kDeathTestInternalError = 'I'; + +// An enumeration describing all of the possible ways that a death test can +// conclude. DIED means that the process died while executing the test +// code; LIVED means that process lived beyond the end of the test code; +// RETURNED means that the test statement attempted to execute a return +// statement, which is not allowed; THREW means that the test statement +// returned control by throwing an exception. IN_PROGRESS means the test +// has not yet concluded. +// TODO(vladl@google.com): Unify names and possibly values for +// AbortReason, DeathTestOutcome, and flag characters above. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; + +// Routine for aborting the program which is safe to call from an +// exec-style death test child process, in which case the error +// message is propagated back to the parent process. Otherwise, the +// message is simply printed to stderr. In either case, the program +// then exits with status 1. +void DeathTestAbort(const std::string& message) { + // On a POSIX system, this function may be called from a threadsafe-style + // death test child process, which operates on a very small stack. Use + // the heap for any additional non-minuscule memory requirements. + const InternalRunDeathTestFlag* const flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + if (flag != NULL) { + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); + fputc(kDeathTestInternalError, parent); + fprintf(parent, "%s", message.c_str()); + fflush(parent); + _exit(1); + } else { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); + posix::Abort(); + } +} + +// A replacement for CHECK that calls DeathTestAbort if the assertion +// fails. +# define GTEST_DEATH_TEST_CHECK_(expression) \ + do { \ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort( \ + ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + + ::testing::internal::StreamableToString(__LINE__) + ": " \ + + #expression); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for +// evaluating any system call that fulfills two conditions: it must return +// -1 on failure, and set errno to EINTR when it is interrupted and +// should be tried again. The macro expands to a loop that repeatedly +// evaluates the expression as long as it evaluates to -1 and sets +// errno to EINTR. If the expression evaluates to -1 but errno is +// something other than EINTR, DeathTestAbort is called. +# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ + do { \ + int gtest_retval; \ + do { \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort( \ + ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + + ::testing::internal::StreamableToString(__LINE__) + ": " \ + + #expression + " != -1"); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// Returns the message describing the last system error in errno. +std::string GetLastErrnoDescription() { + return errno == 0 ? "" : posix::StrError(errno); +} + +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + int num_read; + + do { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + if (num_read == 0) { + GTEST_LOG_(FATAL) << error.GetString(); + } else { + const int last_error = errno; + GTEST_LOG_(FATAL) << "Error while reading death test internal: " + << GetLastErrnoDescription() << " [" << last_error << "]"; + } +} + +// Death test constructor. Increments the running death test count +// for the current test. +DeathTest::DeathTest() { + TestInfo* const info = GetUnitTestImpl()->current_test_info(); + if (info == NULL) { + DeathTestAbort("Cannot run a death test outside of a TEST or " + "TEST_F construct"); + } +} + +// Creates and returns a death test by dispatching to the current +// death test factory. +bool DeathTest::Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) { + return GetUnitTestImpl()->death_test_factory()->Create( + statement, regex, file, line, test); +} + +const char* DeathTest::LastMessage() { + return last_death_test_message_.c_str(); +} + +void DeathTest::set_last_death_test_message(const std::string& message) { + last_death_test_message_ = message; +} + +std::string DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* a_statement, const RE* a_regex) + : statement_(a_statement), + regex_(a_regex), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS), + read_fd_(-1), + write_fd_(-1) {} + + // read_fd_ is expected to be closed and cleared by a derived class. + ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + + void Abort(AbortReason reason); + virtual bool Passed(bool status_ok); + + const char* statement() const { return statement_; } + const RE* regex() const { return regex_; } + bool spawned() const { return spawned_; } + void set_spawned(bool is_spawned) { spawned_ = is_spawned; } + int status() const { return status_; } + void set_status(int a_status) { status_ = a_status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } + int read_fd() const { return read_fd_; } + void set_read_fd(int fd) { read_fd_ = fd; } + int write_fd() const { return write_fd_; } + void set_write_fd(int fd) { write_fd_ = fd; } + + // Called in the parent process only. Reads the result code of the death + // test child process via a pipe, interprets it to set the outcome_ + // member, and closes read_fd_. Outputs diagnostics and terminates in + // case of unexpected codes. + void ReadAndInterpretStatusByte(); + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // The regular expression which test output must match. DeathTestImpl + // doesn't own this object and should not attempt to delete it. + const RE* const regex_; + // True if the death test child process has been successfully spawned. + bool spawned_; + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; + // Descriptor to the read end of the pipe to the child process. It is + // always -1 in the child process. The child keeps its write end of the + // pipe in write_fd_. + int read_fd_; + // Descriptor to the child's write end of the pipe to the parent process. + // It is always -1 in the parent process. The parent keeps its end of the + // pipe in read_fd_. + int write_fd_; +}; + +// Called in the parent process only. Reads the result code of the death +// test child process via a pipe, interprets it to set the outcome_ +// member, and closes read_fd_. Outputs diagnostics and terminates in +// case of unexpected codes. +void DeathTestImpl::ReadAndInterpretStatusByte() { + char flag; + int bytes_read; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + do { + bytes_read = posix::Read(read_fd(), &flag, 1); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestThrew: + set_outcome(THREW); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd()); // Does not return. + break; + default: + GTEST_LOG_(FATAL) << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"; + } + } else { + GTEST_LOG_(FATAL) << "Read from death test child process failed: " + << GetLastErrnoDescription(); + } + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); + set_read_fd(-1); +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file descriptor, then +// calls _exit(1). +void DeathTestImpl::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : + reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; + + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + // We are leaking the descriptor here because on some platforms (i.e., + // when built as Windows DLL), destructors of global objects will still + // run after calling _exit(). On such systems, write_fd_ will be + // indirectly closed from the destructor of UnitTestImpl, causing double + // close if it is also closed here. On debug configurations, double close + // may assert. As there are no in-process buffers to flush here, we are + // relying on the OS to close the descriptor after the process terminates + // when the destructors are not run. + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// Returns an indented copy of stderr output for a death test. +// This makes distinguishing death test output lines from regular log lines +// much easier. +static ::std::string FormatDeathTestOutput(const ::std::string& output) { + ::std::string ret; + for (size_t at = 0; ; ) { + const size_t line_end = output.find('\n', at); + ret += "[ DEATH ] "; + if (line_end == ::std::string::npos) { + ret += output.substr(at); + break; + } + ret += output.substr(at, line_end + 1 - at); + at = line_end + 1; + } + return ret; +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: An enumeration describing how the death test +// concluded: DIED, LIVED, THREW, or RETURNED. The death test +// fails in the latter three cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// regex: A regular expression object to be applied to +// the test's captured standard error output; the death test +// fails if it does not match. +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true iff all of the above conditions are met. Otherwise, the +// first failing condition, in the order given above, is the one that is +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) + return false; + + const std::string error_message = GetCapturedStderr(); + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case THREW: + buffer << " Result: threw an exception.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case DIED: + if (status_ok) { + const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); + if (matched) { + success = true; + } else { + buffer << " Result: died but not with expected error.\n" + << " Expected: " << regex()->pattern() << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status()) << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + break; + case IN_PROGRESS: + default: + GTEST_LOG_(FATAL) + << "DeathTest::Passed somehow called before conclusion of test"; + } + + DeathTest::set_last_death_test_message(buffer.GetString()); + return success; +} + +# if GTEST_OS_WINDOWS +// WindowsDeathTest implements death tests on Windows. Due to the +// specifics of starting new processes on Windows, death tests there are +// always threadsafe, and Google Test considers the +// --gtest_death_test_style=fast setting to be equivalent to +// --gtest_death_test_style=threadsafe there. +// +// A few implementation notes: Like the Linux version, the Windows +// implementation uses pipes for child-to-parent communication. But due to +// the specifics of pipes on Windows, some extra steps are required: +// +// 1. The parent creates a communication pipe and stores handles to both +// ends of it. +// 2. The parent starts the child and provides it with the information +// necessary to acquire the handle to the write end of the pipe. +// 3. The child acquires the write end of the pipe and signals the parent +// using a Windows event. +// 4. Now the parent can release the write end of the pipe on its side. If +// this is done before step 3, the object's reference count goes down to +// 0 and it is destroyed, preventing the child from acquiring it. The +// parent now has to release it, or read operations on the read end of +// the pipe will not return when the child terminates. +// 5. The parent reads child's output through the pipe (outcome code and +// any possible error messages) from the pipe, and its stderr and then +// determines whether to fail the test. +// +// Note: to distinguish Win32 API calls from the local method and function +// calls, the former are explicitly resolved in the global namespace. +// +class WindowsDeathTest : public DeathTestImpl { + public: + WindowsDeathTest(const char* a_statement, + const RE* a_regex, + const char* file, + int line) + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // Handle to the write end of the pipe to the child process. + AutoHandle write_handle_; + // Child process handle. + AutoHandle child_handle_; + // Event the child process uses to signal the parent that it has + // acquired the handle to the write end of the pipe. After seeing this + // event the parent can release its own handles to make sure its + // ReadFile() calls return when the child terminates. + AutoHandle event_handle_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int WindowsDeathTest::Wait() { + if (!spawned()) + return 0; + + // Wait until the child either signals that it has acquired the write end + // of the pipe or it dies. + const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; + switch (::WaitForMultipleObjects(2, + wait_handles, + FALSE, // Waits for any of the handles. + INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 1: + break; + default: + GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + } + + // The child has acquired the write end of the pipe or exited. + // We release the handle on our side and continue. + write_handle_.Reset(); + event_handle_.Reset(); + + ReadAndInterpretStatusByte(); + + // Waits for the child process to exit if it haven't already. This + // returns immediately if the child has already exited, regardless of + // whether previous calls to WaitForMultipleObjects synchronized on this + // handle or not. + GTEST_DEATH_TEST_CHECK_( + WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), + INFINITE)); + DWORD status_code; + GTEST_DEATH_TEST_CHECK_( + ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); + child_handle_.Reset(); + set_status(static_cast(status_code)); + return status(); +} + +// The AssumeRole process for a Windows death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole WindowsDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + // WindowsDeathTest uses an anonymous pipe to communicate results of + // a death test. + SECURITY_ATTRIBUTES handles_are_inheritable = { + sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + HANDLE read_handle, write_handle; + GTEST_DEATH_TEST_CHECK_( + ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); + set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), + O_RDONLY)); + write_handle_.Reset(write_handle); + event_handle_.Reset(::CreateEvent( + &handles_are_inheritable, + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + NULL)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); + const std::string filter_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + + info->test_case_name() + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + + "=" + file_ + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index) + "|" + + StreamableToString(static_cast(::GetCurrentProcessId())) + + // size_t has the same width as pointers on both 32-bit and 64-bit + // Windows platforms. + // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. + "|" + StreamableToString(reinterpret_cast(write_handle)) + + "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); + + char executable_path[_MAX_PATH + 1]; // NOLINT + GTEST_DEATH_TEST_CHECK_( + _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, + executable_path, + _MAX_PATH)); + + std::string command_line = + std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + + internal_flag + "\""; + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // The child process will share the standard handles with the parent. + STARTUPINFOA startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); + + PROCESS_INFORMATION process_info; + GTEST_DEATH_TEST_CHECK_(::CreateProcessA( + executable_path, + const_cast(command_line.c_str()), + NULL, // Retuned process handle is not inheritable. + NULL, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + NULL, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), + &startup_info, + &process_info) != FALSE); + child_handle_.Reset(process_info.hProcess); + ::CloseHandle(process_info.hThread); + set_spawned(true); + return OVERSEE_TEST; +} +# else // We are not on Windows. + +// ForkingDeathTest provides implementations for most of the abstract +// methods of the DeathTest interface. Only the AssumeRole method is +// left undefined. +class ForkingDeathTest : public DeathTestImpl { + public: + ForkingDeathTest(const char* statement, const RE* regex); + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + + protected: + void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } + + private: + // PID of child process during death test; 0 in the child process itself. + pid_t child_pid_; +}; + +// Constructs a ForkingDeathTest. +ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) + : DeathTestImpl(a_statement, a_regex), + child_pid_(-1) {} + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int ForkingDeathTest::Wait() { + if (!spawned()) + return 0; + + ReadAndInterpretStatusByte(); + + int status_value; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); + set_status(status_value); + return status_value; +} + +// A concrete death test class that forks, then immediately runs the test +// in the child process. +class NoExecDeathTest : public ForkingDeathTest { + public: + NoExecDeathTest(const char* a_statement, const RE* a_regex) : + ForkingDeathTest(a_statement, a_regex) { } + virtual TestRole AssumeRole(); +}; + +// The AssumeRole process for a fork-and-run death test. It implements a +// straightforward fork, with a simple pipe to transmit the status byte. +DeathTest::TestRole NoExecDeathTest::AssumeRole() { + const size_t thread_count = GetThreadCount(); + if (thread_count != 1) { + GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + + DeathTest::set_last_death_test_message(""); + CaptureStderr(); + // When we fork the process below, the log file buffers are copied, but the + // file descriptors are shared. We flush all log files here so that closing + // the file descriptors in the child process doesn't throw off the + // synchronization between descriptors and buffers in the parent process. + // This is as close to the fork as possible to avoid a race condition in case + // there are multiple threads running before the death test, and another + // thread writes to the log file. + FlushInfoLog(); + + const pid_t child_pid = fork(); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + set_child_pid(child_pid); + if (child_pid == 0) { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); + set_write_fd(pipe_fd[1]); + // Redirects all logging to stderr in the child process to prevent + // concurrent writes to the log files. We capture stderr in the parent + // process and append the child process' output to a log. + LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); + g_in_fast_death_test_child = true; + return EXECUTE_TEST; + } else { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; + } +} + +// A concrete death test class that forks and re-executes the main +// program from the beginning, with command-line flags set that cause +// only this specific death test to be run. +class ExecDeathTest : public ForkingDeathTest { + public: + ExecDeathTest(const char* a_statement, const RE* a_regex, + const char* file, int line) : + ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } + virtual TestRole AssumeRole(); + private: + static ::std::vector + GetArgvsForDeathTestChildProcess() { + ::std::vector args = GetInjectableArgvs(); + return args; + } + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + + private: + std::vector args_; +}; + +// A struct that encompasses the arguments to the child process of a +// threadsafe-style death test process. +struct ExecDeathTestArgs { + char* const* argv; // Command-line arguments for the child's call to exec + int close_fd; // File descriptor to close; the read end of a pipe +}; + +# if GTEST_OS_MAC +inline char** GetEnviron() { + // When Google Test is built as a framework on MacOS X, the environ variable + // is unavailable. Apple's documentation (man environ) recommends using + // _NSGetEnviron() instead. + return *_NSGetEnviron(); +} +# else +// Some POSIX platforms expect you to declare environ. extern "C" makes +// it reside in the global namespace. +extern "C" char** environ; +inline char** GetEnviron() { return environ; } +# endif // GTEST_OS_MAC + +# if !GTEST_OS_QNX +// The main function for a threadsafe-style death test child process. +// This function is called in a clone()-ed process and thus must avoid +// any potentially unsafe operations like malloc or libc functions. +static int ExecDeathTestChildMain(void* child_arg) { + ExecDeathTestArgs* const args = static_cast(child_arg); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); + + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + + GetLastErrnoDescription()); + return EXIT_FAILURE; + } + + // We can safely call execve() as it's a direct system call. We + // cannot use execvp() as it's a libc function and thus potentially + // unsafe. Since execve() doesn't search the PATH, the user must + // invoke the test program via a valid path that contains at least + // one path separator. + execve(args->argv[0], args->argv, GetEnviron()); + DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + + original_dir + " failed: " + + GetLastErrnoDescription()); + return EXIT_FAILURE; +} +# endif // !GTEST_OS_QNX + +// Two utility routines that together determine the direction the stack +// grows. +// This could be accomplished more elegantly by a single recursive +// function, but we want to guard against the unlikely possibility of +// a smart compiler optimizing the recursion away. +// +// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining +// StackLowerThanAddress into StackGrowsDown, which then doesn't give +// correct answer. +void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; +void StackLowerThanAddress(const void* ptr, bool* result) { + int dummy; + *result = (&dummy < ptr); +} + +bool StackGrowsDown() { + int dummy; + bool result; + StackLowerThanAddress(&dummy, &result); + return result; +} + +// Spawns a child process with the same executable as the current process in +// a thread-safe manner and instructs it to run the death test. The +// implementation uses fork(2) + exec. On systems where clone(2) is +// available, it is used instead, being slightly more thread-safe. On QNX, +// fork supports only single-threaded environments, so this function uses +// spawn(2) there instead. The function dies with an error message if +// anything goes wrong. +static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { + ExecDeathTestArgs args = { argv, close_fd }; + pid_t child_pid = -1; + +# if GTEST_OS_QNX + // Obtains the current directory and sets it to be closed in the child + // process. + const int cwd_fd = open(".", O_RDONLY); + GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); + GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + + GetLastErrnoDescription()); + return EXIT_FAILURE; + } + + int fd_flags; + // Set close_fd to be closed after spawn. + GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, + fd_flags | FD_CLOEXEC)); + struct inheritance inherit = {0}; + // spawn is a system call. + child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); + // Restores the current working directory. + GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); + +# else // GTEST_OS_QNX +# if GTEST_OS_LINUX + // When a SIGPROF signal is received while fork() or clone() are executing, + // the process may hang. To avoid this, we ignore SIGPROF here and re-enable + // it after the call to fork()/clone() is complete. + struct sigaction saved_sigprof_action; + struct sigaction ignore_sigprof_action; + memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); + sigemptyset(&ignore_sigprof_action.sa_mask); + ignore_sigprof_action.sa_handler = SIG_IGN; + GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( + SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); +# endif // GTEST_OS_LINUX + +# if GTEST_HAS_CLONE + const bool use_fork = GTEST_FLAG(death_test_use_fork); + + if (!use_fork) { + static const bool stack_grows_down = StackGrowsDown(); + const size_t stack_size = getpagesize(); + // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. + void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + + // Maximum stack alignment in bytes: For a downward-growing stack, this + // amount is subtracted from size of the stack space to get an address + // that is within the stack space and is aligned on all systems we care + // about. As far as I know there is no ABI with stack alignment greater + // than 64. We assume stack and stack_size already have alignment of + // kMaxStackAlignment. + const size_t kMaxStackAlignment = 64; + void* const stack_top = + static_cast(stack) + + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); + GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && + reinterpret_cast(stack_top) % kMaxStackAlignment == 0); + + child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); + + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); + } +# else + const bool use_fork = true; +# endif // GTEST_HAS_CLONE + + if (use_fork && (child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } +# endif // GTEST_OS_QNX +# if GTEST_OS_LINUX + GTEST_DEATH_TEST_CHECK_SYSCALL_( + sigaction(SIGPROF, &saved_sigprof_action, NULL)); +# endif // GTEST_OS_LINUX + + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + return child_pid; +} + +// The AssumeRole process for a fork-and-exec death test. It re-executes the +// main program from the beginning, setting the --gtest_filter +// and --gtest_internal_run_death_test flags to cause only the current +// death test to be re-run. +DeathTest::TestRole ExecDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + // Clear the close-on-exec flag on the write end of the pipe, lest + // it be closed when the child process does an exec: + GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + + const std::string filter_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + + info->test_case_name() + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index) + "|" + + StreamableToString(pipe_fd[1]); + Arguments args; + args.AddArguments(GetArgvsForDeathTestChildProcess()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // See the comment in NoExecDeathTest::AssumeRole for why the next line + // is necessary. + FlushInfoLog(); + + const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_child_pid(child_pid); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; +} + +# endif // !GTEST_OS_WINDOWS + +// Creates a concrete DeathTest-derived class that depends on the +// --gtest_death_test_style flag, and sets the pointer pointed to +// by the "test" argument to its address. If the test should be +// skipped, sets that pointer to NULL. Returns true, unless the +// flag is set to an invalid value. +bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, + const char* file, int line, + DeathTest** test) { + UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const int death_test_index = impl->current_test_info() + ->increment_death_test_count(); + + if (flag != NULL) { + if (death_test_index > flag->index()) { + DeathTest::set_last_death_test_message( + "Death test count (" + StreamableToString(death_test_index) + + ") somehow exceeded expected maximum (" + + StreamableToString(flag->index()) + ")"); + return false; + } + + if (!(flag->file() == file && flag->line() == line && + flag->index() == death_test_index)) { + *test = NULL; + return true; + } + } + +# if GTEST_OS_WINDOWS + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new WindowsDeathTest(statement, regex, file, line); + } + +# else + + if (GTEST_FLAG(death_test_style) == "threadsafe") { + *test = new ExecDeathTest(statement, regex, file, line); + } else if (GTEST_FLAG(death_test_style) == "fast") { + *test = new NoExecDeathTest(statement, regex); + } + +# endif // GTEST_OS_WINDOWS + + else { // NOLINT - this is more readable than unbalanced brackets inside #if. + DeathTest::set_last_death_test_message( + "Unknown death test style \"" + GTEST_FLAG(death_test_style) + + "\" encountered"); + return false; + } + + return true; +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have +// ::std::string, so we can use it here. +static void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + +# if GTEST_OS_WINDOWS +// Recreates the pipe and event handles from the provided parameters, +// signals the event, and returns a file descriptor wrapped around the pipe +// handle. This function is called in the child process only. +int GetStatusFileDescriptor(unsigned int parent_process_id, + size_t write_handle_as_size_t, + size_t event_handle_as_size_t) { + AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, // Non-inheritable. + parent_process_id)); + if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { + DeathTestAbort("Unable to open parent process " + + StreamableToString(parent_process_id)); + } + + // TODO(vladl@google.com): Replace the following check with a + // compile-time assertion when available. + GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); + + const HANDLE write_handle = + reinterpret_cast(write_handle_as_size_t); + HANDLE dup_write_handle; + + // The newly initialized handle is accessible only in in the parent + // process. To obtain one accessible within the child, we need to use + // DuplicateHandle. + if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, + ::GetCurrentProcess(), &dup_write_handle, + 0x0, // Requested privileges ignored since + // DUPLICATE_SAME_ACCESS is used. + FALSE, // Request non-inheritable handler. + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort("Unable to duplicate the pipe handle " + + StreamableToString(write_handle_as_size_t) + + " from the parent process " + + StreamableToString(parent_process_id)); + } + + const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); + HANDLE dup_event_handle; + + if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, + ::GetCurrentProcess(), &dup_event_handle, + 0x0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort("Unable to duplicate the event handle " + + StreamableToString(event_handle_as_size_t) + + " from the parent process " + + StreamableToString(parent_process_id)); + } + + const int write_fd = + ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); + if (write_fd == -1) { + DeathTestAbort("Unable to convert pipe handle " + + StreamableToString(write_handle_as_size_t) + + " to a file descriptor"); + } + + // Signals the parent that the write end of the pipe has been acquired + // so the parent can release its own write end. + ::SetEvent(dup_event_handle); + + return write_fd; +} +# endif // GTEST_OS_WINDOWS + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + int line = -1; + int index = -1; + ::std::vector< ::std::string> fields; + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); + int write_fd = -1; + +# if GTEST_OS_WINDOWS + + unsigned int parent_process_id = 0; + size_t write_handle_as_size_t = 0; + size_t event_handle_as_size_t = 0; + + if (fields.size() != 6 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &parent_process_id) + || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) + || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + write_fd = GetStatusFileDescriptor(parent_process_id, + write_handle_as_size_t, + event_handle_as_size_t); +# else + + if (fields.size() != 4 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &write_fd)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + +# endif // GTEST_OS_WINDOWS + + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); +} + +} // namespace internal + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keith.ray@gmail.com (Keith Ray) + + +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include +#elif GTEST_OS_WINDOWS +# include +# include +#elif GTEST_OS_SYMBIAN +// Symbian OpenC has PATH_MAX in sys/syslimits.h +# include +#else +# include +# include // Some Linux distributions define PATH_MAX here. +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_MAX_ _MAX_PATH +#elif defined(PATH_MAX) +# define GTEST_PATH_MAX_ PATH_MAX +#elif defined(_XOPEN_PATH_MAX) +# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#else +# define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#endif // GTEST_OS_WINDOWS + + +namespace testing { +namespace internal { + +#if GTEST_OS_WINDOWS +// On Windows, '\\' is the standard path separator, but many tools and the +// Windows API also accept '/' as an alternate path separator. Unless otherwise +// noted, a file path can contain either kind of path separators, or a mixture +// of them. +const char kPathSeparator = '\\'; +const char kAlternatePathSeparator = '/'; +const char kPathSeparatorString[] = "\\"; +const char kAlternatePathSeparatorString[] = "/"; +# if GTEST_OS_WINDOWS_MOBILE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +# else +const char kCurrentDirectoryString[] = ".\\"; +# endif // GTEST_OS_WINDOWS_MOBILE +#else +const char kPathSeparator = '/'; +const char kPathSeparatorString[] = "/"; +const char kCurrentDirectoryString[] = "./"; +#endif // GTEST_OS_WINDOWS + +// Returns whether the given character is a valid path separator. +static bool IsPathSeparator(char c) { +#if GTEST_HAS_ALT_PATH_SEP_ + return (c == kPathSeparator) || (c == kAlternatePathSeparator); +#else + return c == kPathSeparator; +#endif +} + +// Returns the current working directory, or "" if unsuccessful. +FilePath FilePath::GetCurrentDir() { +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't have a current directory, so we just return + // something reasonable. + return FilePath(kCurrentDirectoryString); +#elif GTEST_OS_WINDOWS + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#else + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns a copy of the FilePath with the case-insensitive extension removed. +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns +// FilePath("dir/file"). If a case-insensitive extension is not +// found, returns a copy of the original FilePath. +FilePath FilePath::RemoveExtension(const char* extension) const { + const std::string dot_extension = std::string(".") + extension; + if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { + return FilePath(pathname_.substr( + 0, pathname_.length() - dot_extension.length())); + } + return *this; +} + +// Returns a pointer to the last occurence of a valid path separator in +// the FilePath. On Windows, for example, both '/' and '\' are valid path +// separators. Returns NULL if no path separator was found. +const char* FilePath::FindLastPathSeparator() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); +#if GTEST_HAS_ALT_PATH_SEP_ + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + // Comparing two pointers of which only one is NULL is undefined. + if (last_alt_sep != NULL && + (last_sep == NULL || last_alt_sep > last_sep)) { + return last_alt_sep; + } +#endif + return last_sep; +} + +// Returns a copy of the FilePath with the directory part removed. +// Example: FilePath("path/to/file").RemoveDirectoryName() returns +// FilePath("file"). If there is no directory part ("just_a_file"), it returns +// the FilePath unmodified. If there is no file part ("just_a_dir/") it +// returns an empty FilePath (""). +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveDirectoryName() const { + const char* const last_sep = FindLastPathSeparator(); + return last_sep ? FilePath(last_sep + 1) : *this; +} + +// RemoveFileName returns the directory path with the filename removed. +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveFileName() const { + const char* const last_sep = FindLastPathSeparator(); + std::string dir; + if (last_sep) { + dir = std::string(c_str(), last_sep + 1 - c_str()); + } else { + dir = kCurrentDirectoryString; + } + return FilePath(dir); +} + +// Helper functions for naming files in a directory for xml output. + +// Given directory = "dir", base_name = "test", number = 0, +// extension = "xml", returns "dir/test.xml". If number is greater +// than zero (e.g., 12), returns "dir/test_12.xml". +// On Windows platform, uses \ as the separator rather than /. +FilePath FilePath::MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension) { + std::string file; + if (number == 0) { + file = base_name.string() + "." + extension; + } else { + file = base_name.string() + "_" + StreamableToString(number) + + "." + extension; + } + return ConcatPaths(directory, FilePath(file)); +} + +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". +// On Windows, uses \ as the separator rather than /. +FilePath FilePath::ConcatPaths(const FilePath& directory, + const FilePath& relative_path) { + if (directory.IsEmpty()) + return relative_path; + const FilePath dir(directory.RemoveTrailingPathSeparator()); + return FilePath(dir.string() + kPathSeparator + relative_path.string()); +} + +// Returns true if pathname describes something findable in the file-system, +// either a file, directory, or whatever. +bool FilePath::FileOrDirectoryExists() const { +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns true if pathname describes a directory in the file-system +// that exists. +bool FilePath::DirectoryExists() const { + bool result = false; +#if GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); +#else + const FilePath& path(*this); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && + posix::IsDir(file_stat); +#endif // GTEST_OS_WINDOWS_MOBILE + + return result; +} + +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#if GTEST_OS_WINDOWS + // TODO(wan@google.com): on Windows a network share like + // \\server\share can be a root directory, although it cannot be the + // current directory. Handle this properly. + return pathname_.length() == 3 && IsAbsolutePath(); +#else + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); +#endif +} + +// Returns true if pathname describes an absolute path. +bool FilePath::IsAbsolutePath() const { + const char* const name = pathname_.c_str(); +#if GTEST_OS_WINDOWS + return pathname_.length() >= 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + IsPathSeparator(name[2]); +#else + return IsPathSeparator(name[0]); +#endif +} + +// Returns a pathname for a file that does not currently exist. The pathname +// will be directory/base_name.extension or +// directory/base_name_.extension if directory/base_name.extension +// already exists. The number will be incremented until a pathname is found +// that does not already exist. +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. +// There could be a race condition if two or more processes are calling this +// function at the same time -- they could both pick the same filename. +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension) { + FilePath full_pathname; + int number = 0; + do { + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); + } while (full_pathname.FileOrDirectoryExists()); + return full_pathname; +} + +// Returns true if FilePath ends with a path separator, which indicates that +// it is intended to represent a directory. Returns false otherwise. +// This does NOT check that a directory (or file) actually exists. +bool FilePath::IsDirectory() const { + return !pathname_.empty() && + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); +} + +// Create directories so that path exists. Returns true if successful or if +// the directories already exist; returns false if unable to create directories +// for any reason. +bool FilePath::CreateDirectoriesRecursively() const { + if (!this->IsDirectory()) { + return false; + } + + if (pathname_.length() == 0 || this->DirectoryExists()) { + return true; + } + + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); +} + +// Create the directory so that path exists. Returns true if successful or +// if the directory already exists; returns false if unable to create the +// directory for any reason, including if the parent directory does not +// exist. Not named "CreateDirectory" because that's a macro on Windows. +bool FilePath::CreateFolder() const { +#if GTEST_OS_WINDOWS_MOBILE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, NULL) ? 0 : -1; + delete [] unicode; +#elif GTEST_OS_WINDOWS + int result = _mkdir(pathname_.c_str()); +#else + int result = mkdir(pathname_.c_str(), 0777); +#endif // GTEST_OS_WINDOWS_MOBILE + + if (result == -1) { + return this->DirectoryExists(); // An error is OK if the directory exists. + } + return true; // No error. +} + +// If input name has a trailing separator character, remove it and return the +// name, otherwise return the name string unmodified. +// On Windows platform, uses \ as the separator, other platforms use /. +FilePath FilePath::RemoveTrailingPathSeparator() const { + return IsDirectory() + ? FilePath(pathname_.substr(0, pathname_.length() - 1)) + : *this; +} + +// Removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +void FilePath::Normalize() { + if (pathname_.c_str() == NULL) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.length() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.length() + 1); + + while (*src != '\0') { + *dest_ptr = *src; + if (!IsPathSeparator(*src)) { + src++; + } else { +#if GTEST_HAS_ALT_PATH_SEP_ + if (*dest_ptr == kAlternatePathSeparator) { + *dest_ptr = kPathSeparator; + } +#endif + while (IsPathSeparator(*src)) + src++; + } + dest_ptr++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + +} // namespace internal +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + + +#include +#include +#include +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include // For TerminateProcess() +#elif GTEST_OS_WINDOWS +# include +# include +#else +# include +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_MAC +# include +# include +# include +#endif // GTEST_OS_MAC + +#if GTEST_OS_QNX +# include +# include +#endif // GTEST_OS_QNX + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { +namespace internal { + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC and C++Builder do not provide a definition of STDERR_FILENO. +const int kStdOutFileno = 1; +const int kStdErrFileno = 2; +#else +const int kStdOutFileno = STDOUT_FILENO; +const int kStdErrFileno = STDERR_FILENO; +#endif // _MSC_VER + +#if GTEST_OS_MAC + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const task_t task = mach_task_self(); + mach_msg_type_number_t thread_count; + thread_act_array_t thread_list; + const kern_return_t status = task_threads(task, &thread_list, &thread_count); + if (status == KERN_SUCCESS) { + // task_threads allocates resources in thread_list and we need to free them + // to avoid leaks. + vm_deallocate(task, + reinterpret_cast(thread_list), + sizeof(thread_t) * thread_count); + return static_cast(thread_count); + } else { + return 0; + } +} + +#elif GTEST_OS_QNX + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const int fd = open("/proc/self/as", O_RDONLY); + if (fd < 0) { + return 0; + } + procfs_info process_info; + const int status = + devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); + close(fd); + if (status == EOK) { + return static_cast(process_info.num_threads); + } else { + return 0; + } +} + +#else + +size_t GetThreadCount() { + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +} + +#endif // GTEST_OS_MAC + +#if GTEST_USES_POSIX_RE + +// Implements RE. Currently only needed for death tests. + +RE::~RE() { + if (is_valid_) { + // regfree'ing an invalid regex might crash because the content + // of the regex is undefined. Since the regex's are essentially + // the same, one cannot be valid (or invalid) without the other + // being so too. + regfree(&partial_regex_); + regfree(&full_regex_); + } + free(const_cast(pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.full_regex_, str, 1, &match, 0) == 0; +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = posix::StrDup(regex); + + // Reserves enough bytes to hold the regular expression used for a + // full match. + const size_t full_regex_len = strlen(regex) + 10; + char* const full_pattern = new char[full_regex_len]; + + snprintf(full_pattern, full_regex_len, "^(%s)$", regex); + is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; + // We want to call regcomp(&partial_regex_, ...) even if the + // previous expression returns false. Otherwise partial_regex_ may + // not be properly initialized can may cause trouble when it's + // freed. + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + if (is_valid_) { + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; + } + EXPECT_TRUE(is_valid_) + << "Regular expression \"" << regex + << "\" is not a valid POSIX Extended regular expression."; + + delete[] full_pattern; +} + +#elif GTEST_USES_SIMPLE_RE + +// Returns true iff ch appears anywhere in str (excluding the +// terminating '\0' character). +bool IsInSet(char ch, const char* str) { + return ch != '\0' && strchr(str, ch) != NULL; +} + +// Returns true iff ch belongs to the given classification. Unlike +// similar functions in , these aren't affected by the +// current locale. +bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsAsciiPunct(char ch) { + return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); +} +bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } +bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsAsciiWordChar(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9') || ch == '_'; +} + +// Returns true iff "\\c" is a supported escape sequence. +bool IsValidEscape(char c) { + return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); +} + +// Returns true iff the given atom (specified by escaped and pattern) +// matches ch. The result is undefined if the atom is invalid. +bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { + if (escaped) { // "\\p" where p is pattern_char. + switch (pattern_char) { + case 'd': return IsAsciiDigit(ch); + case 'D': return !IsAsciiDigit(ch); + case 'f': return ch == '\f'; + case 'n': return ch == '\n'; + case 'r': return ch == '\r'; + case 's': return IsAsciiWhiteSpace(ch); + case 'S': return !IsAsciiWhiteSpace(ch); + case 't': return ch == '\t'; + case 'v': return ch == '\v'; + case 'w': return IsAsciiWordChar(ch); + case 'W': return !IsAsciiWordChar(ch); + } + return IsAsciiPunct(pattern_char) && pattern_char == ch; + } + + return (pattern_char == '.' && ch != '\n') || pattern_char == ch; +} + +// Helper function used by ValidateRegex() to format error messages. +std::string FormatRegexSyntaxError(const char* regex, int index) { + return (Message() << "Syntax error at index " << index + << " in simple regular expression \"" << regex << "\": ").GetString(); +} + +// Generates non-fatal failures and returns false if regex is invalid; +// otherwise returns true. +bool ValidateRegex(const char* regex) { + if (regex == NULL) { + // TODO(wan@google.com): fix the source file location in the + // assertion failures to match where the regex is used in user + // code. + ADD_FAILURE() << "NULL is not a valid simple regular expression."; + return false; + } + + bool is_valid = true; + + // True iff ?, *, or + can follow the previous atom. + bool prev_repeatable = false; + for (int i = 0; regex[i]; i++) { + if (regex[i] == '\\') { // An escape sequence + i++; + if (regex[i] == '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "'\\' cannot appear at the end."; + return false; + } + + if (!IsValidEscape(regex[i])) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "invalid escape sequence \"\\" << regex[i] << "\"."; + is_valid = false; + } + prev_repeatable = true; + } else { // Not an escape sequence. + const char ch = regex[i]; + + if (ch == '^' && i > 0) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'^' can only appear at the beginning."; + is_valid = false; + } else if (ch == '$' && regex[i + 1] != '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'$' can only appear at the end."; + is_valid = false; + } else if (IsInSet(ch, "()[]{}|")) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' is unsupported."; + is_valid = false; + } else if (IsRepeat(ch) && !prev_repeatable) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' can only follow a repeatable token."; + is_valid = false; + } + + prev_repeatable = !IsInSet(ch, "^$?*+"); + } + } + + return is_valid; +} + +// Matches a repeated regex atom followed by a valid simple regular +// expression. The regex atom is defined as c if escaped is false, +// or \c otherwise. repeat is the repetition meta character (?, *, +// or +). The behavior is undefined if str contains too many +// characters to be indexable by size_t, in which case the test will +// probably time out anyway. We are fine with this limitation as +// std::string has it too. +bool MatchRepetitionAndRegexAtHead( + bool escaped, char c, char repeat, const char* regex, + const char* str) { + const size_t min_count = (repeat == '+') ? 1 : 0; + const size_t max_count = (repeat == '?') ? 1 : + static_cast(-1) - 1; + // We cannot call numeric_limits::max() as it conflicts with the + // max() macro on Windows. + + for (size_t i = 0; i <= max_count; ++i) { + // We know that the atom matches each of the first i characters in str. + if (i >= min_count && MatchRegexAtHead(regex, str + i)) { + // We have enough matches at the head, and the tail matches too. + // Since we only care about *whether* the pattern matches str + // (as opposed to *how* it matches), there is no need to find a + // greedy match. + return true; + } + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) + return false; + } + return false; +} + +// Returns true iff regex matches a prefix of str. regex must be a +// valid simple regular expression and not start with "^", or the +// result is undefined. +bool MatchRegexAtHead(const char* regex, const char* str) { + if (*regex == '\0') // An empty regex matches a prefix of anything. + return true; + + // "$" only matches the end of a string. Note that regex being + // valid guarantees that there's nothing after "$" in it. + if (*regex == '$') + return *str == '\0'; + + // Is the first thing in regex an escape sequence? + const bool escaped = *regex == '\\'; + if (escaped) + ++regex; + if (IsRepeat(regex[1])) { + // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so + // here's an indirect recursion. It terminates as the regex gets + // shorter in each recursion. + return MatchRepetitionAndRegexAtHead( + escaped, regex[0], regex[1], regex + 2, str); + } else { + // regex isn't empty, isn't "$", and doesn't start with a + // repetition. We match the first atom of regex with the first + // character of str and recurse. + return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && + MatchRegexAtHead(regex + 1, str + 1); + } +} + +// Returns true iff regex matches any substring of str. regex must be +// a valid simple regular expression, or the result is undefined. +// +// The algorithm is recursive, but the recursion depth doesn't exceed +// the regex length, so we won't need to worry about running out of +// stack space normally. In rare cases the time complexity can be +// exponential with respect to the regex length + the string length, +// but usually it's must faster (often close to linear). +bool MatchRegexAnywhere(const char* regex, const char* str) { + if (regex == NULL || str == NULL) + return false; + + if (*regex == '^') + return MatchRegexAtHead(regex + 1, str); + + // A successful match can be anywhere in str. + do { + if (MatchRegexAtHead(regex, str)) + return true; + } while (*str++ != '\0'); + return false; +} + +// Implements the RE class. + +RE::~RE() { + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = full_pattern_ = NULL; + if (regex != NULL) { + pattern_ = posix::StrDup(regex); + } + + is_valid_ = ValidateRegex(regex); + if (!is_valid_) { + // No need to calculate the full pattern when the regex is invalid. + return; + } + + const size_t len = strlen(regex); + // Reserves enough bytes to hold the regular expression used for a + // full match: we need space to prepend a '^', append a '$', and + // terminate the string with '\0'. + char* buffer = static_cast(malloc(len + 3)); + full_pattern_ = buffer; + + if (*regex != '^') + *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. + + // We don't use snprintf or strncpy, as they trigger a warning when + // compiled with VC++ 8.0. + memcpy(buffer, regex, len); + buffer += len; + + if (len == 0 || regex[len - 1] != '$') + *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. + + *buffer = '\0'; +} + +#endif // GTEST_USES_POSIX_RE + +const char kUnknownFile[] = "unknown file"; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { + const std::string file_name(file == NULL ? kUnknownFile : file); + + if (line < 0) { + return file_name + ":"; + } +#ifdef _MSC_VER + return file_name + "(" + StreamableToString(line) + "):"; +#else + return file_name + ":" + StreamableToString(line) + ":"; +#endif // _MSC_VER +} + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +// Note that FormatCompilerIndependentFileLocation() does NOT append colon +// to the file location it produces, unlike FormatFileLocation(). +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( + const char* file, int line) { + const std::string file_name(file == NULL ? kUnknownFile : file); + + if (line < 0) + return file_name; + else + return file_name + ":" + StreamableToString(line); +} + + +GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) + : severity_(severity) { + const char* const marker = + severity == GTEST_INFO ? "[ INFO ]" : + severity == GTEST_WARNING ? "[WARNING]" : + severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + GetStream() << ::std::endl << marker << " " + << FormatFileLocation(file, line).c_str() << ": "; +} + +// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. +GTestLog::~GTestLog() { + GetStream() << ::std::endl; + if (severity_ == GTEST_FATAL) { + fflush(stderr); + posix::Abort(); + } +} +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4996) +#endif // _MSC_VER + +#if GTEST_HAS_STREAM_REDIRECTION + +// Object that captures an output stream (stdout/stderr). +class CapturedStream { + public: + // The ctor redirects the stream to a temporary file. + explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { +# if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + const UINT success = ::GetTempFileNameA(temp_dir_path, + "gtest_redir", + 0, // Generate unique file name. + temp_file_path); + GTEST_CHECK_(success != 0) + << "Unable to create a temporary file in " << temp_dir_path; + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " + << temp_file_path; + filename_ = temp_file_path; +# else + // There's no guarantee that a test has write access to the current + // directory, so we create the temporary file in the /tmp directory + // instead. We use /tmp on most systems, and /sdcard on Android. + // That's because Android doesn't have /tmp. +# if GTEST_OS_LINUX_ANDROID + // Note: Android applications are expected to call the framework's + // Context.getExternalStorageDirectory() method through JNI to get + // the location of the world-writable SD Card directory. However, + // this requires a Context handle, which cannot be retrieved + // globally from native code. Doing so also precludes running the + // code as part of a regular standalone executable, which doesn't + // run in a Dalvik process (e.g. when running it through 'adb shell'). + // + // The location /sdcard is directly accessible from native code + // and is the only location (unofficially) supported by the Android + // team. It's generally a symlink to the real SD Card mount point + // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or + // other OEM-customized locations. Never rely on these, and always + // use /sdcard. + char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; +# else + char name_template[] = "/tmp/captured_stream.XXXXXX"; +# endif // GTEST_OS_LINUX_ANDROID + const int captured_fd = mkstemp(name_template); + filename_ = name_template; +# endif // GTEST_OS_WINDOWS + fflush(NULL); + dup2(captured_fd, fd_); + close(captured_fd); + } + + ~CapturedStream() { + remove(filename_.c_str()); + } + + std::string GetCapturedString() { + if (uncaptured_fd_ != -1) { + // Restores the original stream. + fflush(NULL); + dup2(uncaptured_fd_, fd_); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } + + FILE* const file = posix::FOpen(filename_.c_str(), "r"); + const std::string content = ReadEntireFile(file); + posix::FClose(file); + return content; + } + + private: + // Reads the entire content of a file as an std::string. + static std::string ReadEntireFile(FILE* file); + + // Returns the size (in bytes) of a file. + static size_t GetFileSize(FILE* file); + + const int fd_; // A stream to capture. + int uncaptured_fd_; + // Name of the temporary file holding the stderr output. + ::std::string filename_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); +}; + +// Returns the size (in bytes) of a file. +size_t CapturedStream::GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +// Reads the entire content of a file as a string. +std::string CapturedStream::ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const std::string content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +# ifdef _MSC_VER +# pragma warning(pop) +# endif // _MSC_VER + +static CapturedStream* g_captured_stderr = NULL; +static CapturedStream* g_captured_stdout = NULL; + +// Starts capturing an output stream (stdout/stderr). +void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { + if (*stream != NULL) { + GTEST_LOG_(FATAL) << "Only one " << stream_name + << " capturer can exist at a time."; + } + *stream = new CapturedStream(fd); +} + +// Stops capturing the output stream and returns the captured string. +std::string GetCapturedStream(CapturedStream** captured_stream) { + const std::string content = (*captured_stream)->GetCapturedString(); + + delete *captured_stream; + *captured_stream = NULL; + + return content; +} + +// Starts capturing stdout. +void CaptureStdout() { + CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); +} + +// Starts capturing stderr. +void CaptureStderr() { + CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); +} + +// Stops capturing stdout and returns the captured string. +std::string GetCapturedStdout() { + return GetCapturedStream(&g_captured_stdout); +} + +// Stops capturing stderr and returns the captured string. +std::string GetCapturedStderr() { + return GetCapturedStream(&g_captured_stderr); +} + +#endif // GTEST_HAS_STREAM_REDIRECTION + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +::std::vector g_argvs; + +static const ::std::vector* g_injected_test_argvs = + NULL; // Owned. + +void SetInjectableArgvs(const ::std::vector* argvs) { + if (g_injected_test_argvs != argvs) + delete g_injected_test_argvs; + g_injected_test_argvs = argvs; +} + +const ::std::vector& GetInjectableArgvs() { + if (g_injected_test_argvs != NULL) { + return *g_injected_test_argvs; + } + return g_argvs; +} +#endif // GTEST_HAS_DEATH_TEST + +#if GTEST_OS_WINDOWS_MOBILE +namespace posix { +void Abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +} // namespace posix +#endif // GTEST_OS_WINDOWS_MOBILE + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GTEST_FOO" in the open-source version. +static std::string FlagToEnvVar(const char* flag) { + const std::string full_flag = + (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); + + Message env_var; + for (size_t i = 0; i != full_flag.length(); i++) { + env_var << ToUpper(full_flag.c_str()[i]); + } + + return env_var.GetString(); +} + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value) { + // Parses the environment variable as a decimal integer. + char* end = NULL; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value \"" << str << "\".\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + // Is the parsed value in the range of an Int32? + const Int32 result = static_cast(long_value); + if (long_value == LONG_MAX || long_value == LONG_MIN || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value " << str << ", which overflows.\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + *value = result; + return true; +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { + const std::string env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + return string_value == NULL ? + default_value : strcmp(string_value, "0") != 0; +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { + const std::string env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + if (string_value == NULL) { + // The environment variable is not set. + return default_value; + } + + Int32 result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, + string_value, &result)) { + printf("The default value %s is used.\n", + (Message() << default_value).GetString().c_str()); + fflush(stdout); + return default_value; + } + + return result; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGTestEnv(const char* flag, const char* default_value) { + const std::string env_var = FlagToEnvVar(flag); + const char* const value = posix::GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +} + +} // namespace internal +} // namespace testing +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. + +#include +#include +#include // NOLINT +#include + +namespace testing { + +namespace { + +using ::std::ostream; + +// Prints a segment of bytes in the given object. +void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, + size_t count, ostream* os) { + char text[5] = ""; + for (size_t i = 0; i != count; i++) { + const size_t j = start + i; + if (i != 0) { + // Organizes the bytes into groups of 2 for easy parsing by + // human. + if ((j % 2) == 0) + *os << ' '; + else + *os << '-'; + } + GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); + *os << text; + } +} + +// Prints the bytes in the given value to the given ostream. +void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, + ostream* os) { + // Tells the user how big the object is. + *os << count << "-byte object <"; + + const size_t kThreshold = 132; + const size_t kChunkSize = 64; + // If the object size is bigger than kThreshold, we'll have to omit + // some details by printing only the first and the last kChunkSize + // bytes. + // TODO(wan): let the user control the threshold using a flag. + if (count < kThreshold) { + PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); + } else { + PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); + *os << " ... "; + // Rounds up to 2-byte boundary. + const size_t resume_pos = (count - kChunkSize + 1)/2*2; + PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); + } + *os << ">"; +} + +} // namespace + +namespace internal2 { + +// Delegates to PrintBytesInObjectToImpl() to print the bytes in the +// given object. The delegation simplifies the implementation, which +// uses the << operator and thus is easier done outside of the +// ::testing::internal namespace, which contains a << operator that +// sometimes conflicts with the one in STL. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, + ostream* os) { + PrintBytesInObjectToImpl(obj_bytes, count, os); +} + +} // namespace internal2 + +namespace internal { + +// Depending on the value of a char (or wchar_t), we print it in one +// of three formats: +// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), +// - as a hexidecimal escape sequence (e.g. '\x7F'), or +// - as a special escape sequence (e.g. '\r', '\n'). +enum CharFormat { + kAsIs, + kHexEscape, + kSpecialEscape +}; + +// Returns true if c is a printable ASCII character. We test the +// value of c directly instead of calling isprint(), which is buggy on +// Windows Mobile. +inline bool IsPrintableAscii(wchar_t c) { + return 0x20 <= c && c <= 0x7E; +} + +// Prints a wide or narrow char c as a character literal without the +// quotes, escaping it when necessary; returns how c was formatted. +// The template argument UnsignedChar is the unsigned version of Char, +// which is the type of c. +template +static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { + switch (static_cast(c)) { + case L'\0': + *os << "\\0"; + break; + case L'\'': + *os << "\\'"; + break; + case L'\\': + *os << "\\\\"; + break; + case L'\a': + *os << "\\a"; + break; + case L'\b': + *os << "\\b"; + break; + case L'\f': + *os << "\\f"; + break; + case L'\n': + *os << "\\n"; + break; + case L'\r': + *os << "\\r"; + break; + case L'\t': + *os << "\\t"; + break; + case L'\v': + *os << "\\v"; + break; + default: + if (IsPrintableAscii(c)) { + *os << static_cast(c); + return kAsIs; + } else { + *os << "\\x" + String::FormatHexInt(static_cast(c)); + return kHexEscape; + } + } + return kSpecialEscape; +} + +// Prints a wchar_t c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\'': + *os << "'"; + return kAsIs; + case L'"': + *os << "\\\""; + return kSpecialEscape; + default: + return PrintAsCharLiteralTo(c, os); + } +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { + return PrintAsStringLiteralTo( + static_cast(static_cast(c)), os); +} + +// Prints a wide or narrow character c and its code. '\0' is printed +// as "'\\0'", other unprintable characters are also properly escaped +// using the standard C++ escape sequence. The template argument +// UnsignedChar is the unsigned version of Char, which is the type of c. +template +void PrintCharAndCodeTo(Char c, ostream* os) { + // First, print c as a literal in the most readable form we can find. + *os << ((sizeof(c) > 1) ? "L'" : "'"); + const CharFormat format = PrintAsCharLiteralTo(c, os); + *os << "'"; + + // To aid user debugging, we also print c's code in decimal, unless + // it's 0 (in which case c was printed as '\\0', making the code + // obvious). + if (c == 0) + return; + *os << " (" << static_cast(c); + + // For more convenience, we print c's code again in hexidecimal, + // unless c was already printed in the form '\x##' or the code is in + // [1, 9]. + if (format == kHexEscape || (1 <= c && c <= 9)) { + // Do nothing. + } else { + *os << ", 0x" << String::FormatHexInt(static_cast(c)); + } + *os << ")"; +} + +void PrintTo(unsigned char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} +void PrintTo(signed char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} + +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its code. L'\0' is printed as "L'\\0'". +void PrintTo(wchar_t wc, ostream* os) { + PrintCharAndCodeTo(wc, os); +} + +// Prints the given array of characters to the ostream. CharType must be either +// char or wchar_t. +// The array starts at begin, the length is len, it may include '\0' characters +// and may not be NUL-terminated. +template +static void PrintCharsAsStringTo( + const CharType* begin, size_t len, ostream* os) { + const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; + *os << kQuoteBegin; + bool is_previous_hex = false; + for (size_t index = 0; index < len; ++index) { + const CharType cur = begin[index]; + if (is_previous_hex && IsXDigit(cur)) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" " << kQuoteBegin; + } + is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; + } + *os << "\""; +} + +// Prints a (const) char/wchar_t array of 'len' elements, starting at address +// 'begin'. CharType must be either char or wchar_t. +template +static void UniversalPrintCharArray( + const CharType* begin, size_t len, ostream* os) { + // The code + // const char kFoo[] = "foo"; + // generates an array of 4, not 3, elements, with the last one being '\0'. + // + // Therefore when printing a char array, we don't print the last element if + // it's '\0', such that the output matches the string literal as it's + // written in the source code. + if (len > 0 && begin[len - 1] == '\0') { + PrintCharsAsStringTo(begin, len - 1, os); + return; + } + + // If, however, the last element in the array is not '\0', e.g. + // const char kFoo[] = { 'f', 'o', 'o' }; + // we must print the entire array. We also print a message to indicate + // that the array is not NUL-terminated. + PrintCharsAsStringTo(begin, len, os); + *os << " (no terminating NUL)"; +} + +// Prints a (const) char array of 'len' elements, starting at address 'begin'. +void UniversalPrintArray(const char* begin, size_t len, ostream* os) { + UniversalPrintCharArray(begin, len, os); +} + +// Prints a (const) wchar_t array of 'len' elements, starting at address +// 'begin'. +void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { + UniversalPrintCharArray(begin, len, os); +} + +// Prints the given C string to the ostream. +void PrintTo(const char* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, strlen(s), os); + } +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Prints the given wide C string to the ostream. +void PrintTo(const wchar_t* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, wcslen(s), os); + } +} +#endif // wchar_t is native + +// Prints a ::string object. +#if GTEST_HAS_GLOBAL_STRING +void PrintStringTo(const ::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void PrintStringTo(const ::std::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} + +// Prints a ::wstring object. +#if GTEST_HAS_GLOBAL_WSTRING +void PrintWideStringTo(const ::wstring& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_WSTRING + +} // namespace internal + +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// The Google C++ Testing Framework (Google Test) + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +using internal::GetUnitTestImpl; + +// Gets the summary of the failure message by omitting the stack trace +// in it. +std::string TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == NULL ? message : + std::string(message, stack_trace); +} + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os + << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess ? "Success" : + result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + array_.push_back(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + internal::posix::Abort(); + } + + return array_[index]; +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return static_cast(array_.size()); +} + +namespace internal { + +HasNewFatalFailureHelper::HasNewFatalFailureHelper() + : has_new_fatal_failure_(false), + original_reporter_(GetUnitTestImpl()-> + GetTestPartResultReporterForCurrentThread()) { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); +} + +HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( + original_reporter_); +} + +void HasNewFatalFailureHelper::ReportTestPartResult( + const TestPartResult& result) { + if (result.fatally_failed()) + has_new_fatal_failure_ = true; + original_reporter_->ReportTestPartResult(result); +} + +} // namespace internal + +} // namespace testing +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + + +namespace testing { +namespace internal { + +#if GTEST_HAS_TYPED_TEST_P + +// Skips to the first non-space char in str. Returns an empty string if str +// contains only whitespace characters. +static const char* SkipSpaces(const char* str) { + while (IsSpace(*str)) + str++; + return str; +} + +// Verifies that registered_tests match the test names in +// defined_test_names_; returns registered_tests if successful, or +// aborts the program otherwise. +const char* TypedTestCasePState::VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests) { + typedef ::std::set::const_iterator DefinedTestIter; + registered_ = true; + + // Skip initial whitespace in registered_tests since some + // preprocessors prefix stringizied literals with whitespace. + registered_tests = SkipSpaces(registered_tests); + + Message errors; + ::std::set tests; + for (const char* names = registered_tests; names != NULL; + names = SkipComma(names)) { + const std::string name = GetPrefixUntilComma(names); + if (tests.count(name) != 0) { + errors << "Test " << name << " is listed more than once.\n"; + continue; + } + + bool found = false; + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (name == *it) { + found = true; + break; + } + } + + if (found) { + tests.insert(name); + } else { + errors << "No test named " << name + << " can be found in this test case.\n"; + } + } + + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (tests.count(*it) == 0) { + errors << "You forgot to list test " << *it << ".\n"; + } + } + + const std::string& errors_str = errors.GetString(); + if (errors_str != "") { + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors_str.c_str()); + fflush(stderr); + posix::Abort(); + } + + return registered_tests; +} + +#endif // GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing diff --git a/deps/gtest/gtest.gyp b/deps/gtest/gtest.gyp new file mode 100644 index 000000000..3728dfc91 --- /dev/null +++ b/deps/gtest/gtest.gyp @@ -0,0 +1,25 @@ +{ + 'target_defaults': { + 'default_configuration': 'Release', + 'configurations': { + 'Debug': {}, + 'Release': {} + }, + }, + 'targets': [{ + 'target_name': 'gtest', + 'type': 'static_library', + 'sources': [ + 'gtest-all.cc' + ], + 'link_settings': { + 'xcode_settings': { 'OTHER_LDFLAGS': [ '-lpthread' ] }, + 'ldflags': [ '-lpthread' ], + }, + 'direct_dependent_settings': { + 'include_dirs': [ + '.', + ], + }, + }] +} \ No newline at end of file diff --git a/deps/gtest/gtest/gtest.h b/deps/gtest/gtest/gtest.h new file mode 100644 index 000000000..4f3804f70 --- /dev/null +++ b/deps/gtest/gtest/gtest.h @@ -0,0 +1,20061 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for Google Test. It should be +// included by any test program that uses Google Test. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! +// +// Acknowledgment: Google Test borrowed the idea of automatic test +// registration from Barthelemy Dagenais' (barthelemy@prologique.com) +// easyUnit framework. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_H_ + +#include +#include +#include + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares functions and macros used internally by +// Google Test. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan) +// +// Low-level types and utilities for porting Google Test to various +// platforms. They are subject to change without notice. DO NOT USE +// THEM IN USER CODE. +// +// This file is fundamental to Google Test. All other Google Test source +// files are expected to #include this. Therefore, it cannot #include +// any other Google Test header. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +// The user can define the following macros in the build script to +// control Google Test's behavior. If the user doesn't define a macro +// in this list, Google Test will define it. +// +// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) +// is/isn't available. +// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions +// are enabled. +// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::string, which is different to std::string). +// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::wstring, which is different to std::wstring). +// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular +// expressions are/aren't available. +// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that +// is/isn't available. +// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't +// enabled. +// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that +// std::wstring does/doesn't work (Google Test can +// be used where std::wstring is unavailable). +// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple +// is/isn't available. +// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the +// compiler supports Microsoft's "Structured +// Exception Handling". +// GTEST_HAS_STREAM_REDIRECTION +// - Define it to 1/0 to indicate whether the +// platform supports I/O stream redirection using +// dup() and dup2(). +// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google +// Test's own tr1 tuple implementation should be +// used. Unused when the user sets +// GTEST_HAS_TR1_TUPLE to 0. +// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test +// is building in C++11/C++98 mode. +// GTEST_LINKED_AS_SHARED_LIBRARY +// - Define to 1 when compiling tests that use +// Google Test as a shared library (known as +// DLL on Windows). +// GTEST_CREATE_SHARED_LIBRARY +// - Define to 1 when compiling Google Test itself +// as a shared library. + +// This header defines the following utilities: +// +// Macros indicating the current platform (defined to 1 if compiled on +// the given platform; otherwise undefined): +// GTEST_OS_AIX - IBM AIX +// GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_HPUX - HP-UX +// GTEST_OS_LINUX - Linux +// GTEST_OS_LINUX_ANDROID - Google Android +// GTEST_OS_MAC - Mac OS X +// GTEST_OS_IOS - iOS +// GTEST_OS_IOS_SIMULATOR - iOS simulator +// GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_OPENBSD - OpenBSD +// GTEST_OS_QNX - QNX +// GTEST_OS_SOLARIS - Sun Solaris +// GTEST_OS_SYMBIAN - Symbian +// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) +// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop +// GTEST_OS_WINDOWS_MINGW - MinGW +// GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_ZOS - z/OS +// +// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// most stable support. Since core members of the Google Test project +// don't have access to other platforms, support for them may be less +// stable. If you notice any problems on your platform, please notify +// googletestframework@googlegroups.com (patches for fixing them are +// even more welcome!). +// +// Note that it is possible that none of the GTEST_OS_* macros are defined. +// +// Macros indicating available Google Test features (defined to 1 if +// the corresponding feature is supported; otherwise undefined): +// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized +// tests) +// GTEST_HAS_DEATH_TEST - death tests +// GTEST_HAS_PARAM_TEST - value-parameterized tests +// GTEST_HAS_TYPED_TEST - typed tests +// GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with +// GTEST_HAS_POSIX_RE (see above) which users can +// define themselves. +// GTEST_USES_SIMPLE_RE - our own simple regex is used; +// the above two are mutually exclusive. +// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). +// +// Macros for basic C++ coding: +// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. +// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a +// variable don't have to be used. +// GTEST_DISALLOW_ASSIGN_ - disables operator=. +// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// +// Synchronization: +// Mutex, MutexLock, ThreadLocal, GetThreadCount() +// - synchronization primitives. +// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above +// synchronization primitives have real implementations +// and Google Test is thread-safe; or 0 otherwise. +// +// Template meta programming: +// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. +// IteratorTraits - partial implementation of std::iterator_traits, which +// is not available in libCstd when compiled with Sun C++. +// +// Smart pointers: +// scoped_ptr - as in TR2. +// +// Regular expressions: +// RE - a simple regular expression class using the POSIX +// Extended Regular Expression syntax on UNIX-like +// platforms, or a reduced regular exception syntax on +// other platforms, including Windows. +// +// Logging: +// GTEST_LOG_() - logs messages at the specified severity level. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. +// +// Stdout and stderr capturing: +// CaptureStdout() - starts capturing stdout. +// GetCapturedStdout() - stops capturing stdout and returns the captured +// string. +// CaptureStderr() - starts capturing stderr. +// GetCapturedStderr() - stops capturing stderr and returns the captured +// string. +// +// Integer types: +// TypeWithSize - maps an integer to a int type. +// Int32, UInt32, Int64, UInt64, TimeInMillis +// - integers of known sizes. +// BiggestInt - the biggest signed integer type. +// +// Command-line utilities: +// GTEST_FLAG() - references a flag. +// GTEST_DECLARE_*() - declares a flag. +// GTEST_DEFINE_*() - defines a flag. +// GetInjectableArgvs() - returns the command line as a vector of strings. +// +// Environment variable utilities: +// GetEnv() - gets the value of an environment variable. +// BoolFromGTestEnv() - parses a bool environment variable. +// Int32FromGTestEnv() - parses an Int32 environment variable. +// StringFromGTestEnv() - parses a string environment variable. + +#include // for isspace, etc +#include // for ptrdiff_t +#include +#include +#include +#ifndef _WIN32_WCE +# include +# include +#endif // !_WIN32_WCE + +#if defined __APPLE__ +# include +# include +#endif + +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +#define GTEST_FLAG_PREFIX_ "gtest_" +#define GTEST_FLAG_PREFIX_DASH_ "gtest-" +#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +#define GTEST_NAME_ "Google Test" +#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" + +// Determines the version of gcc that is used to compile this. +#ifdef __GNUC__ +// 40302 means version 4.3.2. +# define GTEST_GCC_VER_ \ + (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif // __GNUC__ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +# define GTEST_OS_CYGWIN 1 +#elif defined __SYMBIAN32__ +# define GTEST_OS_SYMBIAN 1 +#elif defined _WIN32 +# define GTEST_OS_WINDOWS 1 +# ifdef _WIN32_WCE +# define GTEST_OS_WINDOWS_MOBILE 1 +# elif defined(__MINGW__) || defined(__MINGW32__) +# define GTEST_OS_WINDOWS_MINGW 1 +# else +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif // _WIN32_WCE +#elif defined __APPLE__ +# define GTEST_OS_MAC 1 +# if TARGET_OS_IPHONE +# define GTEST_OS_IOS 1 +# if TARGET_IPHONE_SIMULATOR +# define GTEST_OS_IOS_SIMULATOR 1 +# endif +# endif +#elif defined __linux__ +# define GTEST_OS_LINUX 1 +# if defined __ANDROID__ +# define GTEST_OS_LINUX_ANDROID 1 +# endif +#elif defined __MVS__ +# define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +# define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +# define GTEST_OS_AIX 1 +#elif defined(__hpux) +# define GTEST_OS_HPUX 1 +#elif defined __native_client__ +# define GTEST_OS_NACL 1 +#elif defined __OpenBSD__ +# define GTEST_OS_OPENBSD 1 +#elif defined __QNX__ +# define GTEST_OS_QNX 1 +#endif // __CYGWIN__ + +#ifndef GTEST_LANG_CXX11 +// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when +// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a +// value for __cplusplus, and recent versions of clang, gcc, and +// probably other compilers set that too in C++11 mode. +# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L +// Compiling in at least C++11 mode. +# define GTEST_LANG_CXX11 1 +# else +# define GTEST_LANG_CXX11 0 +# endif +#endif + +// Brings in definitions for functions used in the testing::internal::posix +// namespace (read, write, close, chdir, isatty, stat). We do not currently +// use them on Windows Mobile. +#if !GTEST_OS_WINDOWS +// This assumes that non-Windows OSes provide unistd.h. For OSes where this +// is not the case, we need to include headers that provide the functions +// mentioned above. +# include +# include +#elif !GTEST_OS_WINDOWS_MOBILE +# include +# include +#endif + +#if GTEST_OS_LINUX_ANDROID +// Used to define __ANDROID_API__ matching the target NDK API level. +# include // NOLINT +#endif + +// Defines this to true iff Google Test can use POSIX regular expressions. +#ifndef GTEST_HAS_POSIX_RE +# if GTEST_OS_LINUX_ANDROID +// On Android, is only available starting with Gingerbread. +# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) +# else +# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) +# endif +#endif + +#if GTEST_HAS_POSIX_RE + +// On some platforms, needs someone to define size_t, and +// won't compile otherwise. We can #include it here as we already +// included , which is guaranteed to define size_t through +// . +# include // NOLINT + +# define GTEST_USES_POSIX_RE 1 + +#elif GTEST_OS_WINDOWS + +// is not available on Windows. Use our own simple regex +// implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#else + +// may not be available on this platform. Use our own +// simple regex implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#endif // GTEST_HAS_POSIX_RE + +#ifndef GTEST_HAS_EXCEPTIONS +// The user didn't tell us whether exceptions are enabled, so we need +// to figure it out. +# if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +// macro to enable exceptions, so we'll do the same. +// Assumes that exceptions are enabled by default. +# ifndef _HAS_EXCEPTIONS +# define _HAS_EXCEPTIONS 1 +# endif // _HAS_EXCEPTIONS +# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +# elif defined(__GNUC__) && __EXCEPTIONS +// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__SUNPRO_CC) +// Sun Pro CC supports exceptions. However, there is no compile-time way of +// detecting whether they are enabled or not. Therefore, we assume that +// they are enabled unless the user tells us otherwise. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__IBMCPP__) && __EXCEPTIONS +// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__HP_aCC) +// Exception handling is in effect by default in HP aCC compiler. It has to +// be turned of by +noeh compiler option if desired. +# define GTEST_HAS_EXCEPTIONS 1 +# else +// For other compilers, we assume exceptions are disabled to be +// conservative. +# define GTEST_HAS_EXCEPTIONS 0 +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +#endif // GTEST_HAS_EXCEPTIONS + +#if !defined(GTEST_HAS_STD_STRING) +// Even though we don't use this macro any longer, we keep it in case +// some clients still depend on it. +# define GTEST_HAS_STD_STRING 1 +#elif !GTEST_HAS_STD_STRING +// The user told us that ::std::string isn't available. +# error "Google Test cannot be used where ::std::string isn't available." +#endif // !defined(GTEST_HAS_STD_STRING) + +#ifndef GTEST_HAS_GLOBAL_STRING +// The user didn't tell us whether ::string is available, so we need +// to figure it out. + +# define GTEST_HAS_GLOBAL_STRING 0 + +#endif // GTEST_HAS_GLOBAL_STRING + +#ifndef GTEST_HAS_STD_WSTRING +// The user didn't tell us whether ::std::wstring is available, so we need +// to figure it out. +// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring +// is available. + +// Cygwin 1.7 and below doesn't support ::std::wstring. +// Solaris' libc++ doesn't support it either. Android has +// no support for it at least as recent as Froyo (2.2). +# define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) + +#endif // GTEST_HAS_STD_WSTRING + +#ifndef GTEST_HAS_GLOBAL_WSTRING +// The user didn't tell us whether ::wstring is available, so we need +// to figure it out. +# define GTEST_HAS_GLOBAL_WSTRING \ + (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Determines whether RTTI is available. +#ifndef GTEST_HAS_RTTI +// The user didn't tell us whether RTTI is enabled, so we need to +// figure it out. + +# ifdef _MSC_VER + +# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. +# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) + +# ifdef __GXX_RTTI +// When building against STLport with the Android NDK and with +// -frtti -fno-exceptions, the build fails at link time with undefined +// references to __cxa_bad_typeid. Note sure if STL or toolchain bug, +// so disable RTTI when detected. +# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ + !defined(__EXCEPTIONS) +# define GTEST_HAS_RTTI 0 +# else +# define GTEST_HAS_RTTI 1 +# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS +# else +# define GTEST_HAS_RTTI 0 +# endif // __GXX_RTTI + +// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends +// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the +// first version with C++ support. +# elif defined(__clang__) + +# define GTEST_HAS_RTTI __has_feature(cxx_rtti) + +// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if +// both the typeid and dynamic_cast features are present. +# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) + +# ifdef __RTTI_ALL__ +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +# else + +// For all other compilers, we assume RTTI is enabled. +# define GTEST_HAS_RTTI 1 + +# endif // _MSC_VER + +#endif // GTEST_HAS_RTTI + +// It's this header's responsibility to #include when RTTI +// is enabled. +#if GTEST_HAS_RTTI +# include +#endif + +// Determines whether Google Test can use the pthreads library. +#ifndef GTEST_HAS_PTHREAD +// The user didn't tell us explicitly, so we assume pthreads support is +// available on Linux and Mac. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ + || GTEST_OS_QNX) +#endif // GTEST_HAS_PTHREAD + +#if GTEST_HAS_PTHREAD +// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is +// true. +# include // NOLINT + +// For timespec and nanosleep, used below. +# include // NOLINT +#endif + +// Determines whether Google Test can use tr1/tuple. You can define +// this macro to 0 to prevent Google Test from using tuple (any +// feature depending on tuple with be disabled in this mode). +#ifndef GTEST_HAS_TR1_TUPLE +# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) +// STLport, provided with the Android NDK, has neither or . +# define GTEST_HAS_TR1_TUPLE 0 +# else +// The user didn't tell us not to do it, so we assume it's OK. +# define GTEST_HAS_TR1_TUPLE 1 +# endif +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether Google Test's own tr1 tuple implementation +// should be used. +#ifndef GTEST_USE_OWN_TR1_TUPLE +// The user didn't tell us, so we need to figure it out. + +// We use our own TR1 tuple if we aren't sure the user has an +// implementation of it already. At this time, libstdc++ 4.0.0+ and +// MSVC 2010 are the only mainstream standard libraries that come +// with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler +// pretends to be GCC by defining __GNUC__ and friends, but cannot +// compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 +// tuple in a 323 MB Feature Pack download, which we cannot assume the +// user has. QNX's QCC compiler is a modified GCC but it doesn't +// support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, +// and it can be used with some compilers that define __GNUC__. +# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ + && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 +# define GTEST_ENV_HAS_TR1_TUPLE_ 1 +# endif + +// C++11 specifies that provides std::tuple. Use that if gtest is used +// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 +// can build with clang but need to use gcc4.2's libstdc++). +# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) +# define GTEST_ENV_HAS_STD_TUPLE_ 1 +# endif + +# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ +# define GTEST_USE_OWN_TR1_TUPLE 0 +# else +# define GTEST_USE_OWN_TR1_TUPLE 1 +# endif + +#endif // GTEST_USE_OWN_TR1_TUPLE + +// To avoid conditional compilation everywhere, we make it +// gtest-port.h's responsibility to #include the header implementing +// tr1/tuple. +#if GTEST_HAS_TR1_TUPLE + +# if GTEST_USE_OWN_TR1_TUPLE +// This file was GENERATED by command: +// pump.py gtest-tuple.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2009 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements a subset of TR1 tuple needed by Google Test and Google Mock. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ + +#include // For ::std::pair. + +// The compiler used in Symbian has a bug that prevents us from declaring the +// tuple template as a friend (it complains that tuple is redefined). This +// hack bypasses the bug by declaring the members that should otherwise be +// private as public. +// Sun Studio versions < 12 also have the above bug. +#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: +#else +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ + template friend class tuple; \ + private: +#endif + +// GTEST_n_TUPLE_(T) is the type of an n-tuple. +#define GTEST_0_TUPLE_(T) tuple<> +#define GTEST_1_TUPLE_(T) tuple +#define GTEST_2_TUPLE_(T) tuple +#define GTEST_3_TUPLE_(T) tuple +#define GTEST_4_TUPLE_(T) tuple +#define GTEST_5_TUPLE_(T) tuple +#define GTEST_6_TUPLE_(T) tuple +#define GTEST_7_TUPLE_(T) tuple +#define GTEST_8_TUPLE_(T) tuple +#define GTEST_9_TUPLE_(T) tuple +#define GTEST_10_TUPLE_(T) tuple + +// GTEST_n_TYPENAMES_(T) declares a list of n typenames. +#define GTEST_0_TYPENAMES_(T) +#define GTEST_1_TYPENAMES_(T) typename T##0 +#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 +#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 +#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3 +#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4 +#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5 +#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6 +#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 +#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8 +#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8, typename T##9 + +// In theory, defining stuff in the ::std namespace is undefined +// behavior. We can do this as we are playing the role of a standard +// library vendor. +namespace std { +namespace tr1 { + +template +class tuple; + +// Anything in namespace gtest_internal is Google Test's INTERNAL +// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. +namespace gtest_internal { + +// ByRef::type is T if T is a reference; otherwise it's const T&. +template +struct ByRef { typedef const T& type; }; // NOLINT +template +struct ByRef { typedef T& type; }; // NOLINT + +// A handy wrapper for ByRef. +#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type + +// AddRef::type is T if T is a reference; otherwise it's T&. This +// is the same as tr1::add_reference::type. +template +struct AddRef { typedef T& type; }; // NOLINT +template +struct AddRef { typedef T& type; }; // NOLINT + +// A handy wrapper for AddRef. +#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type + +// A helper for implementing get(). +template class Get; + +// A helper for implementing tuple_element. kIndexValid is true +// iff k < the number of fields in tuple type T. +template +struct TupleElement; + +template +struct TupleElement { + typedef T0 type; +}; + +template +struct TupleElement { + typedef T1 type; +}; + +template +struct TupleElement { + typedef T2 type; +}; + +template +struct TupleElement { + typedef T3 type; +}; + +template +struct TupleElement { + typedef T4 type; +}; + +template +struct TupleElement { + typedef T5 type; +}; + +template +struct TupleElement { + typedef T6 type; +}; + +template +struct TupleElement { + typedef T7 type; +}; + +template +struct TupleElement { + typedef T8 type; +}; + +template +struct TupleElement { + typedef T9 type; +}; + +} // namespace gtest_internal + +template <> +class tuple<> { + public: + tuple() {} + tuple(const tuple& /* t */) {} + tuple& operator=(const tuple& /* t */) { return *this; } +}; + +template +class GTEST_1_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} + + tuple(const tuple& t) : f0_(t.f0_) {} + + template + tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_1_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { + f0_ = t.f0_; + return *this; + } + + T0 f0_; +}; + +template +class GTEST_2_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), + f1_(f1) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} + + template + tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} + template + tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_2_TUPLE_(U)& t) { + return CopyFrom(t); + } + template + tuple& operator=(const ::std::pair& p) { + f0_ = p.first; + f1_ = p.second; + return *this; + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + return *this; + } + + T0 f0_; + T1 f1_; +}; + +template +class GTEST_3_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + template + tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_3_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; +}; + +template +class GTEST_4_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} + + template + tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_4_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; +}; + +template +class GTEST_5_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, + GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_) {} + + template + tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_5_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; +}; + +template +class GTEST_6_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_) {} + + template + tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_6_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; +}; + +template +class GTEST_7_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + template + tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_7_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; +}; + +template +class GTEST_8_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, + GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + template + tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_8_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; +}; + +template +class GTEST_9_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + template + tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_9_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; +}; + +template +class tuple { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), + f9_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} + + template + tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), + f9_(t.f9_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_10_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + f9_ = t.f9_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; + T9 f9_; +}; + +// 6.1.3.2 Tuple creation functions. + +// Known limitations: we don't support passing an +// std::tr1::reference_wrapper to make_tuple(). And we don't +// implement tie(). + +inline tuple<> make_tuple() { return tuple<>(); } + +template +inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { + return GTEST_1_TUPLE_(T)(f0); +} + +template +inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { + return GTEST_2_TUPLE_(T)(f0, f1); +} + +template +inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { + return GTEST_3_TUPLE_(T)(f0, f1, f2); +} + +template +inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3) { + return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); +} + +template +inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4) { + return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); +} + +template +inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5) { + return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); +} + +template +inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6) { + return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); +} + +template +inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { + return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); +} + +template +inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8) { + return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); +} + +template +inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8, const T9& f9) { + return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); +} + +// 6.1.3.3 Tuple helper classes. + +template struct tuple_size; + +template +struct tuple_size { + static const int value = 0; +}; + +template +struct tuple_size { + static const int value = 1; +}; + +template +struct tuple_size { + static const int value = 2; +}; + +template +struct tuple_size { + static const int value = 3; +}; + +template +struct tuple_size { + static const int value = 4; +}; + +template +struct tuple_size { + static const int value = 5; +}; + +template +struct tuple_size { + static const int value = 6; +}; + +template +struct tuple_size { + static const int value = 7; +}; + +template +struct tuple_size { + static const int value = 8; +}; + +template +struct tuple_size { + static const int value = 9; +}; + +template +struct tuple_size { + static const int value = 10; +}; + +template +struct tuple_element { + typedef typename gtest_internal::TupleElement< + k < (tuple_size::value), k, Tuple>::type type; +}; + +#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type + +// 6.1.3.4 Element access. + +namespace gtest_internal { + +template <> +class Get<0> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + Field(Tuple& t) { return t.f0_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + ConstField(const Tuple& t) { return t.f0_; } +}; + +template <> +class Get<1> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + Field(Tuple& t) { return t.f1_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + ConstField(const Tuple& t) { return t.f1_; } +}; + +template <> +class Get<2> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + Field(Tuple& t) { return t.f2_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + ConstField(const Tuple& t) { return t.f2_; } +}; + +template <> +class Get<3> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + Field(Tuple& t) { return t.f3_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + ConstField(const Tuple& t) { return t.f3_; } +}; + +template <> +class Get<4> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + Field(Tuple& t) { return t.f4_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + ConstField(const Tuple& t) { return t.f4_; } +}; + +template <> +class Get<5> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + Field(Tuple& t) { return t.f5_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + ConstField(const Tuple& t) { return t.f5_; } +}; + +template <> +class Get<6> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + Field(Tuple& t) { return t.f6_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + ConstField(const Tuple& t) { return t.f6_; } +}; + +template <> +class Get<7> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + Field(Tuple& t) { return t.f7_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + ConstField(const Tuple& t) { return t.f7_; } +}; + +template <> +class Get<8> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + Field(Tuple& t) { return t.f8_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + ConstField(const Tuple& t) { return t.f8_; } +}; + +template <> +class Get<9> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + Field(Tuple& t) { return t.f9_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + ConstField(const Tuple& t) { return t.f9_; } +}; + +} // namespace gtest_internal + +template +GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::Field(t); +} + +template +GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(const GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::ConstField(t); +} + +// 6.1.3.5 Relational operators + +// We only implement == and !=, as we don't have a need for the rest yet. + +namespace gtest_internal { + +// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the +// first k fields of t1 equals the first k fields of t2. +// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if +// k1 != k2. +template +struct SameSizeTuplePrefixComparator; + +template <> +struct SameSizeTuplePrefixComparator<0, 0> { + template + static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { + return true; + } +}; + +template +struct SameSizeTuplePrefixComparator { + template + static bool Eq(const Tuple1& t1, const Tuple2& t2) { + return SameSizeTuplePrefixComparator::Eq(t1, t2) && + ::std::tr1::get(t1) == ::std::tr1::get(t2); + } +}; + +} // namespace gtest_internal + +template +inline bool operator==(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { + return gtest_internal::SameSizeTuplePrefixComparator< + tuple_size::value, + tuple_size::value>::Eq(t, u); +} + +template +inline bool operator!=(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { return !(t == u); } + +// 6.1.4 Pairs. +// Unimplemented. + +} // namespace tr1 +} // namespace std + +#undef GTEST_0_TUPLE_ +#undef GTEST_1_TUPLE_ +#undef GTEST_2_TUPLE_ +#undef GTEST_3_TUPLE_ +#undef GTEST_4_TUPLE_ +#undef GTEST_5_TUPLE_ +#undef GTEST_6_TUPLE_ +#undef GTEST_7_TUPLE_ +#undef GTEST_8_TUPLE_ +#undef GTEST_9_TUPLE_ +#undef GTEST_10_TUPLE_ + +#undef GTEST_0_TYPENAMES_ +#undef GTEST_1_TYPENAMES_ +#undef GTEST_2_TYPENAMES_ +#undef GTEST_3_TYPENAMES_ +#undef GTEST_4_TYPENAMES_ +#undef GTEST_5_TYPENAMES_ +#undef GTEST_6_TYPENAMES_ +#undef GTEST_7_TYPENAMES_ +#undef GTEST_8_TYPENAMES_ +#undef GTEST_9_TYPENAMES_ +#undef GTEST_10_TYPENAMES_ + +#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ +#undef GTEST_BY_REF_ +#undef GTEST_ADD_REF_ +#undef GTEST_TUPLE_ELEMENT_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +# elif GTEST_ENV_HAS_STD_TUPLE_ +# include +// C++11 puts its tuple into the ::std namespace rather than +// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. +// This causes undefined behavior, but supported compilers react in +// the way we intend. +namespace std { +namespace tr1 { +using ::std::get; +using ::std::make_tuple; +using ::std::tuple; +using ::std::tuple_element; +using ::std::tuple_size; +} +} + +# elif GTEST_OS_SYMBIAN + +// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to +// use STLport's tuple implementation, which unfortunately doesn't +// work as the copy of STLport distributed with Symbian is incomplete. +// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to +// use its own tuple implementation. +# ifdef BOOST_HAS_TR1_TUPLE +# undef BOOST_HAS_TR1_TUPLE +# endif // BOOST_HAS_TR1_TUPLE + +// This prevents , which defines +// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . +# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED +# include + +# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) +// GCC 4.0+ implements tr1/tuple in the header. This does +// not conform to the TR1 spec, which requires the header to be . + +# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 +// Until version 4.3.2, gcc has a bug that causes , +// which is #included by , to not compile when RTTI is +// disabled. _TR1_FUNCTIONAL is the header guard for +// . Hence the following #define is a hack to prevent +// from being included. +# define _TR1_FUNCTIONAL 1 +# include +# undef _TR1_FUNCTIONAL // Allows the user to #include + // if he chooses to. +# else +# include // NOLINT +# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 + +# else +// If the compiler is not GCC 4.0+, we assume the user is using a +// spec-conforming TR1 implementation. +# include // NOLINT +# endif // GTEST_USE_OWN_TR1_TUPLE + +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether clone(2) is supported. +// Usually it will only be available on Linux, excluding +// Linux on the Itanium architecture. +// Also see http://linux.die.net/man/2/clone. +#ifndef GTEST_HAS_CLONE +// The user didn't tell us, so we need to figure it out. + +# if GTEST_OS_LINUX && !defined(__ia64__) +# if GTEST_OS_LINUX_ANDROID +// On Android, clone() is only available on ARM starting with Gingerbread. +# if defined(__arm__) && __ANDROID_API__ >= 9 +# define GTEST_HAS_CLONE 1 +# else +# define GTEST_HAS_CLONE 0 +# endif +# else +# define GTEST_HAS_CLONE 1 +# endif +# else +# define GTEST_HAS_CLONE 0 +# endif // GTEST_OS_LINUX && !defined(__ia64__) + +#endif // GTEST_HAS_CLONE + +// Determines whether to support stream redirection. This is used to test +// output correctness and to implement death tests. +#ifndef GTEST_HAS_STREAM_REDIRECTION +// By default, we assume that stream redirection is supported on all +// platforms except known mobile ones. +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN +# define GTEST_HAS_STREAM_REDIRECTION 0 +# else +# define GTEST_HAS_STREAM_REDIRECTION 1 +# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +#endif // GTEST_HAS_STREAM_REDIRECTION + +// Determines whether to support death tests. +// Google Test does not support death tests for VC 7.1 and earlier as +// abort() in a VC 7.1 application compiled as GUI in debug config +// pops up a dialog window that cannot be suppressed programmatically. +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ + GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ + GTEST_OS_OPENBSD || GTEST_OS_QNX) +# define GTEST_HAS_DEATH_TEST 1 +# include // NOLINT +#endif + +// We don't support MSVC 7.1 with exceptions disabled now. Therefore +// all the compilers we care about are adequate for supporting +// value-parameterized tests. +#define GTEST_HAS_PARAM_TEST 1 + +// Determines whether to support type-driven tests. + +// Typed tests need and variadic macros, which GCC, VC++ 8.0, +// Sun Pro CC, IBM Visual Age, and HP aCC support. +#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ + defined(__IBMCPP__) || defined(__HP_aCC) +# define GTEST_HAS_TYPED_TEST 1 +# define GTEST_HAS_TYPED_TEST_P 1 +#endif + +// Determines whether to support Combine(). This only makes sense when +// value-parameterized tests are enabled. The implementation doesn't +// work on Sun Studio since it doesn't understand templated conversion +// operators. +#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) +# define GTEST_HAS_COMBINE 1 +#endif + +// Determines whether the system compiler uses UTF-16 for encoding wide strings. +#define GTEST_WIDE_STRING_USES_UTF16_ \ + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + +// Determines whether test results can be streamed to a socket. +#if GTEST_OS_LINUX +# define GTEST_CAN_STREAM_RESULTS_ 1 +#endif + +// Defines some utility macros. + +// The GNU compiler emits a warning if nested "if" statements are followed by +// an "else" statement and braces are not used to explicitly disambiguate the +// "else" binding. This leads to problems with code like: +// +// if (gate) +// ASSERT_*(condition) << "Some message"; +// +// The "switch (0) case 0:" idiom is used to suppress this. +#ifdef __INTEL_COMPILER +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ +#else +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT +#endif + +// Use this annotation at the end of a struct/class definition to +// prevent the compiler from optimizing away instances that are never +// used. This is useful when all interesting logic happens inside the +// c'tor and / or d'tor. Example: +// +// struct Foo { +// Foo() { ... } +// } GTEST_ATTRIBUTE_UNUSED_; +// +// Also use it after a variable or parameter declaration to tell the +// compiler the variable/parameter does not have to be used. +#if defined(__GNUC__) && !defined(COMPILER_ICC) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +#else +# define GTEST_ATTRIBUTE_UNUSED_ +#endif + +// A macro to disallow operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_ASSIGN_(type)\ + void operator=(type const &) + +// A macro to disallow copy constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ + type(type const &);\ + GTEST_DISALLOW_ASSIGN_(type) + +// Tell the compiler to warn about unused return values for functions declared +// with this macro. The macro should be used on function declarations +// following the argument list: +// +// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; +#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) +# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) +#else +# define GTEST_MUST_USE_RESULT_ +#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC + +// Determine whether the compiler supports Microsoft's Structured Exception +// Handling. This is supported by several Windows compilers but generally +// does not exist on any other system. +#ifndef GTEST_HAS_SEH +// The user didn't tell us, so we need to figure it out. + +# if defined(_MSC_VER) || defined(__BORLANDC__) +// These two compilers are known to support SEH. +# define GTEST_HAS_SEH 1 +# else +// Assume no SEH. +# define GTEST_HAS_SEH 0 +# endif + +#endif // GTEST_HAS_SEH + +#ifdef _MSC_VER + +# if GTEST_LINKED_AS_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllimport) +# elif GTEST_CREATE_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllexport) +# endif + +#endif // _MSC_VER + +#ifndef GTEST_API_ +# define GTEST_API_ +#endif + +#ifdef __GNUC__ +// Ask the compiler to never inline a given function. +# define GTEST_NO_INLINE_ __attribute__((noinline)) +#else +# define GTEST_NO_INLINE_ +#endif + +// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. +#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) +# define GTEST_HAS_CXXABI_H_ 1 +#else +# define GTEST_HAS_CXXABI_H_ 0 +#endif + +namespace testing { + +class Message; + +namespace internal { + +// A secret type that Google Test users don't know about. It has no +// definition on purpose. Therefore it's impossible to create a +// Secret object, which is what we want. +class Secret; + +// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +template +struct CompileAssert { +}; + +#define GTEST_COMPILE_ASSERT_(expr, msg) \ + typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ + msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ + +// Implementation details of GTEST_COMPILE_ASSERT_: +// +// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outter parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// GTEST_COMPILE_ASSERT_(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. +// +// This template is declared, but intentionally undefined. +template +struct StaticAssertTypeEqHelper; + +template +struct StaticAssertTypeEqHelper {}; + +#if GTEST_HAS_GLOBAL_STRING +typedef ::string string; +#else +typedef ::std::string string; +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_GLOBAL_WSTRING +typedef ::wstring wstring; +#elif GTEST_HAS_STD_WSTRING +typedef ::std::wstring wstring; +#endif // GTEST_HAS_GLOBAL_WSTRING + +// A helper for suppressing warnings on constant condition. It just +// returns 'condition'. +GTEST_API_ bool IsTrue(bool condition); + +// Defines scoped_ptr. + +// This implementation of scoped_ptr is PARTIAL - it only contains +// enough stuff to satisfy Google Test's need. +template +class scoped_ptr { + public: + typedef T element_type; + + explicit scoped_ptr(T* p = NULL) : ptr_(p) {} + ~scoped_ptr() { reset(); } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + T* get() const { return ptr_; } + + T* release() { + T* const ptr = ptr_; + ptr_ = NULL; + return ptr; + } + + void reset(T* p = NULL) { + if (p != ptr_) { + if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. + delete ptr_; + } + ptr_ = p; + } + } + + private: + T* ptr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); +}; + +// Defines RE. + +// A simple C++ wrapper for . It uses the POSIX Extended +// Regular Expression syntax. +class GTEST_API_ RE { + public: + // A copy constructor is required by the Standard to initialize object + // references from r-values. + RE(const RE& other) { Init(other.pattern()); } + + // Constructs an RE from a string. + RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT + +#if GTEST_HAS_GLOBAL_STRING + + RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT + +#endif // GTEST_HAS_GLOBAL_STRING + + RE(const char* regex) { Init(regex); } // NOLINT + ~RE(); + + // Returns the string representation of the regex. + const char* pattern() const { return pattern_; } + + // FullMatch(str, re) returns true iff regular expression re matches + // the entire str. + // PartialMatch(str, re) returns true iff regular expression re + // matches a substring of str (including str itself). + // + // TODO(wan@google.com): make FullMatch() and PartialMatch() work + // when str contains NUL characters. + static bool FullMatch(const ::std::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::std::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#if GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const ::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#endif // GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const char* str, const RE& re); + static bool PartialMatch(const char* str, const RE& re); + + private: + void Init(const char* regex); + + // We use a const char* instead of an std::string, as Google Test used to be + // used where std::string is not available. TODO(wan@google.com): change to + // std::string. + const char* pattern_; + bool is_valid_; + +#if GTEST_USES_POSIX_RE + + regex_t full_regex_; // For FullMatch(). + regex_t partial_regex_; // For PartialMatch(). + +#else // GTEST_USES_SIMPLE_RE + + const char* full_pattern_; // For FullMatch(); + +#endif + + GTEST_DISALLOW_ASSIGN_(RE); +}; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, + int line); + +// Defines logging utilities: +// GTEST_LOG_(severity) - logs messages at the specified severity level. The +// message itself is streamed into the macro. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. + +enum GTestLogSeverity { + GTEST_INFO, + GTEST_WARNING, + GTEST_ERROR, + GTEST_FATAL +}; + +// Formats log entry severity, provides a stream object for streaming the +// log message, and terminates the message with a newline when going out of +// scope. +class GTEST_API_ GTestLog { + public: + GTestLog(GTestLogSeverity severity, const char* file, int line); + + // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. + ~GTestLog(); + + ::std::ostream& GetStream() { return ::std::cerr; } + + private: + const GTestLogSeverity severity_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); +}; + +#define GTEST_LOG_(severity) \ + ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ + __FILE__, __LINE__).GetStream() + +inline void LogToStderr() {} +inline void FlushInfoLog() { fflush(NULL); } + +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +#define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " + +// An all-mode assert to verify that the given POSIX-style function +// call returns 0 (indicating success). Known limitation: this +// doesn't expand to a balanced 'if' statement, so enclose the macro +// in {} if you need to use it as the only statement in an 'if' +// branch. +#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ + if (const int gtest_error = (posix_call)) \ + GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ + << gtest_error + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Use ImplicitCast_ as a safe version of static_cast for upcasting in +// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a +// const Foo*). When you use ImplicitCast_, the compiler checks that +// the cast is safe. Such explicit ImplicitCast_s are necessary in +// surprisingly many situations where C++ demands an exact type match +// instead of an argument type convertable to a target type. +// +// The syntax for using ImplicitCast_ is the same as for static_cast: +// +// ImplicitCast_(expr) +// +// ImplicitCast_ would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., implicit_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template +inline To ImplicitCast_(To x) { return x; } + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., down_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template // use like this: DownCast_(foo); +inline To DownCast_(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + const To to = NULL; + ::testing::internal::ImplicitCast_(to); + } + +#if GTEST_HAS_RTTI + // RTTI: debug mode only! + GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); +#endif + return static_cast(f); +} + +// Downcasts the pointer of type Base to Derived. +// Derived must be a subclass of Base. The parameter MUST +// point to a class of type Derived, not any subclass of it. +// When RTTI is available, the function performs a runtime +// check to enforce this. +template +Derived* CheckedDowncastToActualType(Base* base) { +#if GTEST_HAS_RTTI + GTEST_CHECK_(typeid(*base) == typeid(Derived)); + return dynamic_cast(base); // NOLINT +#else + return static_cast(base); // Poor man's downcast. +#endif +} + +#if GTEST_HAS_STREAM_REDIRECTION + +// Defines the stderr capturer: +// CaptureStdout - starts capturing stdout. +// GetCapturedStdout - stops capturing stdout and returns the captured string. +// CaptureStderr - starts capturing stderr. +// GetCapturedStderr - stops capturing stderr and returns the captured string. +// +GTEST_API_ void CaptureStdout(); +GTEST_API_ std::string GetCapturedStdout(); +GTEST_API_ void CaptureStderr(); +GTEST_API_ std::string GetCapturedStderr(); + +#endif // GTEST_HAS_STREAM_REDIRECTION + + +#if GTEST_HAS_DEATH_TEST + +const ::std::vector& GetInjectableArgvs(); +void SetInjectableArgvs(const ::std::vector* + new_argvs); + +// A copy of all command line arguments. Set by InitGoogleTest(). +extern ::std::vector g_argvs; + +#endif // GTEST_HAS_DEATH_TEST + +// Defines synchronization primitives. + +#if GTEST_HAS_PTHREAD + +// Sleeps for (roughly) n milli-seconds. This function is only for +// testing Google Test's own constructs. Don't use it in user tests, +// either directly or indirectly. +inline void SleepMilliseconds(int n) { + const timespec time = { + 0, // 0 seconds. + n * 1000L * 1000L, // And n ms. + }; + nanosleep(&time, NULL); +} + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class Notification { + public: + Notification() : notified_(false) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + } + ~Notification() { + pthread_mutex_destroy(&mutex_); + } + + // Notifies all threads created with this notification to start. Must + // be called from the controller thread. + void Notify() { + pthread_mutex_lock(&mutex_); + notified_ = true; + pthread_mutex_unlock(&mutex_); + } + + // Blocks until the controller thread notifies. Must be called from a test + // thread. + void WaitForNotification() { + for (;;) { + pthread_mutex_lock(&mutex_); + const bool notified = notified_; + pthread_mutex_unlock(&mutex_); + if (notified) + break; + SleepMilliseconds(10); + } + } + + private: + pthread_mutex_t mutex_; + bool notified_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; + +// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. +// Consequently, it cannot select a correct instantiation of ThreadWithParam +// in order to call its Run(). Introducing ThreadWithParamBase as a +// non-templated base class for ThreadWithParam allows us to bypass this +// problem. +class ThreadWithParamBase { + public: + virtual ~ThreadWithParamBase() {} + virtual void Run() = 0; +}; + +// pthread_create() accepts a pointer to a function type with the C linkage. +// According to the Standard (7.5/1), function types with different linkages +// are different even if they are otherwise identical. Some compilers (for +// example, SunStudio) treat them as different types. Since class methods +// cannot be defined with C-linkage we need to define a free C-function to +// pass into pthread_create(). +extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { + static_cast(thread)->Run(); + return NULL; +} + +// Helper class for testing Google Test's multi-threading constructs. +// To use it, write: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// Notification thread_can_start; +// ... +// // The thread_can_start parameter is optional; you can supply NULL. +// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); +// thread_can_start.Notify(); +// +// These classes are only for testing Google Test's own constructs. Do +// not use them in user tests, either directly or indirectly. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void (*UserThreadFunc)(T); + + ThreadWithParam( + UserThreadFunc func, T param, Notification* thread_can_start) + : func_(func), + param_(param), + thread_can_start_(thread_can_start), + finished_(false) { + ThreadWithParamBase* const base = this; + // The thread can be created only after all fields except thread_ + // have been initialized. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + } + ~ThreadWithParam() { Join(); } + + void Join() { + if (!finished_) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + finished_ = true; + } + } + + virtual void Run() { + if (thread_can_start_ != NULL) + thread_can_start_->WaitForNotification(); + func_(param_); + } + + private: + const UserThreadFunc func_; // User-supplied thread function. + const T param_; // User-supplied parameter to the thread function. + // When non-NULL, used to block execution until the controller thread + // notifies. + Notification* const thread_can_start_; + bool finished_; // true iff we know that the thread function has finished. + pthread_t thread_; // The native thread object. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// MutexBase and Mutex implement mutex on pthreads-based platforms. They +// are used in conjunction with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end +// // of the current scope. +// +// MutexBase implements behavior for both statically and dynamically +// allocated mutexes. Do not use MutexBase directly. Instead, write +// the following to define a static mutex: +// +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// +// You can forward declare a static mutex like this: +// +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// To create a dynamic mutex, just define an object of type Mutex. +class MutexBase { + public: + // Acquires this mutex. + void Lock() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); + owner_ = pthread_self(); + has_owner_ = true; + } + + // Releases this mutex. + void Unlock() { + // Since the lock is being released the owner_ field should no longer be + // considered valid. We don't protect writing to has_owner_ here, as it's + // the caller's responsibility to ensure that the current thread holds the + // mutex when this is called. + has_owner_ = false; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); + } + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const { + GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) + << "The current thread is not holding the mutex @" << this; + } + + // A static mutex may be used before main() is entered. It may even + // be used before the dynamic initialization stage. Therefore we + // must be able to initialize a static mutex object at link time. + // This means MutexBase has to be a POD and its member variables + // have to be public. + public: + pthread_mutex_t mutex_; // The underlying pthread mutex. + // has_owner_ indicates whether the owner_ field below contains a valid thread + // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All + // accesses to the owner_ field should be protected by a check of this field. + // An alternative might be to memset() owner_ to all zeros, but there's no + // guarantee that a zero'd pthread_t is necessarily invalid or even different + // from pthread_self(). + bool has_owner_; + pthread_t owner_; // The thread holding the mutex. +}; + +// Forward-declares a static mutex. +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically (i.e. at link time) initializes a static mutex. +// The initialization list here does not explicitly initialize each field, +// instead relying on default initialization for the unspecified fields. In +// particular, the owner_ field (a pthread_t) is not explicitly initialized. +// This allows initialization to work whether pthread_t is a scalar or struct. +// The flag -Wmissing-field-initializers must not be specified for this to work. +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } + +// The Mutex class can only be used for mutexes created at runtime. It +// shares its API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + has_owner_ = false; + } + ~Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot name this class MutexLock as the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Helpers for ThreadLocal. + +// pthread_key_create() requires DeleteThreadLocalValue() to have +// C-linkage. Therefore it cannot be templatized to access +// ThreadLocal. Hence the need for class +// ThreadLocalValueHolderBase. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Called by pthread to delete thread-local data stored by +// pthread_setspecific(). +extern "C" inline void DeleteThreadLocalValue(void* value_holder) { + delete static_cast(value_holder); +} + +// Implements thread-local storage on pthreads-based systems. +// +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. +// +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// An object managed for a thread by a ThreadLocal instance is deleted +// when the thread exits. Or, if the ThreadLocal instance dies in +// that thread, when the ThreadLocal dies. It's the user's +// responsibility to ensure that all other threads using a ThreadLocal +// have exited when it dies, or the per-thread objects for those +// threads will not be deleted. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal { + public: + ThreadLocal() : key_(CreateKey()), + default_() {} + explicit ThreadLocal(const T& value) : key_(CreateKey()), + default_(value) {} + + ~ThreadLocal() { + // Destroys the managed object for the current thread, if any. + DeleteThreadLocalValue(pthread_getspecific(key_)); + + // Releases resources associated with the key. This will *not* + // delete managed objects for other threads. + GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of type T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + static pthread_key_t CreateKey() { + pthread_key_t key; + // When a thread exits, DeleteThreadLocalValue() will be called on + // the object managed for that thread. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_key_create(&key, &DeleteThreadLocalValue)); + return key; + } + + T* GetOrCreateValue() const { + ThreadLocalValueHolderBase* const holder = + static_cast(pthread_getspecific(key_)); + if (holder != NULL) { + return CheckedDowncastToActualType(holder)->pointer(); + } + + ValueHolder* const new_holder = new ValueHolder(default_); + ThreadLocalValueHolderBase* const holder_base = new_holder; + GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); + return new_holder->pointer(); + } + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + const T default_; // The default value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# define GTEST_IS_THREADSAFE 1 + +#else // GTEST_HAS_PTHREAD + +// A dummy implementation of synchronization primitives (mutex, lock, +// and thread-local variable). Necessary for compiling Google Test where +// mutex is not supported - using Google Test in multiple threads is not +// supported on such platforms. + +class Mutex { + public: + Mutex() {} + void Lock() {} + void Unlock() {} + void AssertHeld() const {} +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex*) {} // NOLINT +}; + +typedef GTestMutexLock MutexLock; + +template +class ThreadLocal { + public: + ThreadLocal() : value_() {} + explicit ThreadLocal(const T& value) : value_(value) {} + T* pointer() { return &value_; } + const T* pointer() const { return &value_; } + const T& get() const { return value_; } + void set(const T& value) { value_ = value; } + private: + T value_; +}; + +// The above synchronization primitives have dummy implementations. +// Therefore Google Test is not thread-safe. +# define GTEST_IS_THREADSAFE 0 + +#endif // GTEST_HAS_PTHREAD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +GTEST_API_ size_t GetThreadCount(); + +// Passing non-POD classes through ellipsis (...) crashes the ARM +// compiler and generates a warning in Sun Studio. The Nokia Symbian +// and the IBM XL C/C++ compiler try to instantiate a copy constructor +// for objects passed through ellipsis (...), failing for uncopyable +// objects. We define this to ensure that only POD is passed through +// ellipsis on these systems. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +# define GTEST_ELLIPSIS_NEEDS_POD_ 1 +#else +# define GTEST_CAN_COMPARE_NULL 1 +#endif + +// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between +// const T& and const T* in a function template. These compilers +// _can_ decide between class template specializations for T and T*, +// so a tr1::type_traits-like is_pointer works. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) +# define GTEST_NEEDS_IS_POINTER_ 1 +#endif + +template +struct bool_constant { + typedef bool_constant type; + static const bool value = bool_value; +}; +template const bool bool_constant::value; + +typedef bool_constant false_type; +typedef bool_constant true_type; + +template +struct is_pointer : public false_type {}; + +template +struct is_pointer : public true_type {}; + +template +struct IteratorTraits { + typedef typename Iterator::value_type value_type; +}; + +template +struct IteratorTraits { + typedef T value_type; +}; + +template +struct IteratorTraits { + typedef T value_type; +}; + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_SEP_ "\\" +# define GTEST_HAS_ALT_PATH_SEP_ 1 +// The biggest signed integer type the compiler supports. +typedef __int64 BiggestInt; +#else +# define GTEST_PATH_SEP_ "/" +# define GTEST_HAS_ALT_PATH_SEP_ 0 +typedef long long BiggestInt; // NOLINT +#endif // GTEST_OS_WINDOWS + +// Utilities for char. + +// isspace(int ch) and friends accept an unsigned char or EOF. char +// may be signed, depending on the compiler (or compiler flags). +// Therefore we need to cast a char to unsigned char before calling +// isspace(), etc. + +inline bool IsAlpha(char ch) { + return isalpha(static_cast(ch)) != 0; +} +inline bool IsAlNum(char ch) { + return isalnum(static_cast(ch)) != 0; +} +inline bool IsDigit(char ch) { + return isdigit(static_cast(ch)) != 0; +} +inline bool IsLower(char ch) { + return islower(static_cast(ch)) != 0; +} +inline bool IsSpace(char ch) { + return isspace(static_cast(ch)) != 0; +} +inline bool IsUpper(char ch) { + return isupper(static_cast(ch)) != 0; +} +inline bool IsXDigit(char ch) { + return isxdigit(static_cast(ch)) != 0; +} +inline bool IsXDigit(wchar_t ch) { + const unsigned char low_byte = static_cast(ch); + return ch == low_byte && isxdigit(low_byte) != 0; +} + +inline char ToLower(char ch) { + return static_cast(tolower(static_cast(ch))); +} +inline char ToUpper(char ch) { + return static_cast(toupper(static_cast(ch))); +} + +// The testing::internal::posix namespace holds wrappers for common +// POSIX functions. These wrappers hide the differences between +// Windows/MSVC and POSIX systems. Since some compilers define these +// standard functions as macros, the wrapper cannot have the same name +// as the wrapped function. + +namespace posix { + +// Functions with a different name on Windows. + +#if GTEST_OS_WINDOWS + +typedef struct _stat StatStruct; + +# ifdef __BORLANDC__ +inline int IsATTY(int fd) { return isatty(fd); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +# else // !__BORLANDC__ +# if GTEST_OS_WINDOWS_MOBILE +inline int IsATTY(int /* fd */) { return 0; } +# else +inline int IsATTY(int fd) { return _isatty(fd); } +# endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return _strdup(src); } +# endif // __BORLANDC__ + +# if GTEST_OS_WINDOWS_MOBILE +inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this +// time and thus not defined there. +# else +inline int FileNo(FILE* file) { return _fileno(file); } +inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } +inline int RmDir(const char* dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct& st) { + return (_S_IFDIR & st.st_mode) != 0; +} +# endif // GTEST_OS_WINDOWS_MOBILE + +#else + +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int IsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + +#endif // GTEST_OS_WINDOWS + +// Functions deprecated by MSVC 8.0. + +#ifdef _MSC_VER +// Temporarily disable warning 4996 (deprecated function). +# pragma warning(push) +# pragma warning(disable:4996) +#endif + +inline const char* StrNCpy(char* dest, const char* src, size_t n) { + return strncpy(dest, src, n); +} + +// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and +// StrError() aren't needed on Windows CE at this time and thus not +// defined there. + +#if !GTEST_OS_WINDOWS_MOBILE +inline int ChDir(const char* dir) { return chdir(dir); } +#endif +inline FILE* FOpen(const char* path, const char* mode) { + return fopen(path, mode); +} +#if !GTEST_OS_WINDOWS_MOBILE +inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { + return freopen(path, mode, stream); +} +inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +#endif +inline int FClose(FILE* fp) { return fclose(fp); } +#if !GTEST_OS_WINDOWS_MOBILE +inline int Read(int fd, void* buf, unsigned int count) { + return static_cast(read(fd, buf, count)); +} +inline int Write(int fd, const void* buf, unsigned int count) { + return static_cast(write(fd, buf, count)); +} +inline int Close(int fd) { return close(fd); } +inline const char* StrError(int errnum) { return strerror(errnum); } +#endif +inline const char* GetEnv(const char* name) { +#if GTEST_OS_WINDOWS_MOBILE + // We are on Windows CE, which has no environment variables. + return NULL; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // Environment variables which we programmatically clear will be set to the + // empty string rather than unset (NULL). Handle that case. + const char* const env = getenv(name); + return (env != NULL && env[0] != '\0') ? env : NULL; +#else + return getenv(name); +#endif +} + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif + +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +void Abort(); +#else +inline void Abort() { abort(); } +#endif // GTEST_OS_WINDOWS_MOBILE + +} // namespace posix + +// MSVC "deprecates" snprintf and issues warnings wherever it is used. In +// order to avoid these warnings, we need to use _snprintf or _snprintf_s on +// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate +// function in order to achieve that. We use macro definition here because +// snprintf is a variadic function. +#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +// MSVC 2005 and above support variadic macros. +# define GTEST_SNPRINTF_(buffer, size, format, ...) \ + _snprintf_s(buffer, size, size, format, __VA_ARGS__) +#elif defined(_MSC_VER) +// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't +// complain about _snprintf. +# define GTEST_SNPRINTF_ _snprintf +#else +# define GTEST_SNPRINTF_ snprintf +#endif + +// The maximum number a BiggestInt can represent. This definition +// works no matter BiggestInt is represented in one's complement or +// two's complement. +// +// We cannot rely on numeric_limits in STL, as __int64 and long long +// are not part of standard C++ and numeric_limits doesn't need to be +// defined for them. +const BiggestInt kMaxBiggestInt = + ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); + +// This template class serves as a compile-time function from size to +// type. It maps a size in bytes to a primitive type with that +// size. e.g. +// +// TypeWithSize<4>::UInt +// +// is typedef-ed to be unsigned int (unsigned integer made up of 4 +// bytes). +// +// Such functionality should belong to STL, but I cannot find it +// there. +// +// Google Test uses this class in the implementation of floating-point +// comparison. +// +// For now it only handles UInt (unsigned int) as that's all Google Test +// needs. Other types can be easily added in the future if need +// arises. +template +class TypeWithSize { + public: + // This prevents the user from using TypeWithSize with incorrect + // values of N. + typedef void UInt; +}; + +// The specialization for size 4. +template <> +class TypeWithSize<4> { + public: + // unsigned int has size 4 in both gcc and MSVC. + // + // As base/basictypes.h doesn't compile on Windows, we cannot use + // uint32, uint64, and etc here. + typedef int Int; + typedef unsigned int UInt; +}; + +// The specialization for size 8. +template <> +class TypeWithSize<8> { + public: +#if GTEST_OS_WINDOWS + typedef __int64 Int; + typedef unsigned __int64 UInt; +#else + typedef long long Int; // NOLINT + typedef unsigned long long UInt; // NOLINT +#endif // GTEST_OS_WINDOWS +}; + +// Integer types of known sizes. +typedef TypeWithSize<4>::Int Int32; +typedef TypeWithSize<4>::UInt UInt32; +typedef TypeWithSize<8>::Int Int64; +typedef TypeWithSize<8>::UInt UInt64; +typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. + +// Utilities for command line flags and environment variables. + +// Macro for referencing flags. +#define GTEST_FLAG(name) FLAGS_gtest_##name + +// Macros for declaring flags. +#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +#define GTEST_DECLARE_int32_(name) \ + GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) +#define GTEST_DECLARE_string_(name) \ + GTEST_API_ extern ::std::string GTEST_FLAG(name) + +// Macros for defining flags. +#define GTEST_DEFINE_bool_(name, default_val, doc) \ + GTEST_API_ bool GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_int32_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_string_(name, default_val, doc) \ + GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) + +// Thread annotations +#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) +#define GTEST_LOCK_EXCLUDED_(locks) + +// Parses 'str' for a 32-bit signed integer. If successful, writes the result +// to *value and returns true; otherwise leaves *value unchanged and returns +// false. +// TODO(chandlerc): Find a better way to refactor flag and environment parsing +// out of both gtest-port.cc and gtest.cc to avoid exporting this utility +// function. +bool ParseInt32(const Message& src_text, const char* str, Int32* value); + +// Parses a bool/Int32/string from the environment variable +// corresponding to the given Google Test flag. +bool BoolFromGTestEnv(const char* flag, bool default_val); +GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +const char* StringFromGTestEnv(const char* flag, const char* default_val); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +#if GTEST_OS_LINUX +# include +# include +# include +# include +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#include +#include +#include +#include +#include +#include + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the Message class. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ + +#include + + +// Ensures that there is at least one operator<< in the global namespace. +// See Message& operator<<(...) below for why. +void operator<<(const testing::internal::Secret&, int); + +namespace testing { + +// The Message class works like an ostream repeater. +// +// Typical usage: +// +// 1. You stream a bunch of values to a Message object. +// It will remember the text in a stringstream. +// 2. Then you stream the Message object to an ostream. +// This causes the text in the Message to be streamed +// to the ostream. +// +// For example; +// +// testing::Message foo; +// foo << 1 << " != " << 2; +// std::cout << foo; +// +// will print "1 != 2". +// +// Message is not intended to be inherited from. In particular, its +// destructor is not virtual. +// +// Note that stringstream behaves differently in gcc and in MSVC. You +// can stream a NULL char pointer to it in the former, but not in the +// latter (it causes an access violation if you do). The Message +// class hides this difference by treating a NULL char pointer as +// "(null)". +class GTEST_API_ Message { + private: + // The type of basic IO manipulators (endl, ends, and flush) for + // narrow streams. + typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); + + public: + // Constructs an empty Message. + Message(); + + // Copy constructor. + Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT + *ss_ << msg.GetString(); + } + + // Constructs a Message from a C-string. + explicit Message(const char* str) : ss_(new ::std::stringstream) { + *ss_ << str; + } + +#if GTEST_OS_SYMBIAN + // Streams a value (either a pointer or not) to this object. + template + inline Message& operator <<(const T& value) { + StreamHelper(typename internal::is_pointer::type(), value); + return *this; + } +#else + // Streams a non-pointer value to this object. + template + inline Message& operator <<(const T& val) { + // Some libraries overload << for STL containers. These + // overloads are defined in the global namespace instead of ::std. + // + // C++'s symbol lookup rule (i.e. Koenig lookup) says that these + // overloads are visible in either the std namespace or the global + // namespace, but not other namespaces, including the testing + // namespace which Google Test's Message class is in. + // + // To allow STL containers (and other types that has a << operator + // defined in the global namespace) to be used in Google Test + // assertions, testing::Message must access the custom << operator + // from the global namespace. With this using declaration, + // overloads of << defined in the global namespace and those + // visible via Koenig lookup are both exposed in this function. + using ::operator <<; + *ss_ << val; + return *this; + } + + // Streams a pointer value to this object. + // + // This function is an overload of the previous one. When you + // stream a pointer to a Message, this definition will be used as it + // is more specialized. (The C++ Standard, section + // [temp.func.order].) If you stream a non-pointer, then the + // previous definition will be used. + // + // The reason for this overload is that streaming a NULL pointer to + // ostream is undefined behavior. Depending on the compiler, you + // may get "0", "(nil)", "(null)", or an access violation. To + // ensure consistent result across compilers, we always treat NULL + // as "(null)". + template + inline Message& operator <<(T* const& pointer) { // NOLINT + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + *ss_ << pointer; + } + return *this; + } +#endif // GTEST_OS_SYMBIAN + + // Since the basic IO manipulators are overloaded for both narrow + // and wide streams, we have to provide this specialized definition + // of operator <<, even though its body is the same as the + // templatized version above. Without this definition, streaming + // endl or other basic IO manipulators to Message will confuse the + // compiler. + Message& operator <<(BasicNarrowIoManip val) { + *ss_ << val; + return *this; + } + + // Instead of 1/0, we want to see true/false for bool values. + Message& operator <<(bool b) { + return *this << (b ? "true" : "false"); + } + + // These two overloads allow streaming a wide C string to a Message + // using the UTF-8 encoding. + Message& operator <<(const wchar_t* wide_c_str); + Message& operator <<(wchar_t* wide_c_str); + +#if GTEST_HAS_STD_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::std::wstring& wstr); +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::wstring& wstr); +#endif // GTEST_HAS_GLOBAL_WSTRING + + // Gets the text streamed to this object so far as an std::string. + // Each '\0' character in the buffer is replaced with "\\0". + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + std::string GetString() const; + + private: + +#if GTEST_OS_SYMBIAN + // These are needed as the Nokia Symbian Compiler cannot decide between + // const T& and const T* in a function template. The Nokia compiler _can_ + // decide between class template specializations for T and T*, so a + // tr1::type_traits-like is_pointer works, and we can overload on that. + template + inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + *ss_ << pointer; + } + } + template + inline void StreamHelper(internal::false_type /*is_pointer*/, + const T& value) { + // See the comments in Message& operator <<(const T&) above for why + // we need this using statement. + using ::operator <<; + *ss_ << value; + } +#endif // GTEST_OS_SYMBIAN + + // We'll hold the text streamed to this object here. + const internal::scoped_ptr< ::std::stringstream> ss_; + + // We declare (but don't implement) this to prevent the compiler + // from implementing the assignment operator. + void operator=(const Message&); +}; + +// Streams a Message to an ostream. +inline std::ostream& operator <<(std::ostream& os, const Message& sb) { + return os << sb.GetString(); +} + +namespace internal { + +// Converts a streamable value to an std::string. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +template +std::string StreamableToString(const T& streamable) { + return (Message() << streamable).GetString(); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares the String class and functions used internally by +// Google Test. They are subject to change without notice. They should not used +// by code external to Google Test. +// +// This header file is #included by . +// It should not be #included by other files. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ + +#ifdef __BORLANDC__ +// string.h is not guaranteed to provide strcpy on C++ Builder. +# include +#endif + +#include +#include + + +namespace testing { +namespace internal { + +// String - an abstract class holding static string utilities. +class GTEST_API_ String { + public: + // Static utility methods + + // Clones a 0-terminated C string, allocating memory using new. The + // caller is responsible for deleting the return value using + // delete[]. Returns the cloned string, or NULL if the input is + // NULL. + // + // This is different from strdup() in string.h, which allocates + // memory using malloc(). + static const char* CloneCString(const char* c_str); + +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be + // able to pass strings to Win32 APIs on CE we need to convert them + // to 'Unicode', UTF-16. + + // Creates a UTF-16 wide string from the given ANSI string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the wide string, or NULL if the + // input is NULL. + // + // The wide string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static LPCWSTR AnsiToUtf16(const char* c_str); + + // Creates an ANSI string from the given wide string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the ANSI string, or NULL if the + // input is NULL. + // + // The returned string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static const char* Utf16ToAnsi(LPCWSTR utf16_str); +#endif + + // Compares two C strings. Returns true iff they have the same content. + // + // Unlike strcmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CStringEquals(const char* lhs, const char* rhs); + + // Converts a wide C string to a String using the UTF-8 encoding. + // NULL will be converted to "(null)". If an error occurred during + // the conversion, "(failed to convert from wide string)" is + // returned. + static std::string ShowWideCString(const wchar_t* wide_c_str); + + // Compares two wide C strings. Returns true iff they have the same + // content. + // + // Unlike wcscmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); + + // Compares two C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike strcasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CaseInsensitiveCStringEquals(const char* lhs, + const char* rhs); + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. + static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs); + + // Returns true iff the given string ends with the given suffix, ignoring + // case. Any string is considered to end with an empty suffix. + static bool EndsWithCaseInsensitive( + const std::string& str, const std::string& suffix); + + // Formats an int value as "%02d". + static std::string FormatIntWidth2(int value); // "%02d" for width == 2 + + // Formats an int value as "%X". + static std::string FormatHexInt(int value); + + // Formats a byte as "%02X". + static std::string FormatByte(unsigned char value); + + private: + String(); // Not meant to be instantiated. +}; // class String + +// Gets the content of the stringstream's buffer as an std::string. Each '\0' +// character in the buffer is replaced with "\\0". +GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: keith.ray@gmail.com (Keith Ray) +// +// Google Test filepath utilities +// +// This header file declares classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included in . +// Do not include this header file separately! + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ + + +namespace testing { +namespace internal { + +// FilePath - a class for file and directory pathname manipulation which +// handles platform-specific conventions (like the pathname separator). +// Used for helper functions for naming files in a directory for xml output. +// Except for Set methods, all methods are const or static, which provides an +// "immutable value object" -- useful for peace of mind. +// A FilePath with a value ending in a path separator ("like/this/") represents +// a directory, otherwise it is assumed to represent a file. In either case, +// it may or may not represent an actual file or directory in the file system. +// Names are NOT checked for syntax correctness -- no checking for illegal +// characters, malformed paths, etc. + +class GTEST_API_ FilePath { + public: + FilePath() : pathname_("") { } + FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } + + explicit FilePath(const std::string& pathname) : pathname_(pathname) { + Normalize(); + } + + FilePath& operator=(const FilePath& rhs) { + Set(rhs); + return *this; + } + + void Set(const FilePath& rhs) { + pathname_ = rhs.pathname_; + } + + const std::string& string() const { return pathname_; } + const char* c_str() const { return pathname_.c_str(); } + + // Returns the current working directory, or "" if unsuccessful. + static FilePath GetCurrentDir(); + + // Given directory = "dir", base_name = "test", number = 0, + // extension = "xml", returns "dir/test.xml". If number is greater + // than zero (e.g., 12), returns "dir/test_12.xml". + // On Windows platform, uses \ as the separator rather than /. + static FilePath MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension); + + // Given directory = "dir", relative_path = "test.xml", + // returns "dir/test.xml". + // On Windows, uses \ as the separator rather than /. + static FilePath ConcatPaths(const FilePath& directory, + const FilePath& relative_path); + + // Returns a pathname for a file that does not currently exist. The pathname + // will be directory/base_name.extension or + // directory/base_name_.extension if directory/base_name.extension + // already exists. The number will be incremented until a pathname is found + // that does not already exist. + // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. + // There could be a race condition if two or more processes are calling this + // function at the same time -- they could both pick the same filename. + static FilePath GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension); + + // Returns true iff the path is "". + bool IsEmpty() const { return pathname_.empty(); } + + // If input name has a trailing separator character, removes it and returns + // the name, otherwise return the name string unmodified. + // On Windows platform, uses \ as the separator, other platforms use /. + FilePath RemoveTrailingPathSeparator() const; + + // Returns a copy of the FilePath with the directory part removed. + // Example: FilePath("path/to/file").RemoveDirectoryName() returns + // FilePath("file"). If there is no directory part ("just_a_file"), it returns + // the FilePath unmodified. If there is no file part ("just_a_dir/") it + // returns an empty FilePath (""). + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveDirectoryName() const; + + // RemoveFileName returns the directory path with the filename removed. + // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". + // If the FilePath is "a_file" or "/a_file", RemoveFileName returns + // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does + // not have a file, like "just/a/dir/", it returns the FilePath unmodified. + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveFileName() const; + + // Returns a copy of the FilePath with the case-insensitive extension removed. + // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns + // FilePath("dir/file"). If a case-insensitive extension is not + // found, returns a copy of the original FilePath. + FilePath RemoveExtension(const char* extension) const; + + // Creates directories so that path exists. Returns true if successful or if + // the directories already exist; returns false if unable to create + // directories for any reason. Will also return false if the FilePath does + // not represent a directory (that is, it doesn't end with a path separator). + bool CreateDirectoriesRecursively() const; + + // Create the directory so that path exists. Returns true if successful or + // if the directory already exists; returns false if unable to create the + // directory for any reason, including if the parent directory does not + // exist. Not named "CreateDirectory" because that's a macro on Windows. + bool CreateFolder() const; + + // Returns true if FilePath describes something in the file-system, + // either a file, directory, or whatever, and that something exists. + bool FileOrDirectoryExists() const; + + // Returns true if pathname describes a directory in the file-system + // that exists. + bool DirectoryExists() const; + + // Returns true if FilePath ends with a path separator, which indicates that + // it is intended to represent a directory. Returns false otherwise. + // This does NOT check that a directory (or file) actually exists. + bool IsDirectory() const; + + // Returns true if pathname describes a root directory. (Windows has one + // root directory per disk drive.) + bool IsRootDirectory() const; + + // Returns true if pathname describes an absolute path. + bool IsAbsolutePath() const; + + private: + // Replaces multiple consecutive separators with a single separator. + // For example, "bar///foo" becomes "bar/foo". Does not eliminate other + // redundancies that might be in a pathname involving "." or "..". + // + // A pathname with multiple consecutive separators may occur either through + // user error or as a result of some scripts or APIs that generate a pathname + // with a trailing separator. On other platforms the same API or script + // may NOT generate a pathname with a trailing "/". Then elsewhere that + // pathname may have another "/" and pathname components added to it, + // without checking for the separator already being there. + // The script language and operating system may allow paths like "foo//bar" + // but some of the functions in FilePath will not handle that correctly. In + // particular, RemoveTrailingPathSeparator() only removes one separator, and + // it is called in CreateDirectoriesRecursively() assuming that it will change + // a pathname from directory syntax (trailing separator) to filename syntax. + // + // On Windows this method also replaces the alternate path separator '/' with + // the primary path separator '\\', so that for example "bar\\/\\foo" becomes + // "bar\\foo". + + void Normalize(); + + // Returns a pointer to the last occurence of a valid path separator in + // the FilePath. On Windows, for example, both '/' and '\' are valid path + // separators. Returns NULL if no path separator was found. + const char* FindLastPathSeparator() const; + + std::string pathname_; +}; // class FilePath + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +// This file was GENERATED by command: +// pump.py gtest-type-util.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most 50 types in a list, and at most 50 +// type-parameterized tests in one type-parameterized test case. +// Please contact googletestframework@googlegroups.com if you need +// more. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +# if GTEST_HAS_CXXABI_H_ +# include +# elif defined(__HP_aCC) +# include +# endif // GTEST_HASH_CXXABI_H_ + +namespace testing { +namespace internal { + +// GetTypeName() returns a human-readable name of type T. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +std::string GetTypeName() { +# if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. +# if GTEST_HAS_CXXABI_H_ + using abi::__cxa_demangle; +# endif // GTEST_HAS_CXXABI_H_ + char* const readable_name = __cxa_demangle(name, 0, 0, &status); + const std::string name_str(status == 0 ? readable_name : name); + free(readable_name); + return name_str; +# else + return name; +# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC + +# else + + return ""; + +# endif // GTEST_HAS_RTTI +} + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// AssertyTypeEq::type is defined iff T1 and T2 are the same +// type. This can be used as a compile-time assertion to ensure that +// two types are equal. + +template +struct AssertTypeEq; + +template +struct AssertTypeEq { + typedef bool type; +}; + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; +template +struct Types2 { + typedef T1 Head; + typedef Types1 Tail; +}; + +template +struct Types3 { + typedef T1 Head; + typedef Types2 Tail; +}; + +template +struct Types4 { + typedef T1 Head; + typedef Types3 Tail; +}; + +template +struct Types5 { + typedef T1 Head; + typedef Types4 Tail; +}; + +template +struct Types6 { + typedef T1 Head; + typedef Types5 Tail; +}; + +template +struct Types7 { + typedef T1 Head; + typedef Types6 Tail; +}; + +template +struct Types8 { + typedef T1 Head; + typedef Types7 Tail; +}; + +template +struct Types9 { + typedef T1 Head; + typedef Types8 Tail; +}; + +template +struct Types10 { + typedef T1 Head; + typedef Types9 Tail; +}; + +template +struct Types11 { + typedef T1 Head; + typedef Types10 Tail; +}; + +template +struct Types12 { + typedef T1 Head; + typedef Types11 Tail; +}; + +template +struct Types13 { + typedef T1 Head; + typedef Types12 Tail; +}; + +template +struct Types14 { + typedef T1 Head; + typedef Types13 Tail; +}; + +template +struct Types15 { + typedef T1 Head; + typedef Types14 Tail; +}; + +template +struct Types16 { + typedef T1 Head; + typedef Types15 Tail; +}; + +template +struct Types17 { + typedef T1 Head; + typedef Types16 Tail; +}; + +template +struct Types18 { + typedef T1 Head; + typedef Types17 Tail; +}; + +template +struct Types19 { + typedef T1 Head; + typedef Types18 Tail; +}; + +template +struct Types20 { + typedef T1 Head; + typedef Types19 Tail; +}; + +template +struct Types21 { + typedef T1 Head; + typedef Types20 Tail; +}; + +template +struct Types22 { + typedef T1 Head; + typedef Types21 Tail; +}; + +template +struct Types23 { + typedef T1 Head; + typedef Types22 Tail; +}; + +template +struct Types24 { + typedef T1 Head; + typedef Types23 Tail; +}; + +template +struct Types25 { + typedef T1 Head; + typedef Types24 Tail; +}; + +template +struct Types26 { + typedef T1 Head; + typedef Types25 Tail; +}; + +template +struct Types27 { + typedef T1 Head; + typedef Types26 Tail; +}; + +template +struct Types28 { + typedef T1 Head; + typedef Types27 Tail; +}; + +template +struct Types29 { + typedef T1 Head; + typedef Types28 Tail; +}; + +template +struct Types30 { + typedef T1 Head; + typedef Types29 Tail; +}; + +template +struct Types31 { + typedef T1 Head; + typedef Types30 Tail; +}; + +template +struct Types32 { + typedef T1 Head; + typedef Types31 Tail; +}; + +template +struct Types33 { + typedef T1 Head; + typedef Types32 Tail; +}; + +template +struct Types34 { + typedef T1 Head; + typedef Types33 Tail; +}; + +template +struct Types35 { + typedef T1 Head; + typedef Types34 Tail; +}; + +template +struct Types36 { + typedef T1 Head; + typedef Types35 Tail; +}; + +template +struct Types37 { + typedef T1 Head; + typedef Types36 Tail; +}; + +template +struct Types38 { + typedef T1 Head; + typedef Types37 Tail; +}; + +template +struct Types39 { + typedef T1 Head; + typedef Types38 Tail; +}; + +template +struct Types40 { + typedef T1 Head; + typedef Types39 Tail; +}; + +template +struct Types41 { + typedef T1 Head; + typedef Types40 Tail; +}; + +template +struct Types42 { + typedef T1 Head; + typedef Types41 Tail; +}; + +template +struct Types43 { + typedef T1 Head; + typedef Types42 Tail; +}; + +template +struct Types44 { + typedef T1 Head; + typedef Types43 Tail; +}; + +template +struct Types45 { + typedef T1 Head; + typedef Types44 Tail; +}; + +template +struct Types46 { + typedef T1 Head; + typedef Types45 Tail; +}; + +template +struct Types47 { + typedef T1 Head; + typedef Types46 Tail; +}; + +template +struct Types48 { + typedef T1 Head; + typedef Types47 Tail; +}; + +template +struct Types49 { + typedef T1 Head; + typedef Types48 Tail; +}; + +template +struct Types50 { + typedef T1 Head; + typedef Types49 Tail; +}; + + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. +template +struct Types { + typedef internal::Types50 type; +}; + +template <> +struct Types { + typedef internal::Types0 type; +}; +template +struct Types { + typedef internal::Types1 type; +}; +template +struct Types { + typedef internal::Types2 type; +}; +template +struct Types { + typedef internal::Types3 type; +}; +template +struct Types { + typedef internal::Types4 type; +}; +template +struct Types { + typedef internal::Types5 type; +}; +template +struct Types { + typedef internal::Types6 type; +}; +template +struct Types { + typedef internal::Types7 type; +}; +template +struct Types { + typedef internal::Types8 type; +}; +template +struct Types { + typedef internal::Types9 type; +}; +template +struct Types { + typedef internal::Types10 type; +}; +template +struct Types { + typedef internal::Types11 type; +}; +template +struct Types { + typedef internal::Types12 type; +}; +template +struct Types { + typedef internal::Types13 type; +}; +template +struct Types { + typedef internal::Types14 type; +}; +template +struct Types { + typedef internal::Types15 type; +}; +template +struct Types { + typedef internal::Types16 type; +}; +template +struct Types { + typedef internal::Types17 type; +}; +template +struct Types { + typedef internal::Types18 type; +}; +template +struct Types { + typedef internal::Types19 type; +}; +template +struct Types { + typedef internal::Types20 type; +}; +template +struct Types { + typedef internal::Types21 type; +}; +template +struct Types { + typedef internal::Types22 type; +}; +template +struct Types { + typedef internal::Types23 type; +}; +template +struct Types { + typedef internal::Types24 type; +}; +template +struct Types { + typedef internal::Types25 type; +}; +template +struct Types { + typedef internal::Types26 type; +}; +template +struct Types { + typedef internal::Types27 type; +}; +template +struct Types { + typedef internal::Types28 type; +}; +template +struct Types { + typedef internal::Types29 type; +}; +template +struct Types { + typedef internal::Types30 type; +}; +template +struct Types { + typedef internal::Types31 type; +}; +template +struct Types { + typedef internal::Types32 type; +}; +template +struct Types { + typedef internal::Types33 type; +}; +template +struct Types { + typedef internal::Types34 type; +}; +template +struct Types { + typedef internal::Types35 type; +}; +template +struct Types { + typedef internal::Types36 type; +}; +template +struct Types { + typedef internal::Types37 type; +}; +template +struct Types { + typedef internal::Types38 type; +}; +template +struct Types { + typedef internal::Types39 type; +}; +template +struct Types { + typedef internal::Types40 type; +}; +template +struct Types { + typedef internal::Types41 type; +}; +template +struct Types { + typedef internal::Types42 type; +}; +template +struct Types { + typedef internal::Types43 type; +}; +template +struct Types { + typedef internal::Types44 type; +}; +template +struct Types { + typedef internal::Types45 type; +}; +template +struct Types { + typedef internal::Types46 type; +}; +template +struct Types { + typedef internal::Types47 type; +}; +template +struct Types { + typedef internal::Types48 type; +}; +template +struct Types { + typedef internal::Types49 type; +}; + +namespace internal { + +# define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +# define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; +template +struct Templates2 { + typedef TemplateSel Head; + typedef Templates1 Tail; +}; + +template +struct Templates3 { + typedef TemplateSel Head; + typedef Templates2 Tail; +}; + +template +struct Templates4 { + typedef TemplateSel Head; + typedef Templates3 Tail; +}; + +template +struct Templates5 { + typedef TemplateSel Head; + typedef Templates4 Tail; +}; + +template +struct Templates6 { + typedef TemplateSel Head; + typedef Templates5 Tail; +}; + +template +struct Templates7 { + typedef TemplateSel Head; + typedef Templates6 Tail; +}; + +template +struct Templates8 { + typedef TemplateSel Head; + typedef Templates7 Tail; +}; + +template +struct Templates9 { + typedef TemplateSel Head; + typedef Templates8 Tail; +}; + +template +struct Templates10 { + typedef TemplateSel Head; + typedef Templates9 Tail; +}; + +template +struct Templates11 { + typedef TemplateSel Head; + typedef Templates10 Tail; +}; + +template +struct Templates12 { + typedef TemplateSel Head; + typedef Templates11 Tail; +}; + +template +struct Templates13 { + typedef TemplateSel Head; + typedef Templates12 Tail; +}; + +template +struct Templates14 { + typedef TemplateSel Head; + typedef Templates13 Tail; +}; + +template +struct Templates15 { + typedef TemplateSel Head; + typedef Templates14 Tail; +}; + +template +struct Templates16 { + typedef TemplateSel Head; + typedef Templates15 Tail; +}; + +template +struct Templates17 { + typedef TemplateSel Head; + typedef Templates16 Tail; +}; + +template +struct Templates18 { + typedef TemplateSel Head; + typedef Templates17 Tail; +}; + +template +struct Templates19 { + typedef TemplateSel Head; + typedef Templates18 Tail; +}; + +template +struct Templates20 { + typedef TemplateSel Head; + typedef Templates19 Tail; +}; + +template +struct Templates21 { + typedef TemplateSel Head; + typedef Templates20 Tail; +}; + +template +struct Templates22 { + typedef TemplateSel Head; + typedef Templates21 Tail; +}; + +template +struct Templates23 { + typedef TemplateSel Head; + typedef Templates22 Tail; +}; + +template +struct Templates24 { + typedef TemplateSel Head; + typedef Templates23 Tail; +}; + +template +struct Templates25 { + typedef TemplateSel Head; + typedef Templates24 Tail; +}; + +template +struct Templates26 { + typedef TemplateSel Head; + typedef Templates25 Tail; +}; + +template +struct Templates27 { + typedef TemplateSel Head; + typedef Templates26 Tail; +}; + +template +struct Templates28 { + typedef TemplateSel Head; + typedef Templates27 Tail; +}; + +template +struct Templates29 { + typedef TemplateSel Head; + typedef Templates28 Tail; +}; + +template +struct Templates30 { + typedef TemplateSel Head; + typedef Templates29 Tail; +}; + +template +struct Templates31 { + typedef TemplateSel Head; + typedef Templates30 Tail; +}; + +template +struct Templates32 { + typedef TemplateSel Head; + typedef Templates31 Tail; +}; + +template +struct Templates33 { + typedef TemplateSel Head; + typedef Templates32 Tail; +}; + +template +struct Templates34 { + typedef TemplateSel Head; + typedef Templates33 Tail; +}; + +template +struct Templates35 { + typedef TemplateSel Head; + typedef Templates34 Tail; +}; + +template +struct Templates36 { + typedef TemplateSel Head; + typedef Templates35 Tail; +}; + +template +struct Templates37 { + typedef TemplateSel Head; + typedef Templates36 Tail; +}; + +template +struct Templates38 { + typedef TemplateSel Head; + typedef Templates37 Tail; +}; + +template +struct Templates39 { + typedef TemplateSel Head; + typedef Templates38 Tail; +}; + +template +struct Templates40 { + typedef TemplateSel Head; + typedef Templates39 Tail; +}; + +template +struct Templates41 { + typedef TemplateSel Head; + typedef Templates40 Tail; +}; + +template +struct Templates42 { + typedef TemplateSel Head; + typedef Templates41 Tail; +}; + +template +struct Templates43 { + typedef TemplateSel Head; + typedef Templates42 Tail; +}; + +template +struct Templates44 { + typedef TemplateSel Head; + typedef Templates43 Tail; +}; + +template +struct Templates45 { + typedef TemplateSel Head; + typedef Templates44 Tail; +}; + +template +struct Templates46 { + typedef TemplateSel Head; + typedef Templates45 Tail; +}; + +template +struct Templates47 { + typedef TemplateSel Head; + typedef Templates46 Tail; +}; + +template +struct Templates48 { + typedef TemplateSel Head; + typedef Templates47 Tail; +}; + +template +struct Templates49 { + typedef TemplateSel Head; + typedef Templates48 Tail; +}; + +template +struct Templates50 { + typedef TemplateSel Head; + typedef Templates49 Tail; +}; + + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. +template +struct Templates { + typedef Templates50 type; +}; + +template <> +struct Templates { + typedef Templates0 type; +}; +template +struct Templates { + typedef Templates1 type; +}; +template +struct Templates { + typedef Templates2 type; +}; +template +struct Templates { + typedef Templates3 type; +}; +template +struct Templates { + typedef Templates4 type; +}; +template +struct Templates { + typedef Templates5 type; +}; +template +struct Templates { + typedef Templates6 type; +}; +template +struct Templates { + typedef Templates7 type; +}; +template +struct Templates { + typedef Templates8 type; +}; +template +struct Templates { + typedef Templates9 type; +}; +template +struct Templates { + typedef Templates10 type; +}; +template +struct Templates { + typedef Templates11 type; +}; +template +struct Templates { + typedef Templates12 type; +}; +template +struct Templates { + typedef Templates13 type; +}; +template +struct Templates { + typedef Templates14 type; +}; +template +struct Templates { + typedef Templates15 type; +}; +template +struct Templates { + typedef Templates16 type; +}; +template +struct Templates { + typedef Templates17 type; +}; +template +struct Templates { + typedef Templates18 type; +}; +template +struct Templates { + typedef Templates19 type; +}; +template +struct Templates { + typedef Templates20 type; +}; +template +struct Templates { + typedef Templates21 type; +}; +template +struct Templates { + typedef Templates22 type; +}; +template +struct Templates { + typedef Templates23 type; +}; +template +struct Templates { + typedef Templates24 type; +}; +template +struct Templates { + typedef Templates25 type; +}; +template +struct Templates { + typedef Templates26 type; +}; +template +struct Templates { + typedef Templates27 type; +}; +template +struct Templates { + typedef Templates28 type; +}; +template +struct Templates { + typedef Templates29 type; +}; +template +struct Templates { + typedef Templates30 type; +}; +template +struct Templates { + typedef Templates31 type; +}; +template +struct Templates { + typedef Templates32 type; +}; +template +struct Templates { + typedef Templates33 type; +}; +template +struct Templates { + typedef Templates34 type; +}; +template +struct Templates { + typedef Templates35 type; +}; +template +struct Templates { + typedef Templates36 type; +}; +template +struct Templates { + typedef Templates37 type; +}; +template +struct Templates { + typedef Templates38 type; +}; +template +struct Templates { + typedef Templates39 type; +}; +template +struct Templates { + typedef Templates40 type; +}; +template +struct Templates { + typedef Templates41 type; +}; +template +struct Templates { + typedef Templates42 type; +}; +template +struct Templates { + typedef Templates43 type; +}; +template +struct Templates { + typedef Templates44 type; +}; +template +struct Templates { + typedef Templates45 type; +}; +template +struct Templates { + typedef Templates46 type; +}; +template +struct Templates { + typedef Templates47 type; +}; +template +struct Templates { + typedef Templates48 type; +}; +template +struct Templates { + typedef Templates49 type; +}; + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_CASE() and +// INSTANTIATE_TYPED_TEST_CASE_P(). + +template +struct TypeList { + typedef Types1 type; +}; + +template +struct TypeList > { + typedef typename Types::type type; +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +// Due to C++ preprocessor weirdness, we need double indirection to +// concatenate two tokens when one of them is __LINE__. Writing +// +// foo ## __LINE__ +// +// will result in the token foo__LINE__, instead of foo followed by +// the current line number. For more details, see +// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 +#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) +#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar + +class ProtocolMessage; +namespace proto2 { class Message; } + +namespace testing { + +// Forward declarations. + +class AssertionResult; // Result of an assertion. +class Message; // Represents a failure message. +class Test; // Represents a test. +class TestInfo; // Information about a test. +class TestPartResult; // Result of a test part. +class UnitTest; // A collection of test cases. + +template +::std::string PrintToString(const T& value); + +namespace internal { + +struct TraceInfo; // Information about a trace point. +class ScopedTrace; // Implements scoped trace. +class TestInfoImpl; // Opaque implementation of TestInfo +class UnitTestImpl; // Opaque implementation of UnitTest + +// How many times InitGoogleTest() has been called. +GTEST_API_ extern int g_init_gtest_count; + +// The text used in failure messages to indicate the start of the +// stack trace. +GTEST_API_ extern const char kStackTraceMarker[]; + +// Two overloaded helpers for checking at compile time whether an +// expression is a null pointer literal (i.e. NULL or any 0-valued +// compile-time integral constant). Their return values have +// different sizes, so we can use sizeof() to test which version is +// picked by the compiler. These helpers have no implementations, as +// we only need their signatures. +// +// Given IsNullLiteralHelper(x), the compiler will pick the first +// version if x can be implicitly converted to Secret*, and pick the +// second version otherwise. Since Secret is a secret and incomplete +// type, the only expression a user can write that has type Secret* is +// a null pointer literal. Therefore, we know that x is a null +// pointer literal if and only if the first version is picked by the +// compiler. +char IsNullLiteralHelper(Secret* p); +char (&IsNullLiteralHelper(...))[2]; // NOLINT + +// A compile-time bool constant that is true if and only if x is a +// null pointer literal (i.e. NULL or any 0-valued compile-time +// integral constant). +#ifdef GTEST_ELLIPSIS_NEEDS_POD_ +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +# define GTEST_IS_NULL_LITERAL_(x) false +#else +# define GTEST_IS_NULL_LITERAL_(x) \ + (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) +#endif // GTEST_ELLIPSIS_NEEDS_POD_ + +// Appends the user-supplied message to the Google-Test-generated message. +GTEST_API_ std::string AppendUserMessage( + const std::string& gtest_msg, const Message& user_msg); + +#if GTEST_HAS_EXCEPTIONS + +// This exception is thrown by (and only by) a failed Google Test +// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions +// are enabled). We derive it from std::runtime_error, which is for +// errors presumably detectable only at run time. Since +// std::runtime_error inherits from std::exception, many testing +// frameworks know how to extract and print the message inside it. +class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure); +}; + +#endif // GTEST_HAS_EXCEPTIONS + +// A helper class for creating scoped traces in user programs. +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + ScopedTrace(const char* file, int line, const Message& message); + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +GTEST_API_ AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const std::string& expected_value, + const std::string& actual_value, + bool ignoring_case); + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +GTEST_API_ std::string GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value); + +// This template class represents an IEEE floating-point number +// (either single-precision or double-precision, depending on the +// template parameters). +// +// The purpose of this class is to do more sophisticated number +// comparison. (Due to round-off error, etc, it's very unlikely that +// two floating-points will be equal exactly. Hence a naive +// comparison by the == operation often doesn't work.) +// +// Format of IEEE floating-point: +// +// The most-significant bit being the leftmost, an IEEE +// floating-point looks like +// +// sign_bit exponent_bits fraction_bits +// +// Here, sign_bit is a single bit that designates the sign of the +// number. +// +// For float, there are 8 exponent bits and 23 fraction bits. +// +// For double, there are 11 exponent bits and 52 fraction bits. +// +// More details can be found at +// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +template +class FloatingPoint { + public: + // Defines the unsigned integer type that has the same size as the + // floating point number. + typedef typename TypeWithSize::UInt Bits; + + // Constants. + + // # of bits in a number. + static const size_t kBitCount = 8*sizeof(RawType); + + // # of fraction bits in a number. + static const size_t kFractionBitCount = + std::numeric_limits::digits - 1; + + // # of exponent bits in a number. + static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; + + // The mask for the sign bit. + static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); + + // The mask for the fraction bits. + static const Bits kFractionBitMask = + ~static_cast(0) >> (kExponentBitCount + 1); + + // The mask for the exponent bits. + static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); + + // How many ULP's (Units in the Last Place) we want to tolerate when + // comparing two numbers. The larger the value, the more error we + // allow. A 0 value means that two numbers must be exactly the same + // to be considered equal. + // + // The maximum error of a single floating-point operation is 0.5 + // units in the last place. On Intel CPU's, all floating-point + // calculations are done with 80-bit precision, while double has 64 + // bits. Therefore, 4 should be enough for ordinary use. + // + // See the following article for more details on ULP: + // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + static const size_t kMaxUlps = 4; + + // Constructs a FloatingPoint from a raw floating-point number. + // + // On an Intel CPU, passing a non-normalized NAN (Not a Number) + // around may change its bits, although the new value is guaranteed + // to be also a NAN. Therefore, don't expect this constructor to + // preserve the bits in x when x is a NAN. + explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + + // Static methods + + // Reinterprets a bit pattern as a floating-point number. + // + // This function is needed to test the AlmostEquals() method. + static RawType ReinterpretBits(const Bits bits) { + FloatingPoint fp(0); + fp.u_.bits_ = bits; + return fp.u_.value_; + } + + // Returns the floating-point number that represent positive infinity. + static RawType Infinity() { + return ReinterpretBits(kExponentBitMask); + } + + // Returns the maximum representable finite floating-point number. + static RawType Max(); + + // Non-static methods + + // Returns the bits that represents this number. + const Bits &bits() const { return u_.bits_; } + + // Returns the exponent bits of this number. + Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + + // Returns the fraction bits of this number. + Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + + // Returns the sign bit of this number. + Bits sign_bit() const { return kSignBitMask & u_.bits_; } + + // Returns true iff this is NAN (not a number). + bool is_nan() const { + // It's a NAN if the exponent bits are all ones and the fraction + // bits are not entirely zeros. + return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); + } + + // Returns true iff this number is at most kMaxUlps ULP's away from + // rhs. In particular, this function: + // + // - returns false if either number is (or both are) NAN. + // - treats really large numbers as almost equal to infinity. + // - thinks +0.0 and -0.0 are 0 DLP's apart. + bool AlmostEquals(const FloatingPoint& rhs) const { + // The IEEE standard says that any comparison operation involving + // a NAN must return false. + if (is_nan() || rhs.is_nan()) return false; + + return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) + <= kMaxUlps; + } + + private: + // The data type used to store the actual floating-point number. + union FloatingPointUnion { + RawType value_; // The raw floating-point number. + Bits bits_; // The bits that represent the number. + }; + + // Converts an integer from the sign-and-magnitude representation to + // the biased representation. More precisely, let N be 2 to the + // power of (kBitCount - 1), an integer x is represented by the + // unsigned number x + N. + // + // For instance, + // + // -N + 1 (the most negative number representable using + // sign-and-magnitude) is represented by 1; + // 0 is represented by N; and + // N - 1 (the biggest number representable using + // sign-and-magnitude) is represented by 2N - 1. + // + // Read http://en.wikipedia.org/wiki/Signed_number_representations + // for more details on signed number representations. + static Bits SignAndMagnitudeToBiased(const Bits &sam) { + if (kSignBitMask & sam) { + // sam represents a negative number. + return ~sam + 1; + } else { + // sam represents a positive number. + return kSignBitMask | sam; + } + } + + // Given two numbers in the sign-and-magnitude representation, + // returns the distance between them as an unsigned number. + static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, + const Bits &sam2) { + const Bits biased1 = SignAndMagnitudeToBiased(sam1); + const Bits biased2 = SignAndMagnitudeToBiased(sam2); + return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); + } + + FloatingPointUnion u_; +}; + +// We cannot use std::numeric_limits::max() as it clashes with the max() +// macro defined by . +template <> +inline float FloatingPoint::Max() { return FLT_MAX; } +template <> +inline double FloatingPoint::Max() { return DBL_MAX; } + +// Typedefs the instances of the FloatingPoint template class that we +// care to use. +typedef FloatingPoint Float; +typedef FloatingPoint Double; + +// In order to catch the mistake of putting tests that use different +// test fixture classes in the same test case, we need to assign +// unique IDs to fixture classes and compare them. The TypeId type is +// used to hold such IDs. The user should treat TypeId as an opaque +// type: the only operation allowed on TypeId values is to compare +// them for equality using the == operator. +typedef const void* TypeId; + +template +class TypeIdHelper { + public: + // dummy_ must not have a const type. Otherwise an overly eager + // compiler (e.g. MSVC 7.1 & 8.0) may try to merge + // TypeIdHelper::dummy_ for different Ts as an "optimization". + static bool dummy_; +}; + +template +bool TypeIdHelper::dummy_ = false; + +// GetTypeId() returns the ID of type T. Different values will be +// returned for different types. Calling the function twice with the +// same type argument is guaranteed to return the same ID. +template +TypeId GetTypeId() { + // The compiler is required to allocate a different + // TypeIdHelper::dummy_ variable for each T used to instantiate + // the template. Therefore, the address of dummy_ is guaranteed to + // be unique. + return &(TypeIdHelper::dummy_); +} + +// Returns the type ID of ::testing::Test. Always call this instead +// of GetTypeId< ::testing::Test>() to get the type ID of +// ::testing::Test, as the latter may give the wrong result due to a +// suspected linker bug when compiling Google Test as a Mac OS X +// framework. +GTEST_API_ TypeId GetTestTypeId(); + +// Defines the abstract factory interface that creates instances +// of a Test object. +class TestFactoryBase { + public: + virtual ~TestFactoryBase() {} + + // Creates a test instance to run. The instance is both created and destroyed + // within TestInfoImpl::Run() + virtual Test* CreateTest() = 0; + + protected: + TestFactoryBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); +}; + +// This class provides implementation of TeastFactoryBase interface. +// It is used in TEST and TEST_F macros. +template +class TestFactoryImpl : public TestFactoryBase { + public: + virtual Test* CreateTest() { return new TestClass; } +}; + +#if GTEST_OS_WINDOWS + +// Predicate-formatters for implementing the HRESULT checking macros +// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} +// We pass a long instead of HRESULT to avoid causing an +// include dependency for the HRESULT type. +GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, + long hr); // NOLINT +GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, + long hr); // NOLINT + +#endif // GTEST_OS_WINDOWS + +// Types of SetUpTestCase() and TearDownTestCase() functions. +typedef void (*SetUpTestCaseFunc)(); +typedef void (*TearDownTestCaseFunc)(); + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param text representation of the test's value parameter, +// or NULL if this is not a type-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +GTEST_API_ TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, + const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory); + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// State of the definition of a type-parameterized test case. +class GTEST_API_ TypedTestCasePState { + public: + TypedTestCasePState() : registered_(false) {} + + // Adds the given test name to defined_test_names_ and return true + // if the test case hasn't been registered; otherwise aborts the + // program. + bool AddTestName(const char* file, int line, const char* case_name, + const char* test_name) { + if (registered_) { + fprintf(stderr, "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + FormatFileLocation(file, line).c_str(), test_name, case_name); + fflush(stderr); + posix::Abort(); + } + defined_test_names_.insert(test_name); + return true; + } + + // Verifies that registered_tests match the test names in + // defined_test_names_; returns registered_tests if successful, or + // aborts the program otherwise. + const char* VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests); + + private: + bool registered_; + ::std::set defined_test_names_; +}; + +// Skips to the first non-space char after the first comma in 'str'; +// returns NULL if no comma is found in 'str'. +inline const char* SkipComma(const char* str) { + const char* comma = strchr(str, ','); + if (comma == NULL) { + return NULL; + } + while (IsSpace(*(++comma))) {} + return comma; +} + +// Returns the prefix of 'str' before the first comma in it; returns +// the entire string if it contains no comma. +inline std::string GetPrefixUntilComma(const char* str) { + const char* comma = strchr(str, ','); + return comma == NULL ? str : std::string(str, comma); +} + +// TypeParameterizedTest::Register() +// registers a list of type-parameterized tests with Google Test. The +// return value is insignificant - we just need to return something +// such that we can call this function in a namespace scope. +// +// Implementation note: The GTEST_TEMPLATE_ macro declares a template +// template parameter. It's defined in gtest-type-util.h. +template +class TypeParameterizedTest { + public: + // 'index' is the index of the test in the type list 'Types' + // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // Types). Valid values for 'index' are [0, N - 1] where N is the + // length of Types. + static bool Register(const char* prefix, const char* case_name, + const char* test_names, int index) { + typedef typename Types::Head Type; + typedef Fixture FixtureClass; + typedef typename GTEST_BIND_(TestSel, Type) TestClass; + + // First, registers the first type-parameterized test in the type + // list. + MakeAndRegisterTestInfo( + (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" + + StreamableToString(index)).c_str(), + GetPrefixUntilComma(test_names).c_str(), + GetTypeName().c_str(), + NULL, // No value parameter. + GetTypeId(), + TestClass::SetUpTestCase, + TestClass::TearDownTestCase, + new TestFactoryImpl); + + // Next, recurses (at compile time) with the tail of the type list. + return TypeParameterizedTest + ::Register(prefix, case_name, test_names, index + 1); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTest { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/, int /*index*/) { + return true; + } +}; + +// TypeParameterizedTestCase::Register() +// registers *all combinations* of 'Tests' and 'Types' with Google +// Test. The return value is insignificant - we just need to return +// something such that we can call this function in a namespace scope. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* prefix, const char* case_name, + const char* test_names) { + typedef typename Tests::Head Head; + + // First, register the first test in 'Test' for each type in 'Types'. + TypeParameterizedTest::Register( + prefix, case_name, test_names, 0); + + // Next, recurses (at compile time) with the tail of the test list. + return TypeParameterizedTestCase + ::Register(prefix, case_name, SkipComma(test_names)); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/) { + return true; + } +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// Returns the current OS stack trace as an std::string. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( + UnitTest* unit_test, int skip_count); + +// Helpers for suppressing warnings on unreachable code or constant +// condition. + +// Always returns true. +GTEST_API_ bool AlwaysTrue(); + +// Always returns false. +inline bool AlwaysFalse() { return !AlwaysTrue(); } + +// Helper for suppressing false warning from Clang on a const char* +// variable declared in a conditional expression always being NULL in +// the else branch. +struct GTEST_API_ ConstCharPtr { + ConstCharPtr(const char* str) : value(str) {} + operator bool() const { return true; } + const char* value; +}; + +// A simple Linear Congruential Generator for generating random +// numbers with a uniform distribution. Unlike rand() and srand(), it +// doesn't use global state (and therefore can't interfere with user +// code). Unlike rand_r(), it's portable. An LCG isn't very random, +// but it's good enough for our purposes. +class GTEST_API_ Random { + public: + static const UInt32 kMaxRange = 1u << 31; + + explicit Random(UInt32 seed) : state_(seed) {} + + void Reseed(UInt32 seed) { state_ = seed; } + + // Generates a random number from [0, range). Crashes if 'range' is + // 0 or greater than kMaxRange. + UInt32 Generate(UInt32 range); + + private: + UInt32 state_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); +}; + +// Defining a variable of type CompileAssertTypesEqual will cause a +// compiler error iff T1 and T2 are different types. +template +struct CompileAssertTypesEqual; + +template +struct CompileAssertTypesEqual { +}; + +// Removes the reference from a type if it is a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::remove_reference, which is not widely available yet. +template +struct RemoveReference { typedef T type; }; // NOLINT +template +struct RemoveReference { typedef T type; }; // NOLINT + +// A handy wrapper around RemoveReference that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_REFERENCE_(T) \ + typename ::testing::internal::RemoveReference::type + +// Removes const from a type if it is a const type, otherwise leaves +// it unchanged. This is the same as tr1::remove_const, which is not +// widely available yet. +template +struct RemoveConst { typedef T type; }; // NOLINT +template +struct RemoveConst { typedef T type; }; // NOLINT + +// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above +// definition to fail to remove the const in 'const int[3]' and 'const +// char[3][4]'. The following specialization works around the bug. +template +struct RemoveConst { + typedef typename RemoveConst::type type[N]; +}; + +#if defined(_MSC_VER) && _MSC_VER < 1400 +// This is the only specialization that allows VC++ 7.1 to remove const in +// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC +// and thus needs to be conditionally compiled. +template +struct RemoveConst { + typedef typename RemoveConst::type type[N]; +}; +#endif + +// A handy wrapper around RemoveConst that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_CONST_(T) \ + typename ::testing::internal::RemoveConst::type + +// Turns const U&, U&, const U, and U all into U. +#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ + GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) + +// Adds reference to a type if it is not a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::add_reference, which is not widely available yet. +template +struct AddReference { typedef T& type; }; // NOLINT +template +struct AddReference { typedef T& type; }; // NOLINT + +// A handy wrapper around AddReference that works when the argument T +// depends on template parameters. +#define GTEST_ADD_REFERENCE_(T) \ + typename ::testing::internal::AddReference::type + +// Adds a reference to const on top of T as necessary. For example, +// it transforms +// +// char ==> const char& +// const char ==> const char& +// char& ==> const char& +// const char& ==> const char& +// +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) + +// ImplicitlyConvertible::value is a compile-time bool +// constant that's true iff type From can be implicitly converted to +// type To. +template +class ImplicitlyConvertible { + private: + // We need the following helper functions only for their types. + // They have no implementations. + + // MakeFrom() is an expression whose type is From. We cannot simply + // use From(), as the type From may not have a public default + // constructor. + static From MakeFrom(); + + // These two functions are overloaded. Given an expression + // Helper(x), the compiler will pick the first version if x can be + // implicitly converted to type To; otherwise it will pick the + // second version. + // + // The first version returns a value of size 1, and the second + // version returns a value of size 2. Therefore, by checking the + // size of Helper(x), which can be done at compile time, we can tell + // which version of Helper() is used, and hence whether x can be + // implicitly converted to type To. + static char Helper(To); + static char (&Helper(...))[2]; // NOLINT + + // We have to put the 'public' section after the 'private' section, + // or MSVC refuses to compile the code. + public: + // MSVC warns about implicitly converting from double to int for + // possible loss of data, so we need to temporarily disable the + // warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4244) // Temporarily disables warning 4244. + + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +# pragma warning(pop) // Restores the warning state. +#elif defined(__BORLANDC__) + // C++Builder cannot use member overload resolution during template + // instantiation. The simplest workaround is to use its C++0x type traits + // functions (C++Builder 2009 and above only). + static const bool value = __is_convertible(From, To); +#else + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +#endif // _MSV_VER +}; +template +const bool ImplicitlyConvertible::value; + +// IsAProtocolMessage::value is a compile-time bool constant that's +// true iff T is type ProtocolMessage, proto2::Message, or a subclass +// of those. +template +struct IsAProtocolMessage + : public bool_constant< + ImplicitlyConvertible::value || + ImplicitlyConvertible::value> { +}; + +// When the compiler sees expression IsContainerTest(0), if C is an +// STL-style container class, the first overload of IsContainerTest +// will be viable (since both C::iterator* and C::const_iterator* are +// valid types and NULL can be implicitly converted to them). It will +// be picked over the second overload as 'int' is a perfect match for +// the type of argument 0. If C::iterator or C::const_iterator is not +// a valid type, the first overload is not viable, and the second +// overload will be picked. Therefore, we can determine whether C is +// a container class by checking the type of IsContainerTest(0). +// The value of the expression is insignificant. +// +// Note that we look for both C::iterator and C::const_iterator. The +// reason is that C++ injects the name of a class as a member of the +// class itself (e.g. you can refer to class iterator as either +// 'iterator' or 'iterator::iterator'). If we look for C::iterator +// only, for example, we would mistakenly think that a class named +// iterator is an STL container. +// +// Also note that the simpler approach of overloading +// IsContainerTest(typename C::const_iterator*) and +// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. +typedef int IsContainer; +template +IsContainer IsContainerTest(int /* dummy */, + typename C::iterator* /* it */ = NULL, + typename C::const_iterator* /* const_it */ = NULL) { + return 0; +} + +typedef char IsNotContainer; +template +IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } + +// EnableIf::type is void when 'Cond' is true, and +// undefined when 'Cond' is false. To use SFINAE to make a function +// overload only apply when a particular expression is true, add +// "typename EnableIf::type* = 0" as the last parameter. +template struct EnableIf; +template<> struct EnableIf { typedef void type; }; // NOLINT + +// Utilities for native arrays. + +// ArrayEq() compares two k-dimensional native arrays using the +// elements' operator==, where k can be any integer >= 0. When k is +// 0, ArrayEq() degenerates into comparing a single pair of values. + +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template +inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { + return internal::ArrayEq(lhs, N, rhs); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous ArrayEq() function, arrays with different sizes would +// lead to different copies of the template code. +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs) { + for (size_t i = 0; i != size; i++) { + if (!internal::ArrayEq(lhs[i], rhs[i])) + return false; + } + return true; +} + +// Finds the first element in the iterator range [begin, end) that +// equals elem. Element may be a native array type itself. +template +Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { + for (Iter it = begin; it != end; ++it) { + if (internal::ArrayEq(*it, elem)) + return it; + } + return end; +} + +// CopyArray() copies a k-dimensional native array using the elements' +// operator=, where k can be any integer >= 0. When k is 0, +// CopyArray() degenerates into copying a single value. + +template +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template +inline void CopyArray(const T(&from)[N], U(*to)[N]) { + internal::CopyArray(from, N, *to); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous CopyArray() function, arrays with different sizes +// would lead to different copies of the template code. +template +void CopyArray(const T* from, size_t size, U* to) { + for (size_t i = 0; i != size; i++) { + internal::CopyArray(from[i], to + i); + } +} + +// The relation between an NativeArray object (see below) and the +// native array it represents. +enum RelationToSource { + kReference, // The NativeArray references the native array. + kCopy // The NativeArray makes a copy of the native array and + // owns the copy. +}; + +// Adapts a native array to a read-only STL-style container. Instead +// of the complete STL container concept, this adaptor only implements +// members useful for Google Mock's container matchers. New members +// should be added as needed. To simplify the implementation, we only +// support Element being a raw type (i.e. having no top-level const or +// reference modifier). It's the client's responsibility to satisfy +// this requirement. Element can be an array type itself (hence +// multi-dimensional arrays are supported). +template +class NativeArray { + public: + // STL-style container typedefs. + typedef Element value_type; + typedef Element* iterator; + typedef const Element* const_iterator; + + // Constructs from a native array. + NativeArray(const Element* array, size_t count, RelationToSource relation) { + Init(array, count, relation); + } + + // Copy constructor. + NativeArray(const NativeArray& rhs) { + Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + } + + ~NativeArray() { + // Ensures that the user doesn't instantiate NativeArray with a + // const or reference type. + static_cast(StaticAssertTypeEqHelper()); + if (relation_to_source_ == kCopy) + delete[] array_; + } + + // STL-style container methods. + size_t size() const { return size_; } + const_iterator begin() const { return array_; } + const_iterator end() const { return array_ + size_; } + bool operator==(const NativeArray& rhs) const { + return size() == rhs.size() && + ArrayEq(begin(), size(), rhs.begin()); + } + + private: + // Initializes this object; makes a copy of the input array if + // 'relation' is kCopy. + void Init(const Element* array, size_t a_size, RelationToSource relation) { + if (relation == kReference) { + array_ = array; + } else { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; + } + size_ = a_size; + relation_to_source_ = relation; + } + + const Element* array_; + size_t size_; + RelationToSource relation_to_source_; + + GTEST_DISALLOW_ASSIGN_(NativeArray); +}; + +} // namespace internal +} // namespace testing + +#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ + ::testing::internal::AssertHelper(result_type, file, line, message) \ + = ::testing::Message() + +#define GTEST_MESSAGE_(message, result_type) \ + GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) + +#define GTEST_FATAL_FAILURE_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) + +#define GTEST_NONFATAL_FAILURE_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) + +#define GTEST_SUCCESS_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) + +// Suppresses MSVC warnings 4072 (unreachable code) for the code following +// statement if it returns or throws (or doesn't return or throw in some +// situations). +#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ + if (::testing::internal::AlwaysTrue()) { statement; } + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::ConstCharPtr gtest_msg = "") { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + catch (...) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ + fail(gtest_msg.value) + +#define GTEST_TEST_NO_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ + fail("Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: it throws.") + +#define GTEST_TEST_ANY_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + bool gtest_caught_any = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_caught_any = true; \ + } \ + if (!gtest_caught_any) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ + fail("Expected: " #statement " throws an exception.\n" \ + " Actual: it doesn't.") + + +// Implements Boolean test assertions such as EXPECT_TRUE. expression can be +// either a boolean expression or an AssertionResult. text is a textual +// represenation of expression as it was passed into the EXPECT_TRUE. +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) \ + ; \ + else \ + fail(::testing::internal::GetBoolAssertionFailureMessage(\ + gtest_ar_, text, #actual, #expected).c_str()) + +#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ + fail("Expected: " #statement " doesn't generate new fatal " \ + "failures in the current thread.\n" \ + " Actual: it does.") + +// Expands to the name of the class that implements the given test. +#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + test_case_name##_##test_name##_Test + +// Helper macro for defining tests. +#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ +class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ + public:\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ + private:\ + virtual void TestBody();\ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ +};\ +\ +::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ + ::test_info_ =\ + ::testing::internal::MakeAndRegisterTestInfo(\ + #test_case_name, #test_name, NULL, NULL, \ + (parent_id), \ + parent_class::SetUpTestCase, \ + parent_class::TearDownTestCase, \ + new ::testing::internal::TestFactoryImpl<\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ +void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for death tests. It is +// #included by gtest.h so a user doesn't need to include this +// directly. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines internal utilities needed for implementing +// death tests. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + + +#include + +namespace testing { +namespace internal { + +GTEST_DECLARE_string_(internal_run_death_test); + +// Names of the flags (needed for parsing Google Test flags). +const char kDeathTestStyleFlag[] = "death_test_style"; +const char kDeathTestUseFork[] = "death_test_use_fork"; +const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; + +#if GTEST_HAS_DEATH_TEST + +// DeathTest is a class that hides much of the complexity of the +// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method +// returns a concrete class that depends on the prevailing death test +// style, as defined by the --gtest_death_test_style and/or +// --gtest_internal_run_death_test flags. + +// In describing the results of death tests, these terms are used with +// the corresponding definitions: +// +// exit status: The integer exit information in the format specified +// by wait(2) +// exit code: The integer code passed to exit(3), _exit(2), or +// returned from main() +class GTEST_API_ DeathTest { + public: + // Create returns false if there was an error determining the + // appropriate action to take for the current death test; for example, + // if the gtest_death_test_style flag is set to an invalid value. + // The LastMessage method will return a more detailed message in that + // case. Otherwise, the DeathTest pointer pointed to by the "test" + // argument is set. If the death test should be skipped, the pointer + // is set to NULL; otherwise, it is set to the address of a new concrete + // DeathTest object that controls the execution of the current test. + static bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); + DeathTest(); + virtual ~DeathTest() { } + + // A helper class that aborts a death test when it's deleted. + class ReturnSentinel { + public: + explicit ReturnSentinel(DeathTest* test) : test_(test) { } + ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } + private: + DeathTest* const test_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); + } GTEST_ATTRIBUTE_UNUSED_; + + // An enumeration of possible roles that may be taken when a death + // test is encountered. EXECUTE means that the death test logic should + // be executed immediately. OVERSEE means that the program should prepare + // the appropriate environment for a child process to execute the death + // test, then wait for it to complete. + enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; + + // An enumeration of the three reasons that a test might be aborted. + enum AbortReason { + TEST_ENCOUNTERED_RETURN_STATEMENT, + TEST_THREW_EXCEPTION, + TEST_DID_NOT_DIE + }; + + // Assumes one of the above roles. + virtual TestRole AssumeRole() = 0; + + // Waits for the death test to finish and returns its status. + virtual int Wait() = 0; + + // Returns true if the death test passed; that is, the test process + // exited during the test, its exit status matches a user-supplied + // predicate, and its stderr output matches a user-supplied regular + // expression. + // The user-supplied predicate may be a macro expression rather + // than a function pointer or functor, or else Wait and Passed could + // be combined. + virtual bool Passed(bool exit_status_ok) = 0; + + // Signals that the death test did not die as expected. + virtual void Abort(AbortReason reason) = 0; + + // Returns a human-readable outcome message regarding the outcome of + // the last death test. + static const char* LastMessage(); + + static void set_last_death_test_message(const std::string& message); + + private: + // A string containing a description of the outcome of the last death test. + static std::string last_death_test_message_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); +}; + +// Factory interface for death tests. May be mocked out for testing. +class DeathTestFactory { + public: + virtual ~DeathTestFactory() { } + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) = 0; +}; + +// A concrete DeathTestFactory implementation for normal use. +class DefaultDeathTestFactory : public DeathTestFactory { + public: + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); +}; + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +GTEST_API_ bool ExitedUnsuccessfully(int exit_status); + +// Traps C++ exceptions escaping statement and reports them as test +// failures. Note that trapping SEH exceptions is not implemented here. +# if GTEST_HAS_EXCEPTIONS +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (const ::std::exception& gtest_exception) { \ + fprintf(\ + stderr, \ + "\n%s: Caught std::exception-derived exception escaping the " \ + "death test statement. Exception message: %s\n", \ + ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ + gtest_exception.what()); \ + fflush(stderr); \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } catch (...) { \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } + +# else +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) + +# endif + +// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, +// ASSERT_EXIT*, and EXPECT_EXIT*. +# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + const ::testing::internal::RE& gtest_regex = (regex); \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != NULL) { \ + ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ + gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel \ + gtest_sentinel(gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: \ + break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ + fail(::testing::internal::DeathTest::LastMessage()) +// The symbol "fail" here expands to something into which a message +// can be streamed. + +// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in +// NDEBUG mode. In this case we need the statements to be executed, the regex is +// ignored, and the macro must accept a streamed message even though the message +// is never printed. +# define GTEST_EXECUTE_STATEMENT_(statement, regex) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else \ + ::testing::Message() + +// A class representing the parsed contents of the +// --gtest_internal_run_death_test flag, as it existed when +// RUN_ALL_TESTS was called. +class InternalRunDeathTestFlag { + public: + InternalRunDeathTestFlag(const std::string& a_file, + int a_line, + int an_index, + int a_write_fd) + : file_(a_file), line_(a_line), index_(an_index), + write_fd_(a_write_fd) {} + + ~InternalRunDeathTestFlag() { + if (write_fd_ >= 0) + posix::Close(write_fd_); + } + + const std::string& file() const { return file_; } + int line() const { return line_; } + int index() const { return index_; } + int write_fd() const { return write_fd_; } + + private: + std::string file_; + int line_; + int index_; + int write_fd_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); +}; + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); + +#else // GTEST_HAS_DEATH_TEST + +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on +// systems that support death tests. This allows one to write such a macro +// on a system that does not support death tests and be sure that it will +// compile on a death-test supporting system. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter iff EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + +namespace testing { + +// This flag controls the style of death tests. Valid values are "threadsafe", +// meaning that the death test child process will re-execute the test binary +// from the start, running only a single death test, or "fast", +// meaning that the child process will execute the test logic immediately +// after forking. +GTEST_DECLARE_string_(death_test_style); + +#if GTEST_HAS_DEATH_TEST + +namespace internal { + +// Returns a Boolean value indicating whether the caller is currently +// executing in the context of the death test child process. Tools such as +// Valgrind heap checkers may need this to modify their behavior in death +// tests. IMPORTANT: This is an internal utility. Using it may break the +// implementation of death tests. User code MUST NOT use it. +GTEST_API_ bool InDeathTestChild(); + +} // namespace internal + +// The following macros are useful for writing death tests. + +// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is +// executed: +// +// 1. It generates a warning if there is more than one active +// thread. This is because it's safe to fork() or clone() only +// when there is a single thread. +// +// 2. The parent process clone()s a sub-process and runs the death +// test in it; the sub-process exits with code 0 at the end of the +// death test, if it hasn't exited already. +// +// 3. The parent process waits for the sub-process to terminate. +// +// 4. The parent process checks the exit code and error message of +// the sub-process. +// +// Examples: +// +// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); +// for (int i = 0; i < 5; i++) { +// EXPECT_DEATH(server.ProcessRequest(i), +// "Invalid request .* in ProcessRequest()") +// << "Failed to die on request " << i; +// } +// +// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); +// +// bool KilledBySIGHUP(int exit_code) { +// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; +// } +// +// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); +// +// On the regular expressions used in death tests: +// +// On POSIX-compliant systems (*nix), we use the library, +// which uses the POSIX extended regex syntax. +// +// On other platforms (e.g. Windows), we only support a simple regex +// syntax implemented as part of Google Test. This limited +// implementation should be enough most of the time when writing +// death tests; though it lacks many features you can find in PCRE +// or POSIX extended regex syntax. For example, we don't support +// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and +// repetition count ("x{5,7}"), among others. +// +// Below is the syntax that we do support. We chose it to be a +// subset of both PCRE and POSIX extended regex, so it's easy to +// learn wherever you come from. In the following: 'A' denotes a +// literal character, period (.), or a single \\ escape sequence; +// 'x' and 'y' denote regular expressions; 'm' and 'n' are for +// natural numbers. +// +// c matches any literal character c +// \\d matches any decimal digit +// \\D matches any character that's not a decimal digit +// \\f matches \f +// \\n matches \n +// \\r matches \r +// \\s matches any ASCII whitespace, including \n +// \\S matches any character that's not a whitespace +// \\t matches \t +// \\v matches \v +// \\w matches any letter, _, or decimal digit +// \\W matches any character that \\w doesn't match +// \\c matches any literal character c, which must be a punctuation +// . matches any single character except \n +// A? matches 0 or 1 occurrences of A +// A* matches 0 or many occurrences of A +// A+ matches 1 or many occurrences of A +// ^ matches the beginning of a string (not that of each line) +// $ matches the end of a string (not that of each line) +// xy matches x followed by y +// +// If you accidentally use PCRE or POSIX extended regex features +// not implemented by us, you will get a run-time failure. In that +// case, please try to rewrite your regular expression within the +// above syntax. +// +// This implementation is *not* meant to be as highly tuned or robust +// as a compiled regex library, but should perform well enough for a +// death test, which already incurs significant overhead by launching +// a child process. +// +// Known caveats: +// +// A "threadsafe" style death test obtains the path to the test +// program from argv[0] and re-executes it in the sub-process. For +// simplicity, the current implementation doesn't search the PATH +// when launching the sub-process. This means that the user must +// invoke the test program via a path that contains at least one +// path separator (e.g. path/to/foo_test and +// /absolute/path/to/bar_test are fine, but foo_test is not). This +// is rarely a problem as people usually don't put the test binary +// directory in PATH. +// +// TODO(wan@google.com): make thread-safe death tests search the PATH. + +// Asserts that a given statement causes the program to exit, with an +// integer exit status that satisfies predicate, and emitting error output +// that matches regex. +# define ASSERT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) + +// Like ASSERT_EXIT, but continues on to successive tests in the +// test case, if any: +# define EXPECT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) + +// Asserts that a given statement causes the program to exit, either by +// explicitly exiting with a nonzero exit code or being killed by a +// signal, and emitting error output that matches regex. +# define ASSERT_DEATH(statement, regex) \ + ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Like ASSERT_DEATH, but continues on to successive tests in the +// test case, if any: +# define EXPECT_DEATH(statement, regex) \ + EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: + +// Tests that an exit code describes a normal exit with a given exit code. +class GTEST_API_ ExitedWithCode { + public: + explicit ExitedWithCode(int exit_code); + bool operator()(int exit_status) const; + private: + // No implementation - assignment is unsupported. + void operator=(const ExitedWithCode& other); + + const int exit_code_; +}; + +# if !GTEST_OS_WINDOWS +// Tests that an exit code describes an exit due to termination by a +// given signal. +class GTEST_API_ KilledBySignal { + public: + explicit KilledBySignal(int signum); + bool operator()(int exit_status) const; + private: + const int signum_; +}; +# endif // !GTEST_OS_WINDOWS + +// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. +// The death testing framework causes this to have interesting semantics, +// since the sideeffects of the call are only visible in opt mode, and not +// in debug mode. +// +// In practice, this can be used to test functions that utilize the +// LOG(DFATAL) macro using the following style: +// +// int DieInDebugOr12(int* sideeffect) { +// if (sideeffect) { +// *sideeffect = 12; +// } +// LOG(DFATAL) << "death"; +// return 12; +// } +// +// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// int sideeffect = 0; +// // Only asserts in dbg. +// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); +// +// #ifdef NDEBUG +// // opt-mode has sideeffect visible. +// EXPECT_EQ(12, sideeffect); +// #else +// // dbg-mode no visible sideeffect. +// EXPECT_EQ(0, sideeffect); +// #endif +// } +// +// This will assert that DieInDebugReturn12InOpt() crashes in debug +// mode, usually due to a DCHECK or LOG(DFATAL), but returns the +// appropriate fallback value (12 in this case) in opt mode. If you +// need to test that a function has appropriate side-effects in opt +// mode, include assertions against the side-effects. A general +// pattern for this is: +// +// EXPECT_DEBUG_DEATH({ +// // Side-effects here will have an effect after this statement in +// // opt mode, but none in debug mode. +// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); +// }, "death"); +// +# ifdef NDEBUG + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + GTEST_EXECUTE_STATEMENT_(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + GTEST_EXECUTE_STATEMENT_(statement, regex) + +# else + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + EXPECT_DEATH(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + ASSERT_DEATH(statement, regex) + +# endif // NDEBUG for EXPECT_DEBUG_DEATH +#endif // GTEST_HAS_DEATH_TEST + +// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and +// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if +// death tests are supported; otherwise they just issue a warning. This is +// useful when you are combining death test assertions with normal test +// assertions in one test. +#if GTEST_HAS_DEATH_TEST +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEATH(statement, regex) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + ASSERT_DEATH(statement, regex) +#else +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) +#endif + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +// This file was GENERATED by command: +// pump.py gtest-param-test.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: vladl@google.com (Vlad Losev) +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing Framework (Google Test) +// +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It is usually derived from testing::TestWithParam (see below for +// another inheritance scheme that's sometimes useful in more complicated +// class hierarchies), where the type of your parameter values. +// TestWithParam is itself derived from testing::Test. T can be any +// copyable type. If it's a raw pointer, you are responsible for managing the +// lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test case +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_CASE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more then once) the first argument to the +// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the +// actual test case name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests +// in the given test case, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_CASE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. +// +// +// A parameterized test fixture must be derived from testing::Test and from +// testing::WithParamInterface, where T is the type of the parameter +// values. Inheriting from TestWithParam satisfies that requirement because +// TestWithParam inherits from both Test and WithParamInterface. In more +// complicated hierarchies, however, it is occasionally useful to inherit +// separately from Test and WithParamInterface. For example: + +class BaseTest : public ::testing::Test { + // You can inherit all the usual members for a non-parameterized test + // fixture here. +}; + +class DerivedTest : public BaseTest, public ::testing::WithParamInterface { + // The usual test fixture members go here too. +}; + +TEST_F(BaseTest, HasFoo) { + // This is an ordinary non-parameterized test. +} + +TEST_P(DerivedTest, DoesBlah) { + // GetParam works just the same here as if you inherit from TestWithParam. + EXPECT_TRUE(foo.Blah(GetParam())); +} + +#endif // 0 + + +#if !GTEST_OS_SYMBIAN +# include +#endif + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ + +#include +#include +#include + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +// Copyright 2003 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Dan Egnor (egnor@google.com) +// +// A "smart" pointer type with reference tracking. Every pointer to a +// particular object is kept on a circular linked list. When the last pointer +// to an object is destroyed or reassigned, the object is deleted. +// +// Used properly, this deletes the object when the last reference goes away. +// There are several caveats: +// - Like all reference counting schemes, cycles lead to leaks. +// - Each smart pointer is actually two pointers (8 bytes instead of 4). +// - Every time a pointer is assigned, the entire list of pointers to that +// object is traversed. This class is therefore NOT SUITABLE when there +// will often be more than two or three pointers to a particular object. +// - References are only tracked as long as linked_ptr<> objects are copied. +// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS +// will happen (double deletion). +// +// A good use of this class is storing object references in STL containers. +// You can safely put linked_ptr<> in a vector<>. +// Other uses may not be as good. +// +// Note: If you use an incomplete type with linked_ptr<>, the class +// *containing* linked_ptr<> must have a constructor and destructor (even +// if they do nothing!). +// +// Bill Gibbons suggested we use something like this. +// +// Thread Safety: +// Unlike other linked_ptr implementations, in this implementation +// a linked_ptr object is thread-safe in the sense that: +// - it's safe to copy linked_ptr objects concurrently, +// - it's safe to copy *from* a linked_ptr and read its underlying +// raw pointer (e.g. via get()) concurrently, and +// - it's safe to write to two linked_ptrs that point to the same +// shared object concurrently. +// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// confusion with normal linked_ptr. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#include +#include + + +namespace testing { +namespace internal { + +// Protects copying of all linked_ptr objects. +GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// This is used internally by all instances of linked_ptr<>. It needs to be +// a non-template class because different types of linked_ptr<> can refer to +// the same object (linked_ptr(obj) vs linked_ptr(obj)). +// So, it needs to be possible for different types of linked_ptr to participate +// in the same circular linked list, so we need a single class type here. +// +// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. +class linked_ptr_internal { + public: + // Create a new circle that includes only this instance. + void join_new() { + next_ = this; + } + + // Many linked_ptr operations may change p.link_ for some linked_ptr + // variable p in the same circle as this object. Therefore we need + // to prevent two such operations from occurring concurrently. + // + // Note that different types of linked_ptr objects can coexist in a + // circle (e.g. linked_ptr, linked_ptr, and + // linked_ptr). Therefore we must use a single mutex to + // protect all linked_ptr objects. This can create serious + // contention in production code, but is acceptable in a testing + // framework. + + // Join an existing circle. + void join(linked_ptr_internal const* ptr) + GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { + MutexLock lock(&g_linked_ptr_mutex); + + linked_ptr_internal const* p = ptr; + while (p->next_ != ptr) p = p->next_; + p->next_ = this; + next_ = ptr; + } + + // Leave whatever circle we're part of. Returns true if we were the + // last member of the circle. Once this is done, you can join() another. + bool depart() + GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { + MutexLock lock(&g_linked_ptr_mutex); + + if (next_ == this) return true; + linked_ptr_internal const* p = next_; + while (p->next_ != this) p = p->next_; + p->next_ = next_; + return false; + } + + private: + mutable linked_ptr_internal const* next_; +}; + +template +class linked_ptr { + public: + typedef T element_type; + + // Take over ownership of a raw pointer. This should happen as soon as + // possible after the object is created. + explicit linked_ptr(T* ptr = NULL) { capture(ptr); } + ~linked_ptr() { depart(); } + + // Copy an existing linked_ptr<>, adding ourselves to the list of references. + template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + linked_ptr(linked_ptr const& ptr) { // NOLINT + assert(&ptr != this); + copy(&ptr); + } + + // Assignment releases the old value and acquires the new. + template linked_ptr& operator=(linked_ptr const& ptr) { + depart(); + copy(&ptr); + return *this; + } + + linked_ptr& operator=(linked_ptr const& ptr) { + if (&ptr != this) { + depart(); + copy(&ptr); + } + return *this; + } + + // Smart pointer members. + void reset(T* ptr = NULL) { + depart(); + capture(ptr); + } + T* get() const { return value_; } + T* operator->() const { return value_; } + T& operator*() const { return *value_; } + + bool operator==(T* p) const { return value_ == p; } + bool operator!=(T* p) const { return value_ != p; } + template + bool operator==(linked_ptr const& ptr) const { + return value_ == ptr.get(); + } + template + bool operator!=(linked_ptr const& ptr) const { + return value_ != ptr.get(); + } + + private: + template + friend class linked_ptr; + + T* value_; + linked_ptr_internal link_; + + void depart() { + if (link_.depart()) delete value_; + } + + void capture(T* ptr) { + value_ = ptr; + link_.join_new(); + } + + template void copy(linked_ptr const* ptr) { + value_ = ptr->get(); + if (value_) + link_.join(&ptr->link_); + else + link_.join_new(); + } +}; + +template inline +bool operator==(T* ptr, const linked_ptr& x) { + return ptr == x.get(); +} + +template inline +bool operator!=(T* ptr, const linked_ptr& x) { + return ptr != x.get(); +} + +// A function to convert T* into linked_ptr +// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation +// for linked_ptr >(new FooBarBaz(arg)) +template +linked_ptr make_linked_ptr(T* ptr) { + return linked_ptr(ptr); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// A user can teach this function how to print a class type T by +// defining either operator<<() or PrintTo() in the namespace that +// defines T. More specifically, the FIRST defined function in the +// following list will be used (assuming T is defined in namespace +// foo): +// +// 1. foo::PrintTo(const T&, ostream*) +// 2. operator<<(ostream&, const T&) defined in either foo or the +// global namespace. +// +// If none of the above is defined, it will print the debug string of +// the value if it is a protocol buffer, or print the raw bytes in the +// value otherwise. +// +// To aid debugging: when T is a reference type, the address of the +// value is also printed; when T is a (const) char pointer, both the +// pointer value and the NUL-terminated string it points to are +// printed. +// +// We also provide some convenient wrappers: +// +// // Prints a value to a string. For a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// std::string ::testing::PrintToString(const T& value); +// +// // Prints a value tersely: for a reference type, the referenced +// // value (but not the address) is printed; for a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); +// +// // Prints value using the type inferred by the compiler. The difference +// // from UniversalTersePrint() is that this function prints both the +// // pointer and the NUL-terminated string for a (const or not) char pointer. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); +// +// // Prints the fields of a tuple tersely to a string vector, one +// // element for each field. Tuple support must be enabled in +// // gtest-port.h. +// std::vector UniversalTersePrintTupleFieldsToStrings( +// const Tuple& value); +// +// Known limitation: +// +// The print primitives print the elements of an STL-style container +// using the compiler-inferred type of *iter where iter is a +// const_iterator of the container. When const_iterator is an input +// iterator but not a forward iterator, this inferred type may not +// match value_type, and the print output may be incorrect. In +// practice, this is rarely a problem as for most containers +// const_iterator is a forward iterator. We'll fix this if there's an +// actual need for it. Note that this fix cannot rely on value_type +// being defined as many user-defined container types don't have +// value_type. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#include // NOLINT +#include +#include +#include +#include + +namespace testing { + +// Definitions in the 'internal' and 'internal2' name spaces are +// subject to change without notice. DO NOT USE THEM IN USER CODE! +namespace internal2 { + +// Prints the given number of bytes in the given object to the given +// ostream. +GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, + size_t count, + ::std::ostream* os); + +// For selecting which printer to use when a given type has neither << +// nor PrintTo(). +enum TypeKind { + kProtobuf, // a protobuf type + kConvertibleToInteger, // a type implicitly convertible to BiggestInt + // (e.g. a named or unnamed enum type) + kOtherType // anything else +}; + +// TypeWithoutFormatter::PrintValue(value, os) is called +// by the universal printer to print a value of type T when neither +// operator<< nor PrintTo() is defined for T, where kTypeKind is the +// "kind" of T as defined by enum TypeKind. +template +class TypeWithoutFormatter { + public: + // This default version is called when kTypeKind is kOtherType. + static void PrintValue(const T& value, ::std::ostream* os) { + PrintBytesInObjectTo(reinterpret_cast(&value), + sizeof(value), os); + } +}; + +// We print a protobuf using its ShortDebugString() when the string +// doesn't exceed this many characters; otherwise we print it using +// DebugString() for better readability. +const size_t kProtobufOneLinerMaxLength = 50; + +template +class TypeWithoutFormatter { + public: + static void PrintValue(const T& value, ::std::ostream* os) { + const ::testing::internal::string short_str = value.ShortDebugString(); + const ::testing::internal::string pretty_str = + short_str.length() <= kProtobufOneLinerMaxLength ? + short_str : ("\n" + value.DebugString()); + *os << ("<" + pretty_str + ">"); + } +}; + +template +class TypeWithoutFormatter { + public: + // Since T has no << operator or PrintTo() but can be implicitly + // converted to BiggestInt, we print it as a BiggestInt. + // + // Most likely T is an enum type (either named or unnamed), in which + // case printing it as an integer is the desired behavior. In case + // T is not an enum, printing it as an integer is the best we can do + // given that it has no user-defined printer. + static void PrintValue(const T& value, ::std::ostream* os) { + const internal::BiggestInt kBigInt = value; + *os << kBigInt; + } +}; + +// Prints the given value to the given ostream. If the value is a +// protocol message, its debug string is printed; if it's an enum or +// of a type implicitly convertible to BiggestInt, it's printed as an +// integer; otherwise the bytes in the value are printed. This is +// what UniversalPrinter::Print() does when it knows nothing about +// type T and T has neither << operator nor PrintTo(). +// +// A user can override this behavior for a class type Foo by defining +// a << operator in the namespace where Foo is defined. +// +// We put this operator in namespace 'internal2' instead of 'internal' +// to simplify the implementation, as much code in 'internal' needs to +// use << in STL, which would conflict with our own << were it defined +// in 'internal'. +// +// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If +// we define it to take an std::ostream instead, we'll get an +// "ambiguous overloads" compiler error when trying to print a type +// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether +// operator<<(std::ostream&, const T&) or +// operator<<(std::basic_stream, const Foo&) is more +// specific. +template +::std::basic_ostream& operator<<( + ::std::basic_ostream& os, const T& x) { + TypeWithoutFormatter::value ? kProtobuf : + internal::ImplicitlyConvertible::value ? + kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); + return os; +} + +} // namespace internal2 +} // namespace testing + +// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up +// magic needed for implementing UniversalPrinter won't work. +namespace testing_internal { + +// Used to print a value that is not an STL-style container when the +// user doesn't define PrintTo() for it. +template +void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { + // With the following statement, during unqualified name lookup, + // testing::internal2::operator<< appears as if it was declared in + // the nearest enclosing namespace that contains both + // ::testing_internal and ::testing::internal2, i.e. the global + // namespace. For more details, refer to the C++ Standard section + // 7.3.4-1 [namespace.udir]. This allows us to fall back onto + // testing::internal2::operator<< in case T doesn't come with a << + // operator. + // + // We cannot write 'using ::testing::internal2::operator<<;', which + // gcc 3.3 fails to compile due to a compiler bug. + using namespace ::testing::internal2; // NOLINT + + // Assuming T is defined in namespace foo, in the next statement, + // the compiler will consider all of: + // + // 1. foo::operator<< (thanks to Koenig look-up), + // 2. ::operator<< (as the current namespace is enclosed in ::), + // 3. testing::internal2::operator<< (thanks to the using statement above). + // + // The operator<< whose type matches T best will be picked. + // + // We deliberately allow #2 to be a candidate, as sometimes it's + // impossible to define #1 (e.g. when foo is ::std, defining + // anything in it is undefined behavior unless you are a compiler + // vendor.). + *os << value; +} + +} // namespace testing_internal + +namespace testing { +namespace internal { + +// UniversalPrinter::Print(value, ostream_ptr) prints the given +// value to the given ostream. The caller must ensure that +// 'ostream_ptr' is not NULL, or the behavior is undefined. +// +// We define UniversalPrinter as a class template (as opposed to a +// function template), as we need to partially specialize it for +// reference types, which cannot be done with function templates. +template +class UniversalPrinter; + +template +void UniversalPrint(const T& value, ::std::ostream* os); + +// Used to print an STL-style container when the user doesn't define +// a PrintTo() for it. +template +void DefaultPrintTo(IsContainer /* dummy */, + false_type /* is not a pointer */, + const C& container, ::std::ostream* os) { + const size_t kMaxCount = 32; // The maximum number of elements to print. + *os << '{'; + size_t count = 0; + for (typename C::const_iterator it = container.begin(); + it != container.end(); ++it, ++count) { + if (count > 0) { + *os << ','; + if (count == kMaxCount) { // Enough has been printed. + *os << " ..."; + break; + } + } + *os << ' '; + // We cannot call PrintTo(*it, os) here as PrintTo() doesn't + // handle *it being a native array. + internal::UniversalPrint(*it, os); + } + + if (count > 0) { + *os << ' '; + } + *os << '}'; +} + +// Used to print a pointer that is neither a char pointer nor a member +// pointer, when the user doesn't define PrintTo() for it. (A member +// variable pointer or member function pointer doesn't really point to +// a location in the address space. Their representation is +// implementation-defined. Therefore they will be printed as raw +// bytes.) +template +void DefaultPrintTo(IsNotContainer /* dummy */, + true_type /* is a pointer */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // C++ doesn't allow casting from a function pointer to any object + // pointer. + // + // IsTrue() silences warnings: "Condition is always true", + // "unreachable code". + if (IsTrue(ImplicitlyConvertible::value)) { + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. However, we cannot cast it to const void* directly, + // even using reinterpret_cast, as earlier versions of gcc + // (e.g. 3.4.5) cannot compile the cast when p is a function + // pointer. Casting to UInt64 first solves the problem. + *os << reinterpret_cast( + reinterpret_cast(p)); + } + } +} + +// Used to print a non-container, non-pointer value when the user +// doesn't define PrintTo() for it. +template +void DefaultPrintTo(IsNotContainer /* dummy */, + false_type /* is not a pointer */, + const T& value, ::std::ostream* os) { + ::testing_internal::DefaultPrintNonContainerTo(value, os); +} + +// Prints the given value using the << operator if it has one; +// otherwise prints the bytes in it. This is what +// UniversalPrinter::Print() does when PrintTo() is not specialized +// or overloaded for type T. +// +// A user can override this behavior for a class type Foo by defining +// an overload of PrintTo() in the namespace where Foo is defined. We +// give the user this option as sometimes defining a << operator for +// Foo is not desirable (e.g. the coding style may prevent doing it, +// or there is already a << operator but it doesn't do what the user +// wants). +template +void PrintTo(const T& value, ::std::ostream* os) { + // DefaultPrintTo() is overloaded. The type of its first two + // arguments determine which version will be picked. If T is an + // STL-style container, the version for container will be called; if + // T is a pointer, the pointer version will be called; otherwise the + // generic version will be called. + // + // Note that we check for container types here, prior to we check + // for protocol message types in our operator<<. The rationale is: + // + // For protocol messages, we want to give people a chance to + // override Google Mock's format by defining a PrintTo() or + // operator<<. For STL containers, other formats can be + // incompatible with Google Mock's format for the container + // elements; therefore we check for container types here to ensure + // that our format is used. + // + // The second argument of DefaultPrintTo() is needed to bypass a bug + // in Symbian's C++ compiler that prevents it from picking the right + // overload between: + // + // PrintTo(const T& x, ...); + // PrintTo(T* x, ...); + DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); +} + +// The following list of PrintTo() overloads tells +// UniversalPrinter::Print() how to print standard types (built-in +// types, strings, plain arrays, and pointers). + +// Overloads for various char types. +GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); +GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); +inline void PrintTo(char c, ::std::ostream* os) { + // When printing a plain char, we always treat it as unsigned. This + // way, the output won't be affected by whether the compiler thinks + // char is signed or not. + PrintTo(static_cast(c), os); +} + +// Overloads for other simple built-in types. +inline void PrintTo(bool x, ::std::ostream* os) { + *os << (x ? "true" : "false"); +} + +// Overload for wchar_t type. +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); + +// Overloads for C strings. +GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); +inline void PrintTo(char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// signed/unsigned char is often used for representing binary data, so +// we print pointers to it as void* to be safe. +inline void PrintTo(const signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(const unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// MSVC can be configured to define wchar_t as a typedef of unsigned +// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native +// type. When wchar_t is a typedef, defining an overload for const +// wchar_t* would cause unsigned short* be printed as a wide string, +// possibly causing invalid memory accesses. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Overloads for wide C strings +GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); +inline void PrintTo(wchar_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +#endif + +// Overload for C arrays. Multi-dimensional arrays are printed +// properly. + +// Prints the given number of elements in an array, without printing +// the curly braces. +template +void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { + UniversalPrint(a[0], os); + for (size_t i = 1; i != count; i++) { + *os << ", "; + UniversalPrint(a[i], os); + } +} + +// Overloads for ::string and ::std::string. +#if GTEST_HAS_GLOBAL_STRING +GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); +inline void PrintTo(const ::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); +inline void PrintTo(const ::std::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} + +// Overloads for ::wstring and ::std::wstring. +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_TR1_TUPLE +// Overload for ::std::tr1::tuple. Needed for printing function arguments, +// which are packed as tuples. + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os); + +// Overloaded PrintTo() for tuples of various arities. We support +// tuples of up-to 10 fields. The following implementation works +// regardless of whether tr1::tuple is implemented using the +// non-standard variadic template feature or not. + +inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo( + const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} +#endif // GTEST_HAS_TR1_TUPLE + +// Overload for std::pair. +template +void PrintTo(const ::std::pair& value, ::std::ostream* os) { + *os << '('; + // We cannot use UniversalPrint(value.first, os) here, as T1 may be + // a reference type. The same for printing value.second. + UniversalPrinter::Print(value.first, os); + *os << ", "; + UniversalPrinter::Print(value.second, os); + *os << ')'; +} + +// Implements printing a non-reference type T by letting the compiler +// pick the right overload of PrintTo() for T. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + // Note: we deliberately don't call this PrintTo(), as that name + // conflicts with ::testing::internal::PrintTo in the body of the + // function. + static void Print(const T& value, ::std::ostream* os) { + // By default, ::testing::internal::PrintTo() is used for printing + // the value. + // + // Thanks to Koenig look-up, if T is a class and has its own + // PrintTo() function defined in its namespace, that function will + // be visible here. Since it is more specific than the generic ones + // in ::testing::internal, it will be picked by the compiler in the + // following statement - exactly what we want. + PrintTo(value, os); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// UniversalPrintArray(begin, len, os) prints an array of 'len' +// elements, starting at address 'begin'. +template +void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { + if (len == 0) { + *os << "{}"; + } else { + *os << "{ "; + const size_t kThreshold = 18; + const size_t kChunkSize = 8; + // If the array has more than kThreshold elements, we'll have to + // omit some details by printing only the first and the last + // kChunkSize elements. + // TODO(wan@google.com): let the user control the threshold using a flag. + if (len <= kThreshold) { + PrintRawArrayTo(begin, len, os); + } else { + PrintRawArrayTo(begin, kChunkSize, os); + *os << ", ..., "; + PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); + } + *os << " }"; + } +} +// This overload prints a (const) char array compactly. +GTEST_API_ void UniversalPrintArray( + const char* begin, size_t len, ::std::ostream* os); + +// This overload prints a (const) wchar_t array compactly. +GTEST_API_ void UniversalPrintArray( + const wchar_t* begin, size_t len, ::std::ostream* os); + +// Implements printing an array type T[N]. +template +class UniversalPrinter { + public: + // Prints the given array, omitting some elements when there are too + // many. + static void Print(const T (&a)[N], ::std::ostream* os) { + UniversalPrintArray(a, N, os); + } +}; + +// Implements printing a reference type T&. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + static void Print(const T& value, ::std::ostream* os) { + // Prints the address of the value. We use reinterpret_cast here + // as static_cast doesn't compile when T is a function type. + *os << "@" << reinterpret_cast(&value) << " "; + + // Then prints the value itself. + UniversalPrint(value, os); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// Prints a value tersely: for a reference type, the referenced value +// (but not the address) is printed; for a (const) char pointer, the +// NUL-terminated string (but not the pointer) is printed. + +template +class UniversalTersePrinter { + public: + static void Print(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); + } +}; +template +class UniversalTersePrinter { + public: + static void Print(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); + } +}; +template +class UniversalTersePrinter { + public: + static void Print(const T (&value)[N], ::std::ostream* os) { + UniversalPrinter::Print(value, os); + } +}; +template <> +class UniversalTersePrinter { + public: + static void Print(const char* str, ::std::ostream* os) { + if (str == NULL) { + *os << "NULL"; + } else { + UniversalPrint(string(str), os); + } + } +}; +template <> +class UniversalTersePrinter { + public: + static void Print(char* str, ::std::ostream* os) { + UniversalTersePrinter::Print(str, os); + } +}; + +#if GTEST_HAS_STD_WSTRING +template <> +class UniversalTersePrinter { + public: + static void Print(const wchar_t* str, ::std::ostream* os) { + if (str == NULL) { + *os << "NULL"; + } else { + UniversalPrint(::std::wstring(str), os); + } + } +}; +#endif + +template <> +class UniversalTersePrinter { + public: + static void Print(wchar_t* str, ::std::ostream* os) { + UniversalTersePrinter::Print(str, os); + } +}; + +template +void UniversalTersePrint(const T& value, ::std::ostream* os) { + UniversalTersePrinter::Print(value, os); +} + +// Prints a value using the type inferred by the compiler. The +// difference between this and UniversalTersePrint() is that for a +// (const) char pointer, this prints both the pointer and the +// NUL-terminated string. +template +void UniversalPrint(const T& value, ::std::ostream* os) { + // A workarond for the bug in VC++ 7.1 that prevents us from instantiating + // UniversalPrinter with T directly. + typedef T T1; + UniversalPrinter::Print(value, os); +} + +#if GTEST_HAS_TR1_TUPLE +typedef ::std::vector Strings; + +// This helper template allows PrintTo() for tuples and +// UniversalTersePrintTupleFieldsToStrings() to be defined by +// induction on the number of tuple fields. The idea is that +// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N +// fields in tuple t, and can be defined in terms of +// TuplePrefixPrinter. + +// The inductive case. +template +struct TuplePrefixPrinter { + // Prints the first N fields of a tuple. + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + TuplePrefixPrinter::PrintPrefixTo(t, os); + *os << ", "; + UniversalPrinter::type> + ::Print(::std::tr1::get(t), os); + } + + // Tersely prints the first N fields of a tuple to a string vector, + // one element for each field. + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Base cases. +template <> +struct TuplePrefixPrinter<0> { + template + static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} + + template + static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} +}; +// We have to specialize the entire TuplePrefixPrinter<> class +// template here, even though the definition of +// TersePrintPrefixToStrings() is the same as the generic version, as +// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't +// support specializing a method template of a class template. +template <> +struct TuplePrefixPrinter<1> { + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + UniversalPrinter::type>:: + Print(::std::tr1::get<0>(t), os); + } + + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get<0>(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os) { + *os << "("; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + PrintPrefixTo(t, os); + *os << ")"; +} + +// Prints the fields of a tuple tersely to a string vector, one +// element for each field. See the comment before +// UniversalTersePrint() for how we define "tersely". +template +Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { + Strings result; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + TersePrintPrefixToStrings(value, &result); + return result; +} +#endif // GTEST_HAS_TR1_TUPLE + +} // namespace internal + +template +::std::string PrintToString(const T& value) { + ::std::stringstream ss; + internal::UniversalTersePrinter::Print(value, &ss); + return ss.str(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#if GTEST_HAS_PARAM_TEST + +namespace testing { +namespace internal { + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Outputs a message explaining invalid registration of different +// fixture class for the same test case. This may happen when +// TEST_P macro is used to define two tests with the same name +// but in different namespaces. +GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line); + +template class ParamGeneratorInterface; +template class ParamGenerator; + +// Interface for iterating over elements provided by an implementation +// of ParamGeneratorInterface. +template +class ParamIteratorInterface { + public: + virtual ~ParamIteratorInterface() {} + // A pointer to the base generator instance. + // Used only for the purposes of iterator comparison + // to make sure that two iterators belong to the same generator. + virtual const ParamGeneratorInterface* BaseGenerator() const = 0; + // Advances iterator to point to the next element + // provided by the generator. The caller is responsible + // for not calling Advance() on an iterator equal to + // BaseGenerator()->End(). + virtual void Advance() = 0; + // Clones the iterator object. Used for implementing copy semantics + // of ParamIterator. + virtual ParamIteratorInterface* Clone() const = 0; + // Dereferences the current iterator and provides (read-only) access + // to the pointed value. It is the caller's responsibility not to call + // Current() on an iterator equal to BaseGenerator()->End(). + // Used for implementing ParamGenerator::operator*(). + virtual const T* Current() const = 0; + // Determines whether the given iterator and other point to the same + // element in the sequence generated by the generator. + // Used for implementing ParamGenerator::operator==(). + virtual bool Equals(const ParamIteratorInterface& other) const = 0; +}; + +// Class iterating over elements provided by an implementation of +// ParamGeneratorInterface. It wraps ParamIteratorInterface +// and implements the const forward iterator concept. +template +class ParamIterator { + public: + typedef T value_type; + typedef const T& reference; + typedef ptrdiff_t difference_type; + + // ParamIterator assumes ownership of the impl_ pointer. + ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} + ParamIterator& operator=(const ParamIterator& other) { + if (this != &other) + impl_.reset(other.impl_->Clone()); + return *this; + } + + const T& operator*() const { return *impl_->Current(); } + const T* operator->() const { return impl_->Current(); } + // Prefix version of operator++. + ParamIterator& operator++() { + impl_->Advance(); + return *this; + } + // Postfix version of operator++. + ParamIterator operator++(int /*unused*/) { + ParamIteratorInterface* clone = impl_->Clone(); + impl_->Advance(); + return ParamIterator(clone); + } + bool operator==(const ParamIterator& other) const { + return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); + } + bool operator!=(const ParamIterator& other) const { + return !(*this == other); + } + + private: + friend class ParamGenerator; + explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} + scoped_ptr > impl_; +}; + +// ParamGeneratorInterface is the binary interface to access generators +// defined in other translation units. +template +class ParamGeneratorInterface { + public: + typedef T ParamType; + + virtual ~ParamGeneratorInterface() {} + + // Generator interface definition + virtual ParamIteratorInterface* Begin() const = 0; + virtual ParamIteratorInterface* End() const = 0; +}; + +// Wraps ParamGeneratorInterface and provides general generator syntax +// compatible with the STL Container concept. +// This class implements copy initialization semantics and the contained +// ParamGeneratorInterface instance is shared among all copies +// of the original object. This is possible because that instance is immutable. +template +class ParamGenerator { + public: + typedef ParamIterator iterator; + + explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} + ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} + + ParamGenerator& operator=(const ParamGenerator& other) { + impl_ = other.impl_; + return *this; + } + + iterator begin() const { return iterator(impl_->Begin()); } + iterator end() const { return iterator(impl_->End()); } + + private: + linked_ptr > impl_; +}; + +// Generates values from a range of two comparable values. Can be used to +// generate sequences of user-defined types that implement operator+() and +// operator<(). +// This class is used in the Range() function. +template +class RangeGenerator : public ParamGeneratorInterface { + public: + RangeGenerator(T begin, T end, IncrementT step) + : begin_(begin), end_(end), + step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} + virtual ~RangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, begin_, 0, step_); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, end_, end_index_, step_); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, T value, int index, + IncrementT step) + : base_(base), value_(value), index_(index), step_(step) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + value_ = value_ + step_; + index_++; + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const T* Current() const { return &value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const int other_index = + CheckedDowncastToActualType(&other)->index_; + return index_ == other_index; + } + + private: + Iterator(const Iterator& other) + : ParamIteratorInterface(), + base_(other.base_), value_(other.value_), index_(other.index_), + step_(other.step_) {} + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + T value_; + int index_; + const IncrementT step_; + }; // class RangeGenerator::Iterator + + static int CalculateEndIndex(const T& begin, + const T& end, + const IncrementT& step) { + int end_index = 0; + for (T i = begin; i < end; i = i + step) + end_index++; + return end_index; + } + + // No implementation - assignment is unsupported. + void operator=(const RangeGenerator& other); + + const T begin_; + const T end_; + const IncrementT step_; + // The index for the end() iterator. All the elements in the generated + // sequence are indexed (0-based) to aid iterator comparison. + const int end_index_; +}; // class RangeGenerator + + +// Generates values from a pair of STL-style iterators. Used in the +// ValuesIn() function. The elements are copied from the source range +// since the source can be located on the stack, and the generator +// is likely to persist beyond that stack frame. +template +class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { + public: + template + ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) + : container_(begin, end) {} + virtual ~ValuesInIteratorRangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, container_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, container_.end()); + } + + private: + typedef typename ::std::vector ContainerType; + + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + typename ContainerType::const_iterator iterator) + : base_(base), iterator_(iterator) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + ++iterator_; + value_.reset(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + // We need to use cached value referenced by iterator_ because *iterator_ + // can return a temporary object (and of type other then T), so just + // having "return &*iterator_;" doesn't work. + // value_ is updated here and not in Advance() because Advance() + // can advance iterator_ beyond the end of the range, and we cannot + // detect that fact. The client code, on the other hand, is + // responsible for not calling Current() on an out-of-range iterator. + virtual const T* Current() const { + if (value_.get() == NULL) + value_.reset(new T(*iterator_)); + return value_.get(); + } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + return iterator_ == + CheckedDowncastToActualType(&other)->iterator_; + } + + private: + Iterator(const Iterator& other) + // The explicit constructor call suppresses a false warning + // emitted by gcc when supplied with the -Wextra option. + : ParamIteratorInterface(), + base_(other.base_), + iterator_(other.iterator_) {} + + const ParamGeneratorInterface* const base_; + typename ContainerType::const_iterator iterator_; + // A cached value of *iterator_. We keep it here to allow access by + // pointer in the wrapping iterator's operator->(). + // value_ needs to be mutable to be accessed in Current(). + // Use of scoped_ptr helps manage cached value's lifetime, + // which is bound by the lifespan of the iterator itself. + mutable scoped_ptr value_; + }; // class ValuesInIteratorRangeGenerator::Iterator + + // No implementation - assignment is unsupported. + void operator=(const ValuesInIteratorRangeGenerator& other); + + const ContainerType container_; +}; // class ValuesInIteratorRangeGenerator + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Stores a parameter value and later creates tests parameterized with that +// value. +template +class ParameterizedTestFactory : public TestFactoryBase { + public: + typedef typename TestClass::ParamType ParamType; + explicit ParameterizedTestFactory(ParamType parameter) : + parameter_(parameter) {} + virtual Test* CreateTest() { + TestClass::SetParam(¶meter_); + return new TestClass(); + } + + private: + const ParamType parameter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactoryBase is a base class for meta-factories that create +// test factories for passing into MakeAndRegisterTestInfo function. +template +class TestMetaFactoryBase { + public: + virtual ~TestMetaFactoryBase() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactory creates test factories for passing into +// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives +// ownership of test factory pointer, same factory object cannot be passed +// into that method twice. But ParameterizedTestCaseInfo is going to call +// it for each Test/Parameter value combination. Thus it needs meta factory +// creator class. +template +class TestMetaFactory + : public TestMetaFactoryBase { + public: + typedef typename TestCase::ParamType ParamType; + + TestMetaFactory() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { + return new ParameterizedTestFactory(parameter); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfoBase is a generic interface +// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// accumulates test information provided by TEST_P macro invocations +// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and uses that information to register all resulting test instances +// in RegisterTests method. The ParameterizeTestCaseRegistry class holds +// a collection of pointers to the ParameterizedTestCaseInfo objects +// and calls RegisterTests() on each of them when asked. +class ParameterizedTestCaseInfoBase { + public: + virtual ~ParameterizedTestCaseInfoBase() {} + + // Base part of test case name for display purposes. + virtual const string& GetTestCaseName() const = 0; + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const = 0; + // UnitTest class invokes this method to register tests in this + // test case right before running them in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + virtual void RegisterTests() = 0; + + protected: + ParameterizedTestCaseInfoBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test case and generators +// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that +// test case. It registers tests with all values generated by all +// generators when asked. +template +class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { + public: + // ParamType and GeneratorCreationFunc are private types but are required + // for declarations of public methods AddTestPattern() and + // AddTestCaseInstantiation(). + typedef typename TestCase::ParamType ParamType; + // A function that returns an instance of appropriate generator type. + typedef ParamGenerator(GeneratorCreationFunc)(); + + explicit ParameterizedTestCaseInfo(const char* name) + : test_case_name_(name) {} + + // Test case base name for display purposes. + virtual const string& GetTestCaseName() const { return test_case_name_; } + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } + // TEST_P macro uses AddTestPattern() to record information + // about a single test in a LocalTestInfo structure. + // test_case_name is the base name of the test case (without invocation + // prefix). test_base_name is the name of an individual test without + // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is + // test case base name and DoBar is test base name. + void AddTestPattern(const char* test_case_name, + const char* test_base_name, + TestMetaFactoryBase* meta_factory) { + tests_.push_back(linked_ptr(new TestInfo(test_case_name, + test_base_name, + meta_factory))); + } + // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // about a generator. + int AddTestCaseInstantiation(const string& instantiation_name, + GeneratorCreationFunc* func, + const char* /* file */, + int /* line */) { + instantiations_.push_back(::std::make_pair(instantiation_name, func)); + return 0; // Return value used only to run this method in namespace scope. + } + // UnitTest class invokes this method to register tests in this test case + // test cases right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more then once. + virtual void RegisterTests() { + for (typename TestInfoContainer::iterator test_it = tests_.begin(); + test_it != tests_.end(); ++test_it) { + linked_ptr test_info = *test_it; + for (typename InstantiationContainer::iterator gen_it = + instantiations_.begin(); gen_it != instantiations_.end(); + ++gen_it) { + const string& instantiation_name = gen_it->first; + ParamGenerator generator((*gen_it->second)()); + + string test_case_name; + if ( !instantiation_name.empty() ) + test_case_name = instantiation_name + "/"; + test_case_name += test_info->test_case_base_name; + + int i = 0; + for (typename ParamGenerator::iterator param_it = + generator.begin(); + param_it != generator.end(); ++param_it, ++i) { + Message test_name_stream; + test_name_stream << test_info->test_base_name << "/" << i; + MakeAndRegisterTestInfo( + test_case_name.c_str(), + test_name_stream.GetString().c_str(), + NULL, // No type parameter. + PrintToString(*param_it).c_str(), + GetTestCaseTypeId(), + TestCase::SetUpTestCase, + TestCase::TearDownTestCase, + test_info->test_meta_factory->CreateTestFactory(*param_it)); + } // for param_it + } // for gen_it + } // for test_it + } // RegisterTests + + private: + // LocalTestInfo structure keeps information about a single test registered + // with TEST_P macro. + struct TestInfo { + TestInfo(const char* a_test_case_base_name, + const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory) : + test_case_base_name(a_test_case_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const string test_case_base_name; + const string test_base_name; + const scoped_ptr > test_meta_factory; + }; + typedef ::std::vector > TestInfoContainer; + // Keeps pairs of + // received from INSTANTIATE_TEST_CASE_P macros. + typedef ::std::vector > + InstantiationContainer; + + const string test_case_name_; + TestInfoContainer tests_; + InstantiationContainer instantiations_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); +}; // class ParameterizedTestCaseInfo + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase +// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P +// macros use it to locate their corresponding ParameterizedTestCaseInfo +// descriptors. +class ParameterizedTestCaseRegistry { + public: + ParameterizedTestCaseRegistry() {} + ~ParameterizedTestCaseRegistry() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + delete *it; + } + } + + // Looks up or creates and returns a structure containing information about + // tests and instantiations of a particular test case. + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, + const char* file, + int line) { + ParameterizedTestCaseInfo* typed_test_info = NULL; + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + if ((*it)->GetTestCaseName() == test_case_name) { + if ((*it)->GetTestCaseTypeId() != GetTypeId()) { + // Complain about incorrect usage of Google Test facilities + // and terminate the program since we cannot guaranty correct + // test case setup and tear-down in this case. + ReportInvalidTestCaseType(test_case_name, file, line); + posix::Abort(); + } else { + // At this point we are sure that the object we found is of the same + // type we are looking for, so we downcast it to that type + // without further checks. + typed_test_info = CheckedDowncastToActualType< + ParameterizedTestCaseInfo >(*it); + } + break; + } + } + if (typed_test_info == NULL) { + typed_test_info = new ParameterizedTestCaseInfo(test_case_name); + test_case_infos_.push_back(typed_test_info); + } + return typed_test_info; + } + void RegisterTests() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + (*it)->RegisterTests(); + } + } + + private: + typedef ::std::vector TestCaseInfoContainer; + + TestCaseInfoContainer test_case_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +// This file was GENERATED by command: +// pump.py gtest-param-util-generated.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently Google Test supports at most 50 arguments in Values, +// and at most 10 arguments in Combine. Please contact +// googletestframework@googlegroups.com if you need more. +// Please note that the number of arguments to Combine is limited +// by the maximum arity of the implementation of tr1::tuple which is +// currently set at 10. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end); + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]); + +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { + +// Used in the Values() function to provide polymorphic capabilities. +template +class ValueArray1 { + public: + explicit ValueArray1(T1 v1) : v1_(v1) {} + + template + operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray1& other); + + const T1 v1_; +}; + +template +class ValueArray2 { + public: + ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray2& other); + + const T1 v1_; + const T2 v2_; +}; + +template +class ValueArray3 { + public: + ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray3& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; +}; + +template +class ValueArray4 { + public: + ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray4& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; +}; + +template +class ValueArray5 { + public: + ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray5& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; +}; + +template +class ValueArray6 { + public: + ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray6& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; +}; + +template +class ValueArray7 { + public: + ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray7& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; +}; + +template +class ValueArray8 { + public: + ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray8& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; +}; + +template +class ValueArray9 { + public: + ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray9& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; +}; + +template +class ValueArray10 { + public: + ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray10& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; +}; + +template +class ValueArray11 { + public: + ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray11& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; +}; + +template +class ValueArray12 { + public: + ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray12& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; +}; + +template +class ValueArray13 { + public: + ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray13& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; +}; + +template +class ValueArray14 { + public: + ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray14& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; +}; + +template +class ValueArray15 { + public: + ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray15& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; +}; + +template +class ValueArray16 { + public: + ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray16& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; +}; + +template +class ValueArray17 { + public: + ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray17& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; +}; + +template +class ValueArray18 { + public: + ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray18& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; +}; + +template +class ValueArray19 { + public: + ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray19& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; +}; + +template +class ValueArray20 { + public: + ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray20& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; +}; + +template +class ValueArray21 { + public: + ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray21& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; +}; + +template +class ValueArray22 { + public: + ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray22& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; +}; + +template +class ValueArray23 { + public: + ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray23& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; +}; + +template +class ValueArray24 { + public: + ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray24& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; +}; + +template +class ValueArray25 { + public: + ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray25& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; +}; + +template +class ValueArray26 { + public: + ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray26& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; +}; + +template +class ValueArray27 { + public: + ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray27& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; +}; + +template +class ValueArray28 { + public: + ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray28& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; +}; + +template +class ValueArray29 { + public: + ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray29& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; +}; + +template +class ValueArray30 { + public: + ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray30& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; +}; + +template +class ValueArray31 { + public: + ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray31& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; +}; + +template +class ValueArray32 { + public: + ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray32& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; +}; + +template +class ValueArray33 { + public: + ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray33& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; +}; + +template +class ValueArray34 { + public: + ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray34& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; +}; + +template +class ValueArray35 { + public: + ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray35& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; +}; + +template +class ValueArray36 { + public: + ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray36& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; +}; + +template +class ValueArray37 { + public: + ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray37& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; +}; + +template +class ValueArray38 { + public: + ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray38& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; +}; + +template +class ValueArray39 { + public: + ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray39& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; +}; + +template +class ValueArray40 { + public: + ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray40& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; +}; + +template +class ValueArray41 { + public: + ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray41& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; +}; + +template +class ValueArray42 { + public: + ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray42& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; +}; + +template +class ValueArray43 { + public: + ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), + v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray43& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; +}; + +template +class ValueArray44 { + public: + ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), + v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), + v43_(v43), v44_(v44) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray44& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; +}; + +template +class ValueArray45 { + public: + ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), + v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray45& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; +}; + +template +class ValueArray46 { + public: + ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_), static_cast(v46_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray46& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; +}; + +template +class ValueArray47 { + public: + ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), + v47_(v47) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_), static_cast(v46_), static_cast(v47_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray47& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; +}; + +template +class ValueArray48 { + public: + ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), + v46_(v46), v47_(v47), v48_(v48) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_), static_cast(v46_), static_cast(v47_), + static_cast(v48_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray48& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; +}; + +template +class ValueArray49 { + public: + ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, + T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_), static_cast(v46_), static_cast(v47_), + static_cast(v48_), static_cast(v49_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray49& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; +}; + +template +class ValueArray50 { + public: + ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, + T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_), static_cast(v46_), static_cast(v47_), + static_cast(v48_), static_cast(v49_), static_cast(v50_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray50& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; + const T50 v50_; +}; + +# if GTEST_HAS_COMBINE +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Generates values from the Cartesian product of values produced +// by the argument generators. +// +template +class CartesianProductGenerator2 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator2(const ParamGenerator& g1, + const ParamGenerator& g2) + : g1_(g1), g2_(g2) {} + virtual ~CartesianProductGenerator2() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current2_; + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + ParamType current_value_; + }; // class CartesianProductGenerator2::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator2& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; +}; // class CartesianProductGenerator2 + + +template +class CartesianProductGenerator3 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator3(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + virtual ~CartesianProductGenerator3() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current3_; + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + ParamType current_value_; + }; // class CartesianProductGenerator3::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator3& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; +}; // class CartesianProductGenerator3 + + +template +class CartesianProductGenerator4 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator4(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + virtual ~CartesianProductGenerator4() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current4_; + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + ParamType current_value_; + }; // class CartesianProductGenerator4::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator4& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; +}; // class CartesianProductGenerator4 + + +template +class CartesianProductGenerator5 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator5(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + virtual ~CartesianProductGenerator5() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current5_; + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + ParamType current_value_; + }; // class CartesianProductGenerator5::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator5& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; +}; // class CartesianProductGenerator5 + + +template +class CartesianProductGenerator6 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator6(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + virtual ~CartesianProductGenerator6() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current6_; + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + ParamType current_value_; + }; // class CartesianProductGenerator6::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator6& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; +}; // class CartesianProductGenerator6 + + +template +class CartesianProductGenerator7 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator7(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + virtual ~CartesianProductGenerator7() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current7_; + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + ParamType current_value_; + }; // class CartesianProductGenerator7::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator7& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; +}; // class CartesianProductGenerator7 + + +template +class CartesianProductGenerator8 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator8(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + virtual ~CartesianProductGenerator8() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current8_; + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + ParamType current_value_; + }; // class CartesianProductGenerator8::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator8& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; +}; // class CartesianProductGenerator8 + + +template +class CartesianProductGenerator9 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator9(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + virtual ~CartesianProductGenerator9() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current9_; + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + ParamType current_value_; + }; // class CartesianProductGenerator9::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator9& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; +}; // class CartesianProductGenerator9 + + +template +class CartesianProductGenerator10 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator10(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9, + const ParamGenerator& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + virtual ~CartesianProductGenerator10() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end(), g10_, g10_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9, + const ParamGenerator& g10, + const typename ParamGenerator::iterator& current10) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9), + begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current10_; + if (current10_ == end10_) { + current10_ = begin10_; + ++current9_; + } + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_ && + current10_ == typed_other->current10_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_), + begin10_(other.begin10_), + end10_(other.end10_), + current10_(other.current10_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_, *current10_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_ || + current10_ == end10_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + const typename ParamGenerator::iterator begin10_; + const typename ParamGenerator::iterator end10_; + typename ParamGenerator::iterator current10_; + ParamType current_value_; + }; // class CartesianProductGenerator10::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator10& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; + const ParamGenerator g10_; +}; // class CartesianProductGenerator10 + + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Helper classes providing Combine() with polymorphic features. They allow +// casting CartesianProductGeneratorN to ParamGenerator if T is +// convertible to U. +// +template +class CartesianProductHolder2 { + public: +CartesianProductHolder2(const Generator1& g1, const Generator2& g2) + : g1_(g1), g2_(g2) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator2( + static_cast >(g1_), + static_cast >(g2_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder2& other); + + const Generator1 g1_; + const Generator2 g2_; +}; // class CartesianProductHolder2 + +template +class CartesianProductHolder3 { + public: +CartesianProductHolder3(const Generator1& g1, const Generator2& g2, + const Generator3& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator3( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder3& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; +}; // class CartesianProductHolder3 + +template +class CartesianProductHolder4 { + public: +CartesianProductHolder4(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator4( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder4& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; +}; // class CartesianProductHolder4 + +template +class CartesianProductHolder5 { + public: +CartesianProductHolder5(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator5( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder5& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; +}; // class CartesianProductHolder5 + +template +class CartesianProductHolder6 { + public: +CartesianProductHolder6(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator6( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder6& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; +}; // class CartesianProductHolder6 + +template +class CartesianProductHolder7 { + public: +CartesianProductHolder7(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator7( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder7& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; +}; // class CartesianProductHolder7 + +template +class CartesianProductHolder8 { + public: +CartesianProductHolder8(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator8( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder8& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; +}; // class CartesianProductHolder8 + +template +class CartesianProductHolder9 { + public: +CartesianProductHolder9(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator9( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder9& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; +}; // class CartesianProductHolder9 + +template +class CartesianProductHolder10 { + public: +CartesianProductHolder10(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9, const Generator10& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator10( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_), + static_cast >(g10_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder10& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; + const Generator10 g10_; +}; // class CartesianProductHolder10 + +# endif // GTEST_HAS_COMBINE + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test case is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test case FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test case StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// +// This instantiates tests from test case StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_CASE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_CASE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end) { + typedef typename ::testing::internal::IteratorTraits + ::value_type ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test case BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// +// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// Currently, Values() supports from 1 to 50 parameters. +// +template +internal::ValueArray1 Values(T1 v1) { + return internal::ValueArray1(v1); +} + +template +internal::ValueArray2 Values(T1 v1, T2 v2) { + return internal::ValueArray2(v1, v2); +} + +template +internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { + return internal::ValueArray3(v1, v2, v3); +} + +template +internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { + return internal::ValueArray4(v1, v2, v3, v4); +} + +template +internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5) { + return internal::ValueArray5(v1, v2, v3, v4, v5); +} + +template +internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6) { + return internal::ValueArray6(v1, v2, v3, v4, v5, v6); +} + +template +internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7) { + return internal::ValueArray7(v1, v2, v3, v4, v5, + v6, v7); +} + +template +internal::ValueArray8 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { + return internal::ValueArray8(v1, v2, v3, v4, + v5, v6, v7, v8); +} + +template +internal::ValueArray9 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { + return internal::ValueArray9(v1, v2, v3, + v4, v5, v6, v7, v8, v9); +} + +template +internal::ValueArray10 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { + return internal::ValueArray10(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10); +} + +template +internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) { + return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); +} + +template +internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) { + return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); +} + +template +internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) { + return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); +} + +template +internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { + return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14); +} + +template +internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { + return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15); +} + +template +internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16) { + return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16); +} + +template +internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17) { + return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17); +} + +template +internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18) { + return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18); +} + +template +internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { + return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); +} + +template +internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { + return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); +} + +template +internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { + return internal::ValueArray21(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); +} + +template +internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22) { + return internal::ValueArray22(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22); +} + +template +internal::ValueArray23 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23) { + return internal::ValueArray23(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23); +} + +template +internal::ValueArray24 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24) { + return internal::ValueArray24(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24); +} + +template +internal::ValueArray25 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { + return internal::ValueArray25(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25); +} + +template +internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) { + return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); +} + +template +internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) { + return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); +} + +template +internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) { + return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28); +} + +template +internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) { + return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29); +} + +template +internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { + return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30); +} + +template +internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { + return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31); +} + +template +internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32) { + return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32); +} + +template +internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33) { + return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); +} + +template +internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34) { + return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); +} + +template +internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { + return internal::ValueArray35(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); +} + +template +internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { + return internal::ValueArray36(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36); +} + +template +internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37) { + return internal::ValueArray37(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37); +} + +template +internal::ValueArray38 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38) { + return internal::ValueArray38(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, + v33, v34, v35, v36, v37, v38); +} + +template +internal::ValueArray39 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38, T39 v39) { + return internal::ValueArray39(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, + v32, v33, v34, v35, v36, v37, v38, v39); +} + +template +internal::ValueArray40 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, + T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, + T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { + return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, + v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); +} + +template +internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { + return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, + v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); +} + +template +internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) { + return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, + v42); +} + +template +internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) { + return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, + v41, v42, v43); +} + +template +internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) { + return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, + v40, v41, v42, v43, v44); +} + +template +internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { + return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, + v39, v40, v41, v42, v43, v44, v45); +} + +template +internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { + return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46); +} + +template +internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { + return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); +} + +template +internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, + T48 v48) { + return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, + v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); +} + +template +internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, + T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, + T47 v47, T48 v48, T49 v49) { + return internal::ValueArray49(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, + v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); +} + +template +internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, + T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, + T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { + return internal::ValueArray50(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, + v48, v49, v50); +} + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test case FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +# if GTEST_HAS_COMBINE +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Combine can have up to 10 arguments. This number is currently limited +// by the maximum number of elements in the tuple implementation used by Google +// Test. +// +// Example: +// +// This will instantiate tests in test case AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder2 Combine( + const Generator1& g1, const Generator2& g2) { + return internal::CartesianProductHolder2( + g1, g2); +} + +template +internal::CartesianProductHolder3 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3) { + return internal::CartesianProductHolder3( + g1, g2, g3); +} + +template +internal::CartesianProductHolder4 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4) { + return internal::CartesianProductHolder4( + g1, g2, g3, g4); +} + +template +internal::CartesianProductHolder5 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5) { + return internal::CartesianProductHolder5( + g1, g2, g3, g4, g5); +} + +template +internal::CartesianProductHolder6 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6) { + return internal::CartesianProductHolder6( + g1, g2, g3, g4, g5, g6); +} + +template +internal::CartesianProductHolder7 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7) { + return internal::CartesianProductHolder7( + g1, g2, g3, g4, g5, g6, g7); +} + +template +internal::CartesianProductHolder8 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8) { + return internal::CartesianProductHolder8( + g1, g2, g3, g4, g5, g6, g7, g8); +} + +template +internal::CartesianProductHolder9 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9) { + return internal::CartesianProductHolder9( + g1, g2, g3, g4, g5, g6, g7, g8, g9); +} + +template +internal::CartesianProductHolder10 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9, + const Generator10& g10) { + return internal::CartesianProductHolder10( + g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); +} +# endif // GTEST_HAS_COMBINE + + + +# define TEST_P(test_case_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + : public test_case_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ + virtual void TestBody(); \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ + #test_case_name, \ + #test_name, \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + return 0; \ + } \ + static int gtest_registering_dummy_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_case_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ + ::testing::internal::ParamGenerator \ + gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + int gtest_##prefix##test_case_name##_dummy_ = \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + __FILE__, __LINE__) + +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Google C++ Testing Framework definitions useful in production code. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ + +// When you need to test the private or protected members of a class, +// use the FRIEND_TEST macro to declare your tests as friends of the +// class. For example: +// +// class MyClass { +// private: +// void MyMethod(); +// FRIEND_TEST(MyClassTest, MyMethod); +// }; +// +// class MyClassTest : public testing::Test { +// // ... +// }; +// +// TEST_F(MyClassTest, MyMethod) { +// // Can call MyClass::MyMethod() here. +// } + +#define FRIEND_TEST(test_case_name, test_name)\ +friend class test_case_name##_##test_name##_Test + +#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ + +#include +#include + +namespace testing { + +// A copyable object representing the result of a test part (i.e. an +// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). +// +// Don't inherit from TestPartResult as its destructor is not virtual. +class GTEST_API_ TestPartResult { + public: + // The possible outcomes of a test part (i.e. an assertion or an + // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). + enum Type { + kSuccess, // Succeeded. + kNonFatalFailure, // Failed but the test can continue. + kFatalFailure // Failed and the test should be terminated. + }; + + // C'tor. TestPartResult does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestPartResult object. + TestPartResult(Type a_type, + const char* a_file_name, + int a_line_number, + const char* a_message) + : type_(a_type), + file_name_(a_file_name == NULL ? "" : a_file_name), + line_number_(a_line_number), + summary_(ExtractSummary(a_message)), + message_(a_message) { + } + + // Gets the outcome of the test part. + Type type() const { return type_; } + + // Gets the name of the source file where the test part took place, or + // NULL if it's unknown. + const char* file_name() const { + return file_name_.empty() ? NULL : file_name_.c_str(); + } + + // Gets the line in the source file where the test part took place, + // or -1 if it's unknown. + int line_number() const { return line_number_; } + + // Gets the summary of the failure message. + const char* summary() const { return summary_.c_str(); } + + // Gets the message associated with the test part. + const char* message() const { return message_.c_str(); } + + // Returns true iff the test part passed. + bool passed() const { return type_ == kSuccess; } + + // Returns true iff the test part failed. + bool failed() const { return type_ != kSuccess; } + + // Returns true iff the test part non-fatally failed. + bool nonfatally_failed() const { return type_ == kNonFatalFailure; } + + // Returns true iff the test part fatally failed. + bool fatally_failed() const { return type_ == kFatalFailure; } + + private: + Type type_; + + // Gets the summary of the failure message by omitting the stack + // trace in it. + static std::string ExtractSummary(const char* message); + + // The name of the source file where the test part took place, or + // "" if the source file is unknown. + std::string file_name_; + // The line in the source file where the test part took place, or -1 + // if the line number is unknown. + int line_number_; + std::string summary_; // The test failure summary. + std::string message_; // The test failure message. +}; + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result); + +// An array of TestPartResult objects. +// +// Don't inherit from TestPartResultArray as its destructor is not +// virtual. +class GTEST_API_ TestPartResultArray { + public: + TestPartResultArray() {} + + // Appends the given TestPartResult to the array. + void Append(const TestPartResult& result); + + // Returns the TestPartResult at the given index (0-based). + const TestPartResult& GetTestPartResult(int index) const; + + // Returns the number of TestPartResult objects in the array. + int size() const; + + private: + std::vector array_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); +}; + +// This interface knows how to report a test part result. +class TestPartResultReporterInterface { + public: + virtual ~TestPartResultReporterInterface() {} + + virtual void ReportTestPartResult(const TestPartResult& result) = 0; +}; + +namespace internal { + +// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a +// statement generates new fatal failures. To do so it registers itself as the +// current test part result reporter. Besides checking if fatal failures were +// reported, it only delegates the reporting to the former result reporter. +// The original result reporter is restored in the destructor. +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +class GTEST_API_ HasNewFatalFailureHelper + : public TestPartResultReporterInterface { + public: + HasNewFatalFailureHelper(); + virtual ~HasNewFatalFailureHelper(); + virtual void ReportTestPartResult(const TestPartResult& result); + bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: + bool has_new_fatal_failure_; + TestPartResultReporterInterface* original_reporter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); +}; + +} // namespace internal + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// This header implements typed tests and type-parameterized tests. + +// Typed (aka type-driven) tests repeat the same test for types in a +// list. You must know which types you want to test with when writing +// typed tests. Here's how you do it: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + public: + ... + typedef std::list List; + static T shared_; + T value_; +}; + +// Next, associate a list of types with the test case, which will be +// repeated for each type in the list. The typedef is necessary for +// the macro to parse correctly. +typedef testing::Types MyTypes; +TYPED_TEST_CASE(FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// TYPED_TEST_CASE(FooTest, int); + +// Then, use TYPED_TEST() instead of TEST_F() to define as many typed +// tests for this test case as you want. +TYPED_TEST(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + // Since we are inside a derived class template, C++ requires use to + // visit the members of FooTest via 'this'. + TypeParam n = this->value_; + + // To visit static members of the fixture, add the TestFixture:: + // prefix. + n += TestFixture::shared_; + + // To refer to typedefs in the fixture, add the "typename + // TestFixture::" prefix. + typename TestFixture::List values; + values.push_back(n); + ... +} + +TYPED_TEST(FooTest, HasPropertyA) { ... } + +#endif // 0 + +// Type-parameterized tests are abstract test patterns parameterized +// by a type. Compared with typed tests, type-parameterized tests +// allow you to define the test pattern without knowing what the type +// parameters are. The defined pattern can be instantiated with +// different types any number of times, in any number of translation +// units. +// +// If you are designing an interface or concept, you can define a +// suite of type-parameterized tests to verify properties that any +// valid implementation of the interface/concept should have. Then, +// each implementation can easily instantiate the test suite to verify +// that it conforms to the requirements, without having to write +// similar tests repeatedly. Here's an example: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + ... +}; + +// Next, declare that you will define a type-parameterized test case +// (the _P suffix is for "parameterized" or "pattern", whichever you +// prefer): +TYPED_TEST_CASE_P(FooTest); + +// Then, use TYPED_TEST_P() to define as many type-parameterized tests +// for this type-parameterized test case as you want. +TYPED_TEST_P(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + TypeParam n = 0; + ... +} + +TYPED_TEST_P(FooTest, HasPropertyA) { ... } + +// Now the tricky part: you need to register all test patterns before +// you can instantiate them. The first argument of the macro is the +// test case name; the rest are the names of the tests in this test +// case. +REGISTER_TYPED_TEST_CASE_P(FooTest, + DoesBlah, HasPropertyA); + +// Finally, you are free to instantiate the pattern with the types you +// want. If you put the above code in a header file, you can #include +// it in multiple C++ source files and instantiate it multiple times. +// +// To distinguish different instances of the pattern, the first +// argument to the INSTANTIATE_* macro is a prefix that will be added +// to the actual test case name. Remember to pick unique prefixes for +// different instances. +typedef testing::Types MyTypes; +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); + +#endif // 0 + + +// Implements typed tests. + +#if GTEST_HAS_TYPED_TEST + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the typedef for the type parameters of the +// given test case. +# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +# define TYPED_TEST_CASE(CaseName, Types) \ + typedef ::testing::internal::TypeList< Types >::type \ + GTEST_TYPE_PARAMS_(CaseName) + +# define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel< \ + GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ + GTEST_TYPE_PARAMS_(CaseName)>::Register(\ + "", #CaseName, #TestName, 0); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() + +#endif // GTEST_HAS_TYPED_TEST + +// Implements type-parameterized tests. + +#if GTEST_HAS_TYPED_TEST_P + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the namespace name that the type-parameterized tests for +// the given type-parameterized test case are defined in. The exact +// name of the namespace is subject to change without notice. +# define GTEST_CASE_NAMESPACE_(TestCaseName) \ + gtest_case_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the variable used to remember the names of +// the defined tests in the given test case. +# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ + gtest_typed_test_case_p_state_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. +// +// Expands to the name of the variable used to remember the names of +// the registered tests in the given test case. +# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ + gtest_registered_test_names_##TestCaseName##_ + +// The variables defined in the type-parameterized test macros are +// static as typically these macros are used in a .h file that can be +// #included in multiple translation units linked together. +# define TYPED_TEST_CASE_P(CaseName) \ + static ::testing::internal::TypedTestCasePState \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) + +# define TYPED_TEST_P(CaseName, TestName) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + template \ + class TestName : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ + __FILE__, __LINE__, #CaseName, #TestName); \ + } \ + template \ + void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() + +# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ + __FILE__, __LINE__, #__VA_ARGS__) + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ + bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestCase::type>::Register(\ + #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// Depending on the platform, different string classes are available. +// On Linux, in addition to ::std::string, Google also makes use of +// class ::string, which has the same interface as ::std::string, but +// has a different implementation. +// +// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that +// ::string is available AND is a distinct type to ::std::string, or +// define it to 0 to indicate otherwise. +// +// If the user's ::std::string and ::string are the same class due to +// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. +// +// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined +// heuristically. + +namespace testing { + +// Declares the flags. + +// This flag temporary enables the disabled tests. +GTEST_DECLARE_bool_(also_run_disabled_tests); + +// This flag brings the debugger on an assertion failure. +GTEST_DECLARE_bool_(break_on_failure); + +// This flag controls whether Google Test catches all test-thrown exceptions +// and logs them as failures. +GTEST_DECLARE_bool_(catch_exceptions); + +// This flag enables using colors in terminal output. Available values are +// "yes" to enable colors, "no" (disable colors), or "auto" (the default) +// to let Google Test decide. +GTEST_DECLARE_string_(color); + +// This flag sets up the filter to select by name using a glob pattern +// the tests to run. If the filter is not given all tests are executed. +GTEST_DECLARE_string_(filter); + +// This flag causes the Google Test to list tests. None of the tests listed +// are actually run if the flag is provided. +GTEST_DECLARE_bool_(list_tests); + +// This flag controls whether Google Test emits a detailed XML report to a file +// in addition to its normal textual output. +GTEST_DECLARE_string_(output); + +// This flags control whether Google Test prints the elapsed time for each +// test. +GTEST_DECLARE_bool_(print_time); + +// This flag specifies the random number seed. +GTEST_DECLARE_int32_(random_seed); + +// This flag sets how many times the tests are repeated. The default value +// is 1. If the value is -1 the tests are repeating forever. +GTEST_DECLARE_int32_(repeat); + +// This flag controls whether Google Test includes Google Test internal +// stack frames in failure stack traces. +GTEST_DECLARE_bool_(show_internal_stack_frames); + +// When this flag is specified, tests' order is randomized on every iteration. +GTEST_DECLARE_bool_(shuffle); + +// This flag specifies the maximum number of stack frames to be +// printed in a failure message. +GTEST_DECLARE_int32_(stack_trace_depth); + +// When this flag is specified, a failed assertion will throw an +// exception if exceptions are enabled, or exit the program with a +// non-zero code otherwise. +GTEST_DECLARE_bool_(throw_on_failure); + +// When this flag is set with a "host:port" string, on supported +// platforms test results are streamed to the specified port on +// the specified host machine. +GTEST_DECLARE_string_(stream_result_to); + +// The upper limit for valid stack trace depths. +const int kMaxStackTraceDepth = 100; + +namespace internal { + +class AssertHelper; +class DefaultGlobalTestPartResultReporter; +class ExecDeathTest; +class NoExecDeathTest; +class FinalSuccessChecker; +class GTestFlagSaver; +class StreamingListenerTest; +class TestResultAccessor; +class TestEventListenersAccessor; +class TestEventRepeater; +class UnitTestRecordPropertyTestHelper; +class WindowsDeathTest; +class UnitTestImpl* GetUnitTestImpl(); +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const std::string& message); + +} // namespace internal + +// The friend relationship of some of these classes is cyclic. +// If we don't forward declare them the compiler might confuse the classes +// in friendship clauses with same named classes on the scope. +class Test; +class TestCase; +class TestInfo; +class UnitTest; + +// A class for indicating whether an assertion was successful. When +// the assertion wasn't successful, the AssertionResult object +// remembers a non-empty message that describes how it failed. +// +// To create an instance of this class, use one of the factory functions +// (AssertionSuccess() and AssertionFailure()). +// +// This class is useful for two purposes: +// 1. Defining predicate functions to be used with Boolean test assertions +// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts +// 2. Defining predicate-format functions to be +// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). +// +// For example, if you define IsEven predicate: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) +// will print the message +// +// Value of: IsEven(Fib(5)) +// Actual: false (5 is odd) +// Expected: true +// +// instead of a more opaque +// +// Value of: IsEven(Fib(5)) +// Actual: false +// Expected: true +// +// in case IsEven is a simple Boolean predicate. +// +// If you expect your predicate to be reused and want to support informative +// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up +// about half as often as positive ones in our tests), supply messages for +// both success and failure cases: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess() << n << " is even"; +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print +// +// Value of: IsEven(Fib(6)) +// Actual: true (8 is even) +// Expected: false +// +// NB: Predicates that support negative Boolean assertions have reduced +// performance in positive ones so be careful not to use them in tests +// that have lots (tens of thousands) of positive Boolean assertions. +// +// To use this class with EXPECT_PRED_FORMAT assertions such as: +// +// // Verifies that Foo() returns an even number. +// EXPECT_PRED_FORMAT1(IsEven, Foo()); +// +// you need to define: +// +// testing::AssertionResult IsEven(const char* expr, int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() +// << "Expected: " << expr << " is even\n Actual: it's " << n; +// } +// +// If Foo() returns 5, you will see the following message: +// +// Expected: Foo() is even +// Actual: it's 5 +// +class GTEST_API_ AssertionResult { + public: + // Copy constructor. + // Used in EXPECT_TRUE/FALSE(assertion_result). + AssertionResult(const AssertionResult& other); + // Used in the EXPECT_TRUE/FALSE(bool_expression). + explicit AssertionResult(bool success) : success_(success) {} + + // Returns true iff the assertion succeeded. + operator bool() const { return success_; } // NOLINT + + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. + AssertionResult operator!() const; + + // Returns the text streamed into this AssertionResult. Test assertions + // use it when they fail (i.e., the predicate's outcome doesn't match the + // assertion's expectation). When nothing has been streamed into the + // object, returns an empty string. + const char* message() const { + return message_.get() != NULL ? message_->c_str() : ""; + } + // TODO(vladl@google.com): Remove this after making sure no clients use it. + // Deprecated; please use message() instead. + const char* failure_message() const { return message(); } + + // Streams a custom failure message into this object. + template AssertionResult& operator<<(const T& value) { + AppendMessage(Message() << value); + return *this; + } + + // Allows streaming basic output manipulators such as endl or flush into + // this object. + AssertionResult& operator<<( + ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { + AppendMessage(Message() << basic_manipulator); + return *this; + } + + private: + // Appends the contents of message to message_. + void AppendMessage(const Message& a_message) { + if (message_.get() == NULL) + message_.reset(new ::std::string); + message_->append(a_message.GetString().c_str()); + } + + // Stores result of the assertion predicate. + bool success_; + // Stores the message describing the condition in case the expectation + // construct is not satisfied with the predicate's outcome. + // Referenced via a pointer to avoid taking too much stack frame space + // with test assertions. + internal::scoped_ptr< ::std::string> message_; + + GTEST_DISALLOW_ASSIGN_(AssertionResult); +}; + +// Makes a successful assertion result. +GTEST_API_ AssertionResult AssertionSuccess(); + +// Makes a failed assertion result. +GTEST_API_ AssertionResult AssertionFailure(); + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << msg. +GTEST_API_ AssertionResult AssertionFailure(const Message& msg); + +// The abstract class that all tests inherit from. +// +// In Google Test, a unit test program contains one or many TestCases, and +// each TestCase contains one or many Tests. +// +// When you define a test using the TEST macro, you don't need to +// explicitly derive from Test - the TEST macro automatically does +// this for you. +// +// The only time you derive from Test is when defining a test fixture +// to be used a TEST_F. For example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { ... } +// virtual void TearDown() { ... } +// ... +// }; +// +// TEST_F(FooTest, Bar) { ... } +// TEST_F(FooTest, Baz) { ... } +// +// Test is not copyable. +class GTEST_API_ Test { + public: + friend class TestInfo; + + // Defines types for pointers to functions that set up and tear down + // a test case. + typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; + typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; + + // The d'tor is virtual as we intend to inherit from Test. + virtual ~Test(); + + // Sets up the stuff shared by all tests in this test case. + // + // Google Test will call Foo::SetUpTestCase() before running the first + // test in test case Foo. Hence a sub-class can define its own + // SetUpTestCase() method to shadow the one defined in the super + // class. + static void SetUpTestCase() {} + + // Tears down the stuff shared by all tests in this test case. + // + // Google Test will call Foo::TearDownTestCase() after running the last + // test in test case Foo. Hence a sub-class can define its own + // TearDownTestCase() method to shadow the one defined in the super + // class. + static void TearDownTestCase() {} + + // Returns true iff the current test has a fatal failure. + static bool HasFatalFailure(); + + // Returns true iff the current test has a non-fatal failure. + static bool HasNonfatalFailure(); + + // Returns true iff the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } + + // Logs a property for the current test, test case, or for the entire + // invocation of the test program when used outside of the context of a + // test case. Only the last value for a given key is remembered. These + // are public static so they can be called from utility functions that are + // not members of the test fixture. Calls to RecordProperty made during + // lifespan of the test (from the moment its constructor starts to the + // moment its destructor finishes) will be output in XML as attributes of + // the element. Properties recorded from fixture's + // SetUpTestCase or TearDownTestCase are logged as attributes of the + // corresponding element. Calls to RecordProperty made in the + // global context (before or after invocation of RUN_ALL_TESTS and from + // SetUp/TearDown method of Environment objects registered with Google + // Test) will be output as attributes of the element. + static void RecordProperty(const std::string& key, const std::string& value); + static void RecordProperty(const std::string& key, int value); + + protected: + // Creates a Test object. + Test(); + + // Sets up the test fixture. + virtual void SetUp(); + + // Tears down the test fixture. + virtual void TearDown(); + + private: + // Returns true iff the current test has the same fixture class as + // the first test in the current test case. + static bool HasSameFixtureClass(); + + // Runs the test after the test fixture has been set up. + // + // A sub-class must implement this to define the test logic. + // + // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. + // Instead, use the TEST or TEST_F macro. + virtual void TestBody() = 0; + + // Sets up, executes, and tears down the test. + void Run(); + + // Deletes self. We deliberately pick an unusual name for this + // internal method to avoid clashing with names used in user TESTs. + void DeleteSelf_() { delete this; } + + // Uses a GTestFlagSaver to save and restore all Google Test flags. + const internal::GTestFlagSaver* const gtest_flag_saver_; + + // Often a user mis-spells SetUp() as Setup() and spends a long time + // wondering why it is never called by Google Test. The declaration of + // the following method is solely for catching such an error at + // compile time: + // + // - The return type is deliberately chosen to be not void, so it + // will be a conflict if a user declares void Setup() in his test + // fixture. + // + // - This method is private, so it will be another compiler error + // if a user calls it from his test fixture. + // + // DO NOT OVERRIDE THIS FUNCTION. + // + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + + // We disallow copying Tests. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); +}; + +typedef internal::TimeInMillis TimeInMillis; + +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const std::string& a_key, const std::string& a_value) : + key_(a_key), value_(a_value) { + } + + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } + + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } + + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const std::string& new_value) { + value_ = new_value; + } + + private: + // The key supplied by the user. + std::string key_; + // The value supplied by the user. + std::string value_; +}; + +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class GTEST_API_ TestResult { + public: + // Creates an empty TestResult. + TestResult(); + + // D'tor. Do not inherit from TestResult. + ~TestResult(); + + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; + + // Returns the number of the test properties. + int test_property_count() const; + + // Returns true iff the test passed (i.e. no test part failed). + bool Passed() const { return !Failed(); } + + // Returns true iff the test failed. + bool Failed() const; + + // Returns true iff the test fatally failed. + bool HasFatalFailure() const; + + // Returns true iff the test has a non-fatal failure. + bool HasNonfatalFailure() const; + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test part result among all the results. i can range + // from 0 to test_property_count() - 1. If i is not in that range, aborts + // the program. + const TestPartResult& GetTestPartResult(int i) const; + + // Returns the i-th test property. i can range from 0 to + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; + + private: + friend class TestInfo; + friend class TestCase; + friend class UnitTest; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::ExecDeathTest; + friend class internal::TestResultAccessor; + friend class internal::UnitTestImpl; + friend class internal::WindowsDeathTest; + + // Gets the vector of TestPartResults. + const std::vector& test_part_results() const { + return test_part_results_; + } + + // Gets the vector of TestProperties. + const std::vector& test_properties() const { + return test_properties_; + } + + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } + + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. xml_element specifies the element for which the property is being + // recorded and is used for validation. + void RecordProperty(const std::string& xml_element, + const TestProperty& test_property); + + // Adds a failure if the key is a reserved attribute of Google Test + // testcase tags. Returns true if the property is valid. + // TODO(russr): Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const std::string& xml_element, + const TestProperty& test_property); + + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); + + // Returns the death test count. + int death_test_count() const { return death_test_count_; } + + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } + + // Clears the test part results. + void ClearTestPartResults(); + + // Clears the object. + void Clear(); + + // Protects mutable state of the property vector and of owned + // properties, whose values may be updated. + internal::Mutex test_properites_mutex_; + + // The vector of TestPartResults + std::vector test_part_results_; + // The vector of TestProperties + std::vector test_properties_; + // Running count of death tests. + int death_test_count_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); +}; // class TestResult + +// A TestInfo object stores the following information about a test: +// +// Test case name +// Test name +// Whether the test should be run +// A function pointer that creates the test object when invoked +// Test result +// +// The constructor of TestInfo registers itself with the UnitTest +// singleton such that the RUN_ALL_TESTS() macro knows which tests to +// run. +class GTEST_API_ TestInfo { + public: + // Destructs a TestInfo object. This function is not virtual, so + // don't inherit from TestInfo. + ~TestInfo(); + + // Returns the test case name. + const char* test_case_name() const { return test_case_name_.c_str(); } + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a typed + // or a type-parameterized test. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } + + // Returns the text representation of the value parameter, or NULL if this + // is not a value-parameterized test. + const char* value_param() const { + if (value_param_.get() != NULL) + return value_param_->c_str(); + return NULL; + } + + // Returns true if this test should run, that is if the test is not + // disabled (or it is disabled but the also_run_disabled_tests flag has + // been specified) and its full name matches the user-specified filter. + // + // Google Test allows the user to filter the tests by their full names. + // The full name of a test Bar in test case Foo is defined as + // "Foo.Bar". Only the tests that match the filter will run. + // + // A filter is a colon-separated list of glob (not regex) patterns, + // optionally followed by a '-' and a colon-separated list of + // negative patterns (tests to exclude). A test is run if it + // matches one of the positive patterns and does not match any of + // the negative patterns. + // + // For example, *A*:Foo.* is a filter that matches any string that + // contains the character 'A' or starts with "Foo.". + bool should_run() const { return should_run_; } + + // Returns true iff this test will appear in the XML report. + bool is_reportable() const { + // For now, the XML report includes all tests matching the filter. + // In the future, we may trim tests that are excluded because of + // sharding. + return matches_filter_; + } + + // Returns the result of the test. + const TestResult* result() const { return &result_; } + + private: +#if GTEST_HAS_DEATH_TEST + friend class internal::DefaultDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + friend class Test; + friend class TestCase; + friend class internal::UnitTestImpl; + friend class internal::StreamingListenerTest; + friend TestInfo* internal::MakeAndRegisterTestInfo( + const char* test_case_name, + const char* name, + const char* type_param, + const char* value_param, + internal::TypeId fixture_class_id, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + internal::TestFactoryBase* factory); + + // Constructs a TestInfo object. The newly constructed instance assumes + // ownership of the factory object. + TestInfo(const std::string& test_case_name, + const std::string& name, + const char* a_type_param, // NULL if not a type-parameterized test + const char* a_value_param, // NULL if not a value-parameterized test + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory); + + // Increments the number of death tests encountered in this test so + // far. + int increment_death_test_count() { + return result_.increment_death_test_count(); + } + + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); + + static void ClearTestResult(TestInfo* test_info) { + test_info->result_.Clear(); + } + + // These fields are immutable properties of the test. + const std::string test_case_name_; // Test case name + const std::string name_; // Test name + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // Text representation of the value parameter, or NULL if this is not a + // value-parameterized test. + const internal::scoped_ptr value_param_; + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object + + // This field is mutable and needs to be reset before running the + // test for the second time. + TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); +}; + +// A test case, which consists of a vector of TestInfos. +// +// TestCase is not copyable. +class GTEST_API_ TestCase { + public: + // Creates a TestCase with the given name. + // + // TestCase does NOT have a default constructor. Always use this + // constructor to create a TestCase object. + // + // Arguments: + // + // name: name of the test case + // a_type_param: the name of the test's type parameter, or NULL if + // this is not a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase(const char* name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Destructor of TestCase. + virtual ~TestCase(); + + // Gets the name of the TestCase. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a + // type-parameterized test case. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } + + // Returns true if any test in this test case should run. + bool should_run() const { return should_run_; } + + // Gets the number of successful tests in this test case. + int successful_test_count() const; + + // Gets the number of failed tests in this test case. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests in this test case. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Get the number of tests in this test case that should run. + int test_to_run_count() const; + + // Gets the number of all tests in this test case. + int total_test_count() const; + + // Returns true iff the test case passed. + bool Passed() const { return !Failed(); } + + // Returns true iff the test case failed. + bool Failed() const { return failed_test_count() > 0; } + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + const TestInfo* GetTestInfo(int i) const; + + // Returns the TestResult that holds test properties recorded during + // execution of SetUpTestCase and TearDownTestCase. + const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } + + private: + friend class Test; + friend class internal::UnitTestImpl; + + // Gets the (mutable) vector of TestInfos in this TestCase. + std::vector& test_info_list() { return test_info_list_; } + + // Gets the (immutable) vector of TestInfos in this TestCase. + const std::vector& test_info_list() const { + return test_info_list_; + } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + TestInfo* GetMutableTestInfo(int i); + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Adds a TestInfo to this test case. Will delete the TestInfo upon + // destruction of the TestCase object. + void AddTestInfo(TestInfo * test_info); + + // Clears the results of all tests in this test case. + void ClearResult(); + + // Clears the results of all tests in the given test case. + static void ClearTestCaseResult(TestCase* test_case) { + test_case->ClearResult(); + } + + // Runs every test in this TestCase. + void Run(); + + // Runs SetUpTestCase() for this TestCase. This wrapper is needed + // for catching exceptions thrown from SetUpTestCase(). + void RunSetUpTestCase() { (*set_up_tc_)(); } + + // Runs TearDownTestCase() for this TestCase. This wrapper is + // needed for catching exceptions thrown from TearDownTestCase(). + void RunTearDownTestCase() { (*tear_down_tc_)(); } + + // Returns true iff test passed. + static bool TestPassed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Passed(); + } + + // Returns true iff test failed. + static bool TestFailed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Failed(); + } + + // Returns true iff the test is disabled and will be reported in the XML + // report. + static bool TestReportableDisabled(const TestInfo* test_info) { + return test_info->is_reportable() && test_info->is_disabled_; + } + + // Returns true iff test is disabled. + static bool TestDisabled(const TestInfo* test_info) { + return test_info->is_disabled_; + } + + // Returns true iff this test will appear in the XML report. + static bool TestReportable(const TestInfo* test_info) { + return test_info->is_reportable(); + } + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo* test_info) { + return test_info->should_run(); + } + + // Shuffles the tests in this test case. + void ShuffleTests(internal::Random* random); + + // Restores the test order to before the first shuffle. + void UnshuffleTests(); + + // Name of the test case. + std::string name_; + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // The vector of TestInfos in their original order. It owns the + // elements in the vector. + std::vector test_info_list_; + // Provides a level of indirection for the test list to allow easy + // shuffling and restoring the test order. The i-th element in this + // vector is the index of the i-th test in the shuffled test list. + std::vector test_indices_; + // Pointer to the function that sets up the test case. + Test::SetUpTestCaseFunc set_up_tc_; + // Pointer to the function that tears down the test case. + Test::TearDownTestCaseFunc tear_down_tc_; + // True iff any test in this test case should run. + bool should_run_; + // Elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + // Holds test properties recorded during execution of SetUpTestCase and + // TearDownTestCase. + TestResult ad_hoc_test_result_; + + // We disallow copying TestCases. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); +}; + +// An Environment object is capable of setting up and tearing down an +// environment. The user should subclass this to define his own +// environment(s). +// +// An Environment object does the set-up and tear-down in virtual +// methods SetUp() and TearDown() instead of the constructor and the +// destructor, as: +// +// 1. You cannot safely throw from a destructor. This is a problem +// as in some cases Google Test is used where exceptions are enabled, and +// we may want to implement ASSERT_* using exceptions where they are +// available. +// 2. You cannot use ASSERT_* directly in a constructor or +// destructor. +class Environment { + public: + // The d'tor is virtual as we need to subclass Environment. + virtual ~Environment() {} + + // Override this to define how to set up the environment. + virtual void SetUp() {} + + // Override this to define how to tear down the environment. + virtual void TearDown() {} + private: + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } +}; + +// The interface for tracing execution of tests. The methods are organized in +// the order the corresponding events are fired. +class TestEventListener { + public: + virtual ~TestEventListener() {} + + // Fired before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + + // Fired before each iteration of tests starts. There may be more than + // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration + // index, starting from 0. + virtual void OnTestIterationStart(const UnitTest& unit_test, + int iteration) = 0; + + // Fired before environment set-up for each iteration of tests starts. + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + + // Fired after environment set-up for each iteration of tests ends. + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + + // Fired before the test case starts. + virtual void OnTestCaseStart(const TestCase& test_case) = 0; + + // Fired before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Fired after a failed assertion or a SUCCEED() invocation. + virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + + // Fired after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Fired after the test case ends. + virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + + // Fired before environment tear-down for each iteration of tests starts. + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; + + // Fired after environment tear-down for each iteration of tests ends. + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; + + // Fired after each iteration of tests finishes. + virtual void OnTestIterationEnd(const UnitTest& unit_test, + int iteration) = 0; + + // Fired after all test activities have ended. + virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. For +// comments about each method please see the definition of TestEventListener +// above. +class EmptyTestEventListener : public TestEventListener { + public: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} + virtual void OnTestStart(const TestInfo& /*test_info*/) {} + virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} + virtual void OnTestEnd(const TestInfo& /*test_info*/) {} + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} + virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} +}; + +// TestEventListeners lets users add listeners to track events in Google Test. +class GTEST_API_ TestEventListeners { + public: + TestEventListeners(); + ~TestEventListeners(); + + // Appends an event listener to the end of the list. Google Test assumes + // the ownership of the listener (i.e. it will delete the listener when + // the test program finishes). + void Append(TestEventListener* listener); + + // Removes the given event listener from the list and returns it. It then + // becomes the caller's responsibility to delete the listener. Returns + // NULL if the listener is not found in the list. + TestEventListener* Release(TestEventListener* listener); + + // Returns the standard listener responsible for the default console + // output. Can be removed from the listeners list to shut down default + // console output. Note that removing this object from the listener list + // with Release transfers its ownership to the caller and makes this + // function return NULL the next time. + TestEventListener* default_result_printer() const { + return default_result_printer_; + } + + // Returns the standard listener responsible for the default XML output + // controlled by the --gtest_output=xml flag. Can be removed from the + // listeners list by users who want to shut down the default XML output + // controlled by this flag and substitute it with custom one. Note that + // removing this object from the listener list with Release transfers its + // ownership to the caller and makes this function return NULL the next + // time. + TestEventListener* default_xml_generator() const { + return default_xml_generator_; + } + + private: + friend class TestCase; + friend class TestInfo; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::NoExecDeathTest; + friend class internal::TestEventListenersAccessor; + friend class internal::UnitTestImpl; + + // Returns repeater that broadcasts the TestEventListener events to all + // subscribers. + TestEventListener* repeater(); + + // Sets the default_result_printer attribute to the provided listener. + // The listener is also added to the listener list and previous + // default_result_printer is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultResultPrinter(TestEventListener* listener); + + // Sets the default_xml_generator attribute to the provided listener. The + // listener is also added to the listener list and previous + // default_xml_generator is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultXmlGenerator(TestEventListener* listener); + + // Controls whether events will be forwarded by the repeater to the + // listeners in the list. + bool EventForwardingEnabled() const; + void SuppressEventForwarding(); + + // The actual list of listeners. + internal::TestEventRepeater* repeater_; + // Listener responsible for the standard result output. + TestEventListener* default_result_printer_; + // Listener responsible for the creation of the XML output file. + TestEventListener* default_xml_generator_; + + // We disallow copying TestEventListeners. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); +}; + +// A UnitTest consists of a vector of TestCases. +// +// This is a singleton class. The only instance of UnitTest is +// created when UnitTest::GetInstance() is first called. This +// instance is never deleted. +// +// UnitTest is not copyable. +// +// This class is thread-safe as long as the methods are called +// according to their specification. +class GTEST_API_ UnitTest { + public: + // Gets the singleton UnitTest object. The first time this method + // is called, a UnitTest object is constructed and returned. + // Consecutive calls will return the same object. + static UnitTest* GetInstance(); + + // Runs all tests in this UnitTest object and prints the result. + // Returns 0 if successful, or 1 otherwise. + // + // This method can only be called from the main thread. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + int Run() GTEST_MUST_USE_RESULT_; + + // Returns the working directory when the first TEST() or TEST_F() + // was executed. The UnitTest object owns the string. + const char* original_working_dir() const; + + // Returns the TestCase object for the test that's currently running, + // or NULL if no test is running. + const TestCase* current_test_case() const + GTEST_LOCK_EXCLUDED_(mutex_); + + // Returns the TestInfo object for the test that's currently running, + // or NULL if no test is running. + const TestInfo* current_test_info() const + GTEST_LOCK_EXCLUDED_(mutex_); + + // Returns the random seed used at the start of the current test run. + int random_seed() const; + +#if GTEST_HAS_PARAM_TEST + // Returns the ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() + GTEST_LOCK_EXCLUDED_(mutex_); +#endif // GTEST_HAS_PARAM_TEST + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the time of the test program start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const; + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const; + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const; + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const; + + // Returns the TestResult containing information on test failures and + // properties logged outside of individual test cases. + const TestResult& ad_hoc_test_result() const; + + // Returns the list of event listeners that can be used to track events + // inside Google Test. + TestEventListeners& listeners(); + + private: + // Registers and returns a global test environment. When a test + // program is run, all global test environments will be set-up in + // the order they were registered. After all tests in the program + // have finished, all global test environments will be torn-down in + // the *reverse* order they were registered. + // + // The UnitTest object takes ownership of the given environment. + // + // This method can only be called from the main thread. + Environment* AddEnvironment(Environment* env); + + // Adds a TestPartResult to the current TestResult object. All + // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) + // eventually call this to report their results. The user code + // should use the assertion macros instead of calling this directly. + void AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const std::string& message, + const std::string& os_stack_trace) + GTEST_LOCK_EXCLUDED_(mutex_); + + // Adds a TestProperty to the current TestResult object when invoked from + // inside a test, to current TestCase's ad_hoc_test_result_ when invoked + // from SetUpTestCase or TearDownTestCase, or to the global property set + // when invoked elsewhere. If the result already contains a property with + // the same key, the value will be updated. + void RecordProperty(const std::string& key, const std::string& value); + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i); + + // Accessors for the implementation object. + internal::UnitTestImpl* impl() { return impl_; } + const internal::UnitTestImpl* impl() const { return impl_; } + + // These classes and funcions are friends as they need to access private + // members of UnitTest. + friend class Test; + friend class internal::AssertHelper; + friend class internal::ScopedTrace; + friend class internal::StreamingListenerTest; + friend class internal::UnitTestRecordPropertyTestHelper; + friend Environment* AddGlobalTestEnvironment(Environment* env); + friend internal::UnitTestImpl* internal::GetUnitTestImpl(); + friend void internal::ReportFailureInUnknownLocation( + TestPartResult::Type result_type, + const std::string& message); + + // Creates an empty UnitTest. + UnitTest(); + + // D'tor + virtual ~UnitTest(); + + // Pushes a trace defined by SCOPED_TRACE() on to the per-thread + // Google Test trace stack. + void PushGTestTrace(const internal::TraceInfo& trace) + GTEST_LOCK_EXCLUDED_(mutex_); + + // Pops a trace from the per-thread Google Test trace stack. + void PopGTestTrace() + GTEST_LOCK_EXCLUDED_(mutex_); + + // Protects mutable state in *impl_. This is mutable as some const + // methods need to lock it too. + mutable internal::Mutex mutex_; + + // Opaque implementation object. This field is never changed once + // the object is constructed. We don't mark it as const here, as + // doing so will cause a warning in the constructor of UnitTest. + // Mutable state in *impl_ is protected by mutex_. + internal::UnitTestImpl* impl_; + + // We disallow copying UnitTest. + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); +}; + +// A convenient wrapper for adding an environment for the test +// program. +// +// You should call this before RUN_ALL_TESTS() is called, probably in +// main(). If you use gtest_main, you need to call this before main() +// starts for it to take effect. For example, you can define a global +// variable like this: +// +// testing::Environment* const foo_env = +// testing::AddGlobalTestEnvironment(new FooEnvironment); +// +// However, we strongly recommend you to write your own main() and +// call AddGlobalTestEnvironment() there, as relying on initialization +// of global variables makes the code harder to read and may cause +// problems when you register multiple environments from different +// translation units and the environments have dependencies among them +// (remember that the compiler doesn't guarantee the order in which +// global variables from different translation units are initialized). +inline Environment* AddGlobalTestEnvironment(Environment* env) { + return UnitTest::GetInstance()->AddEnvironment(env); +} + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +GTEST_API_ void InitGoogleTest(int* argc, char** argv); + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); + +namespace internal { + +// FormatForComparison::Format(value) formats a +// value of type ToPrint that is an operand of a comparison assertion +// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in +// the comparison, and is used to help determine the best way to +// format the value. In particular, when the value is a C string +// (char pointer) and the other operand is an STL string object, we +// want to format the C string as a string, since we know it is +// compared by value with the string object. If the value is a char +// pointer but the other operand is not an STL string object, we don't +// know whether the pointer is supposed to point to a NUL-terminated +// string, and thus want to print it as a pointer to be safe. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// The default case. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint& value) { + return ::testing::PrintToString(value); + } +}; + +// Array. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint* value) { + return FormatForComparison::Format(value); + } +}; + +// By default, print C string as pointers to be safe, as we don't know +// whether they actually point to a NUL-terminated string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ + template \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(static_cast(value)); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ + +// If a C string is compared with an STL string object, we know it's meant +// to point to a NUL-terminated string, and thus can print it as a string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ + template <> \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(value); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); + +#if GTEST_HAS_GLOBAL_STRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); +#endif + +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); +#endif + +#if GTEST_HAS_STD_WSTRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); +#endif + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char* or void*, and print it as a C string when it is compared +// against an std::string object, for example. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +std::string FormatForComparisonFailureMessage( + const T1& value, const T2& /* other_operand */) { + return FormatForComparison::Format(value); +} + +// The helper function for {ASSERT|EXPECT}_EQ. +template +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4389) // Temporarily disables warning on + // signed/unsigned mismatch. +#endif + + if (expected == actual) { + return AssertionSuccess(); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// With this overloaded version, we allow anonymous enums to be used +// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums +// can be implicitly cast to BiggestInt. +GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual); + +// The helper class for {ASSERT|EXPECT}_EQ. The template argument +// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() +// is a null pointer literal. The following default implementation is +// for lhs_is_null_literal being false. +template +class EqHelper { + public: + // This templatized version is for the general case. + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // With this overloaded version, we allow anonymous enums to be used + // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous + // enums can be implicitly cast to BiggestInt. + // + // Even though its body looks the same as the above version, we + // cannot merge the two, as it will make anonymous enums unhappy. + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } +}; + +// This specialization is used when the first argument to ASSERT_EQ() +// is a null pointer literal, like NULL, false, or 0. +template <> +class EqHelper { + public: + // We define two overloaded versions of Compare(). The first + // version will be picked when the second argument to ASSERT_EQ() is + // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or + // EXPECT_EQ(false, a_bool). + template + static AssertionResult Compare( + const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual, + // The following line prevents this overload from being considered if T2 + // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) + // expands to Compare("", "", NULL, my_ptr), which requires a conversion + // to match the Secret* in the other overload, which would otherwise make + // this template match better. + typename EnableIf::value>::type* = 0) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // This version will be picked when the second argument to ASSERT_EQ() is a + // pointer, e.g. ASSERT_EQ(NULL, a_pointer). + template + static AssertionResult Compare( + const char* expected_expression, + const char* actual_expression, + // We used to have a second template parameter instead of Secret*. That + // template parameter would deduce to 'long', making this a better match + // than the first overload even without the first overload's EnableIf. + // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to + // non-pointer argument" (even a deduced integral argument), so the old + // implementation caused warnings in user code. + Secret* /* expected (NULL) */, + T* actual) { + // We already know that 'expected' is a null pointer. + return CmpHelperEQ(expected_expression, actual_expression, + static_cast(NULL), actual); + } +}; + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste +// of similar code. +// +// For each templatized helper function, we also define an overloaded +// version for BiggestInt in order to reduce code bloat and allow +// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled +// with gcc 4. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +template \ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + const T1& val1, const T2& val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +}\ +GTEST_API_ AssertionResult CmpHelper##op_name(\ + const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) + +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// Implements the helper function for {ASSERT|EXPECT}_NE +GTEST_IMPL_CMP_HELPER_(NE, !=); +// Implements the helper function for {ASSERT|EXPECT}_LE +GTEST_IMPL_CMP_HELPER_(LE, <=); +// Implements the helper function for {ASSERT|EXPECT}_LT +GTEST_IMPL_CMP_HELPER_(LT, <); +// Implements the helper function for {ASSERT|EXPECT}_GE +GTEST_IMPL_CMP_HELPER_(GE, >=); +// Implements the helper function for {ASSERT|EXPECT}_GT +GTEST_IMPL_CMP_HELPER_(GT, >); + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRNE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + + +// Helper function for *_STREQ on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual); + +// Helper function for *_STRNE on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +} // namespace internal + +// IsSubstring() and IsNotSubstring() are intended to be used as the +// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by +// themselves. They check whether needle is a substring of haystack +// (NULL is considered a substring of itself only), and return an +// appropriate error message when they fail. +// +// The {needle,haystack}_expr arguments are the stringified +// expressions that generated the two real arguments. +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +// Helper template function for comparing floating-points. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, + const char* actual_expression, + RawType expected, + RawType actual) { + const FloatingPoint lhs(expected), rhs(actual); + + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + ::std::stringstream expected_ss; + expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << expected; + + ::std::stringstream actual_ss; + actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << actual; + + return EqFailure(expected_expression, + actual_expression, + StringStreamToString(&expected_ss), + StringStreamToString(&actual_ss), + false); +} + +// Helper function for implementing ASSERT_NEAR. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// A class that enables one to stream messages to assertion macros +class GTEST_API_ AssertHelper { + public: + // Constructor. + AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message); + ~AssertHelper(); + + // Message assignment is a semantic trick to enable assertion + // streaming; see the GTEST_MESSAGE_ macro below. + void operator=(const Message& message) const; + + private: + // We put our data in a struct so that the size of the AssertHelper class can + // be as small as possible. This is important because gcc is incapable of + // re-using stack space even for temporary variables, so every EXPECT_EQ + // reserves stack space for another AssertHelper. + struct AssertHelperData { + AssertHelperData(TestPartResult::Type t, + const char* srcfile, + int line_num, + const char* msg) + : type(t), file(srcfile), line(line_num), message(msg) { } + + TestPartResult::Type const type; + const char* const file; + int const line; + std::string const message; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); + }; + + AssertHelperData* const data_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); +}; + +} // namespace internal + +#if GTEST_HAS_PARAM_TEST +// The pure interface class that all value-parameterized tests inherit from. +// A value-parameterized class must inherit from both ::testing::Test and +// ::testing::WithParamInterface. In most cases that just means inheriting +// from ::testing::TestWithParam, but more complicated test hierarchies +// may need to inherit from Test and WithParamInterface at different levels. +// +// This interface has support for accessing the test parameter value via +// the GetParam() method. +// +// Use it with one of the parameter generator defining functions, like Range(), +// Values(), ValuesIn(), Bool(), and Combine(). +// +// class FooTest : public ::testing::TestWithParam { +// protected: +// FooTest() { +// // Can use GetParam() here. +// } +// virtual ~FooTest() { +// // Can use GetParam() here. +// } +// virtual void SetUp() { +// // Can use GetParam() here. +// } +// virtual void TearDown { +// // Can use GetParam() here. +// } +// }; +// TEST_P(FooTest, DoesBar) { +// // Can use GetParam() method here. +// Foo foo; +// ASSERT_TRUE(foo.DoesBar(GetParam())); +// } +// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); + +template +class WithParamInterface { + public: + typedef T ParamType; + virtual ~WithParamInterface() {} + + // The current parameter value. Is also available in the test fixture's + // constructor. This member function is non-static, even though it only + // references static data, to reduce the opportunity for incorrect uses + // like writing 'WithParamInterface::GetParam()' for a test that + // uses a fixture whose parameter type is int. + const ParamType& GetParam() const { + GTEST_CHECK_(parameter_ != NULL) + << "GetParam() can only be called inside a value-parameterized test " + << "-- did you intend to write TEST_P instead of TEST_F?"; + return *parameter_; + } + + private: + // Sets parameter value. The caller is responsible for making sure the value + // remains alive and unchanged throughout the current test. + static void SetParam(const ParamType* parameter) { + parameter_ = parameter; + } + + // Static value used for accessing parameter during a test lifetime. + static const ParamType* parameter_; + + // TestClass must be a subclass of WithParamInterface and Test. + template friend class internal::ParameterizedTestFactory; +}; + +template +const T* WithParamInterface::parameter_ = NULL; + +// Most value-parameterized classes can ignore the existence of +// WithParamInterface, and can just inherit from ::testing::TestWithParam. + +template +class TestWithParam : public Test, public WithParamInterface { +}; + +#endif // GTEST_HAS_PARAM_TEST + +// Macros for indicating success/failure in test code. + +// ADD_FAILURE unconditionally adds a failure to the current test. +// SUCCEED generates a success - it doesn't automatically make the +// current test successful, as a test is only successful when it has +// no failure. +// +// EXPECT_* verifies that a certain condition is satisfied. If not, +// it behaves like ADD_FAILURE. In particular: +// +// EXPECT_TRUE verifies that a Boolean condition is true. +// EXPECT_FALSE verifies that a Boolean condition is false. +// +// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except +// that they will also abort the current function on failure. People +// usually want the fail-fast behavior of FAIL and ASSERT_*, but those +// writing data-driven tests often find themselves using ADD_FAILURE +// and EXPECT_* more. + +// Generates a nonfatal failure with a generic message. +#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") + +// Generates a nonfatal failure at the given source file location with +// a generic message. +#define ADD_FAILURE_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kNonFatalFailure) + +// Generates a fatal failure with a generic message. +#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") + +// Define this macro to 1 to omit the definition of FAIL(), which is a +// generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_FAIL +# define FAIL() GTEST_FAIL() +#endif + +// Generates a success with a generic message. +#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") + +// Define this macro to 1 to omit the definition of SUCCEED(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_SUCCEED +# define SUCCEED() GTEST_SUCCEED() +#endif + +// Macros for testing exceptions. +// +// * {ASSERT|EXPECT}_THROW(statement, expected_exception): +// Tests that the statement throws the expected exception. +// * {ASSERT|EXPECT}_NO_THROW(statement): +// Tests that the statement doesn't throw any exception. +// * {ASSERT|EXPECT}_ANY_THROW(statement): +// Tests that the statement throws an exception. + +#define EXPECT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) +#define EXPECT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define EXPECT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define ASSERT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) +#define ASSERT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) +#define ASSERT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) + +// Boolean assertions. Condition can be either a Boolean expression or an +// AssertionResult. For more information on how to use AssertionResult with +// these macros see comments on that class. +#define EXPECT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_NONFATAL_FAILURE_) +#define EXPECT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_NONFATAL_FAILURE_) +#define ASSERT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_FATAL_FAILURE_) +#define ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_FATAL_FAILURE_) + +// Includes the auto-generated header that implements a family of +// generic predicate assertion macros. +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Makes sure this header is not included before gtest.h. +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) \ + ; \ + else \ + on_failure(gtest_ar.failure_message()) + + +// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +template +AssertionResult AssertPred1Helper(const char* pred_text, + const char* e1, + Pred pred, + const T1& v1) { + if (pred(v1)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. +// Don't use this in your code. +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, v1), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +#define GTEST_PRED1_(pred, v1, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ + #v1, \ + pred, \ + v1), on_failure) + +// Unary predicate assertion macros. +#define EXPECT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +template +AssertionResult AssertPred2Helper(const char* pred_text, + const char* e1, + const char* e2, + Pred pred, + const T1& v1, + const T2& v2) { + if (pred(v1, v2)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. +// Don't use this in your code. +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +#define GTEST_PRED2_(pred, v1, v2, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ + #v1, \ + #v2, \ + pred, \ + v1, \ + v2), on_failure) + +// Binary predicate assertion macros. +#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +template +AssertionResult AssertPred3Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3) { + if (pred(v1, v2, v3)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. +// Don't use this in your code. +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + pred, \ + v1, \ + v2, \ + v3), on_failure) + +// Ternary predicate assertion macros. +#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +template +AssertionResult AssertPred4Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (pred(v1, v2, v3, v4)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. +// Don't use this in your code. +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4), on_failure) + +// 4-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +template +AssertionResult AssertPred5Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ", " + << e5 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4 + << "\n" << e5 << " evaluates to " << v5; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. +// Don't use this in your code. +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + #v5, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4, \ + v5), on_failure) + +// 5-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) + + + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Macros for testing equalities and inequalities. +// +// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// +// When they are not, Google Test prints both the tested expressions and +// their actual values. The values must be compatible built-in types, +// or you will get a compiler error. By "compatible" we mean that the +// values can be compared by the respective operator. +// +// Note: +// +// 1. It is possible to make a user-defined type work with +// {ASSERT|EXPECT}_??(), but that requires overloading the +// comparison operators and is thus discouraged by the Google C++ +// Usage Guide. Therefore, you are advised to use the +// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are +// equal. +// +// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on +// pointers (in particular, C strings). Therefore, if you use it +// with two C strings, you are testing how their locations in memory +// are related, not how their content is related. To compare two C +// strings by content, use {ASSERT|EXPECT}_STR*(). +// +// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to +// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you +// what the actual value is when it fails, and similarly for the +// other comparisons. +// +// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() +// evaluate their arguments, which is undefined. +// +// 5. These macros evaluate their arguments exactly once. +// +// Examples: +// +// EXPECT_NE(5, Foo()); +// EXPECT_EQ(NULL, a_pointer); +// ASSERT_LT(i, array_size); +// ASSERT_GT(records.size(), 0) << "There is no record left."; + +#define EXPECT_EQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define EXPECT_NE(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) +#define EXPECT_LE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define EXPECT_LT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define EXPECT_GE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define EXPECT_GT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +#define GTEST_ASSERT_EQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define GTEST_ASSERT_NE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define GTEST_ASSERT_LE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define GTEST_ASSERT_LT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define GTEST_ASSERT_GE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define GTEST_ASSERT_GT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of +// ASSERT_XY(), which clashes with some users' own code. + +#if !GTEST_DONT_DEFINE_ASSERT_EQ +# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_NE +# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LE +# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LT +# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GE +# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GT +# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) +#endif + +// C-string Comparisons. All tests treat NULL and any non-NULL string +// as different. Two NULLs are equal. +// +// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 +// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 +// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case +// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case +// +// For wide or narrow string objects, you can use the +// {ASSERT|EXPECT}_??() macros. +// +// Don't depend on the order in which the arguments are evaluated, +// which is undefined. +// +// These macros evaluate their arguments exactly once. + +#define EXPECT_STREQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define EXPECT_STRNE(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define EXPECT_STRCASEEQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define EXPECT_STRCASENE(s1, s2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +#define ASSERT_STREQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define ASSERT_STRNE(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define ASSERT_STRCASEEQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define ASSERT_STRCASENE(s1, s2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +// Macros for comparing floating-point numbers. +// +// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): +// Tests that two float values are almost equal. +// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): +// Tests that two double values are almost equal. +// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): +// Tests that v1 and v2 are within the given distance to each other. +// +// Google Test uses ULP-based comparison to automatically pick a default +// error bound that is appropriate for the operands. See the +// FloatingPoint template class in gtest-internal.h if you are +// interested in the implementation details. + +#define EXPECT_FLOAT_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_DOUBLE_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_FLOAT_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_DOUBLE_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_NEAR(val1, val2, abs_error)\ + EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +#define ASSERT_NEAR(val1, val2, abs_error)\ + ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +// These predicate format functions work on floating-point values, and +// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. +// +// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2); +GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2); + + +#if GTEST_OS_WINDOWS + +// Macros that test for HRESULT failure and success, these are only useful +// on Windows, and rely on Windows SDK macros and APIs to compile. +// +// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) +// +// When expr unexpectedly fails or succeeds, Google Test prints the +// expected result and the actual result with both a human-readable +// string representation of the error, if available, as well as the +// hex result code. +# define EXPECT_HRESULT_SUCCEEDED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define ASSERT_HRESULT_SUCCEEDED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define EXPECT_HRESULT_FAILED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +# define ASSERT_HRESULT_FAILED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#endif // GTEST_OS_WINDOWS + +// Macros that execute statement and check that it doesn't generate new fatal +// failures in the current thread. +// +// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); +// +// Examples: +// +// EXPECT_NO_FATAL_FAILURE(Process()); +// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; +// +#define ASSERT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) +#define EXPECT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) + +// Causes a trace (including the source file path, the current line +// number, and the given message) to be included in every test failure +// message generated by code in the current scope. The effect is +// undone when the control leaves the current scope. +// +// The message argument can be anything streamable to std::ostream. +// +// In the implementation, we include the current line number as part +// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s +// to appear in the same block - as long as they are on different +// lines. +#define SCOPED_TRACE(message) \ + ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, ::testing::Message() << (message)) + +// Compile-time assertion for type equality. +// StaticAssertTypeEq() compiles iff type1 and type2 are +// the same type. The value it returns is not interesting. +// +// Instead of making StaticAssertTypeEq a class template, we make it a +// function template that invokes a helper class template. This +// prevents a user from misusing StaticAssertTypeEq by +// defining objects of that type. +// +// CAVEAT: +// +// When used inside a method of a class template, +// StaticAssertTypeEq() is effective ONLY IF the method is +// instantiated. For example, given: +// +// template class Foo { +// public: +// void Bar() { testing::StaticAssertTypeEq(); } +// }; +// +// the code: +// +// void Test1() { Foo foo; } +// +// will NOT generate a compiler error, as Foo::Bar() is never +// actually instantiated. Instead, you need: +// +// void Test2() { Foo foo; foo.Bar(); } +// +// to cause a compiler error. +template +bool StaticAssertTypeEq() { + (void)internal::StaticAssertTypeEqHelper(); + return true; +} + +// Defines a test. +// +// The first parameter is the name of the test case, and the second +// parameter is the name of the test within the test case. +// +// The convention is to end the test case name with "Test". For +// example, a test case for the Foo class can be named FooTest. +// +// The user should put his test code between braces after using this +// macro. Example: +// +// TEST(FooTest, InitializesCorrectly) { +// Foo foo; +// EXPECT_TRUE(foo.StatusIsOK()); +// } + +// Note that we call GetTestTypeId() instead of GetTypeId< +// ::testing::Test>() here to get the type ID of testing::Test. This +// is to work around a suspected linker bug when using Google Test as +// a framework on Mac OS X. The bug causes GetTypeId< +// ::testing::Test>() to return different values depending on whether +// the call is from the Google Test framework itself or from user test +// code. GetTestTypeId() is guaranteed to always return the same +// value, as it always calls GetTypeId<>() from the Google Test +// framework. +#define GTEST_TEST(test_case_name, test_name)\ + GTEST_TEST_(test_case_name, test_name, \ + ::testing::Test, ::testing::internal::GetTestTypeId()) + +// Define this macro to 1 to omit the definition of TEST(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_TEST +# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#endif + +// Defines a test that uses a test fixture. +// +// The first parameter is the name of the test fixture class, which +// also doubles as the test case name. The second parameter is the +// name of the test within the test case. +// +// A test fixture class must be declared earlier. The user should put +// his test code between braces after using this macro. Example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { b_.AddElement(3); } +// +// Foo a_; +// Foo b_; +// }; +// +// TEST_F(FooTest, InitializesCorrectly) { +// EXPECT_TRUE(a_.StatusIsOK()); +// } +// +// TEST_F(FooTest, ReturnsElementCountCorrectly) { +// EXPECT_EQ(0, a_.size()); +// EXPECT_EQ(1, b_.size()); +// } + +#define TEST_F(test_fixture, test_name)\ + GTEST_TEST_(test_fixture, test_name, test_fixture, \ + ::testing::internal::GetTypeId()) + +} // namespace testing + +// Use this function in main() to run all tests. It returns 0 if all +// tests are successful, or 1 otherwise. +// +// RUN_ALL_TESTS() should be invoked after the command line has been +// parsed by InitGoogleTest(). +// +// This function was formerly a macro; thus, it is in the global +// namespace and has an all-caps name. +int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; + +inline int RUN_ALL_TESTS() { + return ::testing::UnitTest::GetInstance()->Run(); +} + +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/deps/gyp/.gitignore b/deps/gyp/.gitignore new file mode 100644 index 000000000..0d20b6487 --- /dev/null +++ b/deps/gyp/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/deps/gyp/LICENSE b/deps/gyp/LICENSE new file mode 100644 index 000000000..ab6b011a1 --- /dev/null +++ b/deps/gyp/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/deps/gyp/OWNERS b/deps/gyp/OWNERS new file mode 100644 index 000000000..72e8ffc0d --- /dev/null +++ b/deps/gyp/OWNERS @@ -0,0 +1 @@ +* diff --git a/deps/gyp/PRESUBMIT.py b/deps/gyp/PRESUBMIT.py new file mode 100644 index 000000000..b79316a91 --- /dev/null +++ b/deps/gyp/PRESUBMIT.py @@ -0,0 +1,118 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + +"""Top-level presubmit script for GYP. + +See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts +for more details about the presubmit API built into gcl. +""" + + +PYLINT_BLACKLIST = [ + # TODO: fix me. + # From SCons, not done in google style. + 'test/lib/TestCmd.py', + 'test/lib/TestCommon.py', + 'test/lib/TestGyp.py', +] + + +PYLINT_DISABLED_WARNINGS = [ + # TODO: fix me. + # Many tests include modules they don't use. + 'W0611', + # Include order doesn't properly include local files? + 'F0401', + # Some use of built-in names. + 'W0622', + # Some unused variables. + 'W0612', + # Operator not preceded/followed by space. + 'C0323', + 'C0322', + # Unnecessary semicolon. + 'W0301', + # Unused argument. + 'W0613', + # String has no effect (docstring in wrong place). + 'W0105', + # Comma not followed by space. + 'C0324', + # Access to a protected member. + 'W0212', + # Bad indent. + 'W0311', + # Line too long. + 'C0301', + # Undefined variable. + 'E0602', + # Not exception type specified. + 'W0702', + # No member of that name. + 'E1101', + # Dangerous default {}. + 'W0102', + # Others, too many to sort. + 'W0201', 'W0232', 'E1103', 'W0621', 'W0108', 'W0223', 'W0231', + 'R0201', 'E0101', 'C0321', + # ************* Module copy + # W0104:427,12:_test.odict.__setitem__: Statement seems to have no effect + 'W0104', +] + + +def CheckChangeOnUpload(input_api, output_api): + report = [] + report.extend(input_api.canned_checks.PanProjectChecks( + input_api, output_api)) + return report + + +def CheckChangeOnCommit(input_api, output_api): + report = [] + + # Accept any year number from 2009 to the current year. + current_year = int(input_api.time.strftime('%Y')) + allowed_years = (str(s) for s in reversed(xrange(2009, current_year + 1))) + years_re = '(' + '|'.join(allowed_years) + ')' + + # The (c) is deprecated, but tolerate it until it's removed from all files. + license = ( + r'.*? Copyright (\(c\) )?%(year)s Google Inc\. All rights reserved\.\n' + r'.*? Use of this source code is governed by a BSD-style license that ' + r'can be\n' + r'.*? found in the LICENSE file\.\n' + ) % { + 'year': years_re, + } + + report.extend(input_api.canned_checks.PanProjectChecks( + input_api, output_api, license_header=license)) + report.extend(input_api.canned_checks.CheckTreeIsOpen( + input_api, output_api, + 'http://gyp-status.appspot.com/status', + 'http://gyp-status.appspot.com/current')) + + import os + import sys + old_sys_path = sys.path + try: + sys.path = ['pylib', 'test/lib'] + sys.path + blacklist = PYLINT_BLACKLIST + if sys.platform == 'win32': + blacklist = [os.path.normpath(x).replace('\\', '\\\\') + for x in PYLINT_BLACKLIST] + report.extend(input_api.canned_checks.RunPylint( + input_api, + output_api, + black_list=blacklist, + disabled_warnings=PYLINT_DISABLED_WARNINGS)) + finally: + sys.path = old_sys_path + return report + + +def GetPreferredTrySlaves(): + return ['gyp-win32', 'gyp-win64', 'gyp-linux', 'gyp-mac', 'gyp-android'] diff --git a/deps/gyp/codereview.settings b/deps/gyp/codereview.settings new file mode 100644 index 000000000..a04a2440d --- /dev/null +++ b/deps/gyp/codereview.settings @@ -0,0 +1,10 @@ +# This file is used by gcl to get repository specific information. +CODE_REVIEW_SERVER: codereview.chromium.org +CC_LIST: gyp-developer@googlegroups.com +VIEW_VC: http://code.google.com/p/gyp/source/detail?r= +TRY_ON_UPLOAD: True +TRYSERVER_PROJECT: gyp +TRYSERVER_PATCHLEVEL: 0 +TRYSERVER_ROOT: trunk +TRYSERVER_SVN_URL: svn://svn.chromium.org/chrome-try/try-nacl + diff --git a/deps/gyp/gyp b/deps/gyp/gyp new file mode 100755 index 000000000..b53a6dde8 --- /dev/null +++ b/deps/gyp/gyp @@ -0,0 +1,8 @@ +#!/bin/bash +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +set -e +base=$(dirname "$0") +exec python "${base}/gyp_main.py" "$@" diff --git a/deps/gyp/gyp.bat b/deps/gyp/gyp.bat new file mode 100755 index 000000000..c0b4ca24e --- /dev/null +++ b/deps/gyp/gyp.bat @@ -0,0 +1,5 @@ +@rem Copyright (c) 2009 Google Inc. All rights reserved. +@rem Use of this source code is governed by a BSD-style license that can be +@rem found in the LICENSE file. + +@python "%~dp0gyp_main.py" %* diff --git a/deps/gyp/gyp_main.py b/deps/gyp/gyp_main.py new file mode 100755 index 000000000..4ec872f0f --- /dev/null +++ b/deps/gyp/gyp_main.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +# Copyright (c) 2009 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import sys + +# TODO(mark): sys.path manipulation is some temporary testing stuff. +try: + import gyp +except ImportError, e: + import os.path + sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'pylib')) + import gyp + +if __name__ == '__main__': + sys.exit(gyp.script_main()) diff --git a/deps/gyp/gyptest.py b/deps/gyp/gyptest.py new file mode 100755 index 000000000..8f3ee0ffb --- /dev/null +++ b/deps/gyp/gyptest.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python + +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +__doc__ = """ +gyptest.py -- test runner for GYP tests. +""" + +import os +import optparse +import subprocess +import sys + +class CommandRunner: + """ + Executor class for commands, including "commands" implemented by + Python functions. + """ + verbose = True + active = True + + def __init__(self, dictionary={}): + self.subst_dictionary(dictionary) + + def subst_dictionary(self, dictionary): + self._subst_dictionary = dictionary + + def subst(self, string, dictionary=None): + """ + Substitutes (via the format operator) the values in the specified + dictionary into the specified command. + + The command can be an (action, string) tuple. In all cases, we + perform substitution on strings and don't worry if something isn't + a string. (It's probably a Python function to be executed.) + """ + if dictionary is None: + dictionary = self._subst_dictionary + if dictionary: + try: + string = string % dictionary + except TypeError: + pass + return string + + def display(self, command, stdout=None, stderr=None): + if not self.verbose: + return + if type(command) == type(()): + func = command[0] + args = command[1:] + s = '%s(%s)' % (func.__name__, ', '.join(map(repr, args))) + if type(command) == type([]): + # TODO: quote arguments containing spaces + # TODO: handle meta characters? + s = ' '.join(command) + else: + s = self.subst(command) + if not s.endswith('\n'): + s += '\n' + sys.stdout.write(s) + sys.stdout.flush() + + def execute(self, command, stdout=None, stderr=None): + """ + Executes a single command. + """ + if not self.active: + return 0 + if type(command) == type(''): + command = self.subst(command) + cmdargs = shlex.split(command) + if cmdargs[0] == 'cd': + command = (os.chdir,) + tuple(cmdargs[1:]) + if type(command) == type(()): + func = command[0] + args = command[1:] + return func(*args) + else: + if stdout is sys.stdout: + # Same as passing sys.stdout, except python2.4 doesn't fail on it. + subout = None + else: + # Open pipe for anything else so Popen works on python2.4. + subout = subprocess.PIPE + if stderr is sys.stderr: + # Same as passing sys.stderr, except python2.4 doesn't fail on it. + suberr = None + elif stderr is None: + # Merge with stdout if stderr isn't specified. + suberr = subprocess.STDOUT + else: + # Open pipe for anything else so Popen works on python2.4. + suberr = subprocess.PIPE + p = subprocess.Popen(command, + shell=(sys.platform == 'win32'), + stdout=subout, + stderr=suberr) + p.wait() + if stdout is None: + self.stdout = p.stdout.read() + elif stdout is not sys.stdout: + stdout.write(p.stdout.read()) + if stderr not in (None, sys.stderr): + stderr.write(p.stderr.read()) + return p.returncode + + def run(self, command, display=None, stdout=None, stderr=None): + """ + Runs a single command, displaying it first. + """ + if display is None: + display = command + self.display(display) + return self.execute(command, stdout, stderr) + + +class Unbuffered: + def __init__(self, fp): + self.fp = fp + def write(self, arg): + self.fp.write(arg) + self.fp.flush() + def __getattr__(self, attr): + return getattr(self.fp, attr) + +sys.stdout = Unbuffered(sys.stdout) +sys.stderr = Unbuffered(sys.stderr) + + +def is_test_name(f): + return f.startswith('gyptest') and f.endswith('.py') + + +def find_all_gyptest_files(directory): + result = [] + for root, dirs, files in os.walk(directory): + if '.svn' in dirs: + dirs.remove('.svn') + result.extend([ os.path.join(root, f) for f in files if is_test_name(f) ]) + result.sort() + return result + + +def main(argv=None): + if argv is None: + argv = sys.argv + + usage = "gyptest.py [-ahlnq] [-f formats] [test ...]" + parser = optparse.OptionParser(usage=usage) + parser.add_option("-a", "--all", action="store_true", + help="run all tests") + parser.add_option("-C", "--chdir", action="store", default=None, + help="chdir to the specified directory") + parser.add_option("-f", "--format", action="store", default='', + help="run tests with the specified formats") + parser.add_option("-G", '--gyp_option', action="append", default=[], + help="Add -G options to the gyp command line") + parser.add_option("-l", "--list", action="store_true", + help="list available tests and exit") + parser.add_option("-n", "--no-exec", action="store_true", + help="no execute, just print the command line") + parser.add_option("--passed", action="store_true", + help="report passed tests") + parser.add_option("--path", action="append", default=[], + help="additional $PATH directory") + parser.add_option("-q", "--quiet", action="store_true", + help="quiet, don't print test command lines") + opts, args = parser.parse_args(argv[1:]) + + if opts.chdir: + os.chdir(opts.chdir) + + if opts.path: + extra_path = [os.path.abspath(p) for p in opts.path] + extra_path = os.pathsep.join(extra_path) + os.environ['PATH'] = extra_path + os.pathsep + os.environ['PATH'] + + if not args: + if not opts.all: + sys.stderr.write('Specify -a to get all tests.\n') + return 1 + args = ['test'] + + tests = [] + for arg in args: + if os.path.isdir(arg): + tests.extend(find_all_gyptest_files(os.path.normpath(arg))) + else: + if not is_test_name(os.path.basename(arg)): + print >>sys.stderr, arg, 'is not a valid gyp test name.' + sys.exit(1) + tests.append(arg) + + if opts.list: + for test in tests: + print test + sys.exit(0) + + CommandRunner.verbose = not opts.quiet + CommandRunner.active = not opts.no_exec + cr = CommandRunner() + + os.environ['PYTHONPATH'] = os.path.abspath('test/lib') + if not opts.quiet: + sys.stdout.write('PYTHONPATH=%s\n' % os.environ['PYTHONPATH']) + + passed = [] + failed = [] + no_result = [] + + if opts.format: + format_list = opts.format.split(',') + else: + # TODO: not duplicate this mapping from pylib/gyp/__init__.py + format_list = { + 'aix5': ['make'], + 'freebsd7': ['make'], + 'freebsd8': ['make'], + 'openbsd5': ['make'], + 'cygwin': ['msvs'], + 'win32': ['msvs', 'ninja'], + 'linux2': ['make', 'ninja'], + 'linux3': ['make', 'ninja'], + 'darwin': ['make', 'ninja', 'xcode'], + }[sys.platform] + + for format in format_list: + os.environ['TESTGYP_FORMAT'] = format + if not opts.quiet: + sys.stdout.write('TESTGYP_FORMAT=%s\n' % format) + + gyp_options = [] + for option in opts.gyp_option: + gyp_options += ['-G', option] + if gyp_options and not opts.quiet: + sys.stdout.write('Extra Gyp options: %s\n' % gyp_options) + + for test in tests: + status = cr.run([sys.executable, test] + gyp_options, + stdout=sys.stdout, + stderr=sys.stderr) + if status == 2: + no_result.append(test) + elif status: + failed.append(test) + else: + passed.append(test) + + if not opts.quiet: + def report(description, tests): + if tests: + if len(tests) == 1: + sys.stdout.write("\n%s the following test:\n" % description) + else: + fmt = "\n%s the following %d tests:\n" + sys.stdout.write(fmt % (description, len(tests))) + sys.stdout.write("\t" + "\n\t".join(tests) + "\n") + + if opts.passed: + report("Passed", passed) + report("Failed", failed) + report("No result from", no_result) + + if failed: + return 1 + else: + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/deps/gyp/pylib/gyp/MSVSNew.py b/deps/gyp/pylib/gyp/MSVSNew.py new file mode 100644 index 000000000..845dcb063 --- /dev/null +++ b/deps/gyp/pylib/gyp/MSVSNew.py @@ -0,0 +1,340 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""New implementation of Visual Studio project generation.""" + +import os +import random + +import gyp.common + +# hashlib is supplied as of Python 2.5 as the replacement interface for md5 +# and other secure hashes. In 2.6, md5 is deprecated. Import hashlib if +# available, avoiding a deprecation warning under 2.6. Import md5 otherwise, +# preserving 2.4 compatibility. +try: + import hashlib + _new_md5 = hashlib.md5 +except ImportError: + import md5 + _new_md5 = md5.new + + +# Initialize random number generator +random.seed() + +# GUIDs for project types +ENTRY_TYPE_GUIDS = { + 'project': '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}', + 'folder': '{2150E333-8FDC-42A3-9474-1A3956D46DE8}', +} + +#------------------------------------------------------------------------------ +# Helper functions + + +def MakeGuid(name, seed='msvs_new'): + """Returns a GUID for the specified target name. + + Args: + name: Target name. + seed: Seed for MD5 hash. + Returns: + A GUID-line string calculated from the name and seed. + + This generates something which looks like a GUID, but depends only on the + name and seed. This means the same name/seed will always generate the same + GUID, so that projects and solutions which refer to each other can explicitly + determine the GUID to refer to explicitly. It also means that the GUID will + not change when the project for a target is rebuilt. + """ + # Calculate a MD5 signature for the seed and name. + d = _new_md5(str(seed) + str(name)).hexdigest().upper() + # Convert most of the signature to GUID form (discard the rest) + guid = ('{' + d[:8] + '-' + d[8:12] + '-' + d[12:16] + '-' + d[16:20] + + '-' + d[20:32] + '}') + return guid + +#------------------------------------------------------------------------------ + + +class MSVSSolutionEntry(object): + def __cmp__(self, other): + # Sort by name then guid (so things are in order on vs2008). + return cmp((self.name, self.get_guid()), (other.name, other.get_guid())) + + +class MSVSFolder(MSVSSolutionEntry): + """Folder in a Visual Studio project or solution.""" + + def __init__(self, path, name = None, entries = None, + guid = None, items = None): + """Initializes the folder. + + Args: + path: Full path to the folder. + name: Name of the folder. + entries: List of folder entries to nest inside this folder. May contain + Folder or Project objects. May be None, if the folder is empty. + guid: GUID to use for folder, if not None. + items: List of solution items to include in the folder project. May be + None, if the folder does not directly contain items. + """ + if name: + self.name = name + else: + # Use last layer. + self.name = os.path.basename(path) + + self.path = path + self.guid = guid + + # Copy passed lists (or set to empty lists) + self.entries = sorted(list(entries or [])) + self.items = list(items or []) + + self.entry_type_guid = ENTRY_TYPE_GUIDS['folder'] + + def get_guid(self): + if self.guid is None: + # Use consistent guids for folders (so things don't regenerate). + self.guid = MakeGuid(self.path, seed='msvs_folder') + return self.guid + + +#------------------------------------------------------------------------------ + + +class MSVSProject(MSVSSolutionEntry): + """Visual Studio project.""" + + def __init__(self, path, name = None, dependencies = None, guid = None, + spec = None, build_file = None, config_platform_overrides = None, + fixpath_prefix = None): + """Initializes the project. + + Args: + path: Absolute path to the project file. + name: Name of project. If None, the name will be the same as the base + name of the project file. + dependencies: List of other Project objects this project is dependent + upon, if not None. + guid: GUID to use for project, if not None. + spec: Dictionary specifying how to build this project. + build_file: Filename of the .gyp file that the vcproj file comes from. + config_platform_overrides: optional dict of configuration platforms to + used in place of the default for this target. + fixpath_prefix: the path used to adjust the behavior of _fixpath + """ + self.path = path + self.guid = guid + self.spec = spec + self.build_file = build_file + # Use project filename if name not specified + self.name = name or os.path.splitext(os.path.basename(path))[0] + + # Copy passed lists (or set to empty lists) + self.dependencies = list(dependencies or []) + + self.entry_type_guid = ENTRY_TYPE_GUIDS['project'] + + if config_platform_overrides: + self.config_platform_overrides = config_platform_overrides + else: + self.config_platform_overrides = {} + self.fixpath_prefix = fixpath_prefix + self.msbuild_toolset = None + + def set_dependencies(self, dependencies): + self.dependencies = list(dependencies or []) + + def get_guid(self): + if self.guid is None: + # Set GUID from path + # TODO(rspangler): This is fragile. + # 1. We can't just use the project filename sans path, since there could + # be multiple projects with the same base name (for example, + # foo/unittest.vcproj and bar/unittest.vcproj). + # 2. The path needs to be relative to $SOURCE_ROOT, so that the project + # GUID is the same whether it's included from base/base.sln or + # foo/bar/baz/baz.sln. + # 3. The GUID needs to be the same each time this builder is invoked, so + # that we don't need to rebuild the solution when the project changes. + # 4. We should be able to handle pre-built project files by reading the + # GUID from the files. + self.guid = MakeGuid(self.name) + return self.guid + + def set_msbuild_toolset(self, msbuild_toolset): + self.msbuild_toolset = msbuild_toolset + +#------------------------------------------------------------------------------ + + +class MSVSSolution: + """Visual Studio solution.""" + + def __init__(self, path, version, entries=None, variants=None, + websiteProperties=True): + """Initializes the solution. + + Args: + path: Path to solution file. + version: Format version to emit. + entries: List of entries in solution. May contain Folder or Project + objects. May be None, if the folder is empty. + variants: List of build variant strings. If none, a default list will + be used. + websiteProperties: Flag to decide if the website properties section + is generated. + """ + self.path = path + self.websiteProperties = websiteProperties + self.version = version + + # Copy passed lists (or set to empty lists) + self.entries = list(entries or []) + + if variants: + # Copy passed list + self.variants = variants[:] + else: + # Use default + self.variants = ['Debug|Win32', 'Release|Win32'] + # TODO(rspangler): Need to be able to handle a mapping of solution config + # to project config. Should we be able to handle variants being a dict, + # or add a separate variant_map variable? If it's a dict, we can't + # guarantee the order of variants since dict keys aren't ordered. + + + # TODO(rspangler): Automatically write to disk for now; should delay until + # node-evaluation time. + self.Write() + + + def Write(self, writer=gyp.common.WriteOnDiff): + """Writes the solution file to disk. + + Raises: + IndexError: An entry appears multiple times. + """ + # Walk the entry tree and collect all the folders and projects. + all_entries = set() + entries_to_check = self.entries[:] + while entries_to_check: + e = entries_to_check.pop(0) + + # If this entry has been visited, nothing to do. + if e in all_entries: + continue + + all_entries.add(e) + + # If this is a folder, check its entries too. + if isinstance(e, MSVSFolder): + entries_to_check += e.entries + + all_entries = sorted(all_entries) + + # Open file and print header + f = writer(self.path) + f.write('Microsoft Visual Studio Solution File, ' + 'Format Version %s\r\n' % self.version.SolutionVersion()) + f.write('# %s\r\n' % self.version.Description()) + + # Project entries + sln_root = os.path.split(self.path)[0] + for e in all_entries: + relative_path = gyp.common.RelativePath(e.path, sln_root) + # msbuild does not accept an empty folder_name. + # use '.' in case relative_path is empty. + folder_name = relative_path.replace('/', '\\') or '.' + f.write('Project("%s") = "%s", "%s", "%s"\r\n' % ( + e.entry_type_guid, # Entry type GUID + e.name, # Folder name + folder_name, # Folder name (again) + e.get_guid(), # Entry GUID + )) + + # TODO(rspangler): Need a way to configure this stuff + if self.websiteProperties: + f.write('\tProjectSection(WebsiteProperties) = preProject\r\n' + '\t\tDebug.AspNetCompiler.Debug = "True"\r\n' + '\t\tRelease.AspNetCompiler.Debug = "False"\r\n' + '\tEndProjectSection\r\n') + + if isinstance(e, MSVSFolder): + if e.items: + f.write('\tProjectSection(SolutionItems) = preProject\r\n') + for i in e.items: + f.write('\t\t%s = %s\r\n' % (i, i)) + f.write('\tEndProjectSection\r\n') + + if isinstance(e, MSVSProject): + if e.dependencies: + f.write('\tProjectSection(ProjectDependencies) = postProject\r\n') + for d in e.dependencies: + f.write('\t\t%s = %s\r\n' % (d.get_guid(), d.get_guid())) + f.write('\tEndProjectSection\r\n') + + f.write('EndProject\r\n') + + # Global section + f.write('Global\r\n') + + # Configurations (variants) + f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n') + for v in self.variants: + f.write('\t\t%s = %s\r\n' % (v, v)) + f.write('\tEndGlobalSection\r\n') + + # Sort config guids for easier diffing of solution changes. + config_guids = [] + config_guids_overrides = {} + for e in all_entries: + if isinstance(e, MSVSProject): + config_guids.append(e.get_guid()) + config_guids_overrides[e.get_guid()] = e.config_platform_overrides + config_guids.sort() + + f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n') + for g in config_guids: + for v in self.variants: + nv = config_guids_overrides[g].get(v, v) + # Pick which project configuration to build for this solution + # configuration. + f.write('\t\t%s.%s.ActiveCfg = %s\r\n' % ( + g, # Project GUID + v, # Solution build configuration + nv, # Project build config for that solution config + )) + + # Enable project in this solution configuration. + f.write('\t\t%s.%s.Build.0 = %s\r\n' % ( + g, # Project GUID + v, # Solution build configuration + nv, # Project build config for that solution config + )) + f.write('\tEndGlobalSection\r\n') + + # TODO(rspangler): Should be able to configure this stuff too (though I've + # never seen this be any different) + f.write('\tGlobalSection(SolutionProperties) = preSolution\r\n') + f.write('\t\tHideSolutionNode = FALSE\r\n') + f.write('\tEndGlobalSection\r\n') + + # Folder mappings + # Omit this section if there are no folders + if any([e.entries for e in all_entries if isinstance(e, MSVSFolder)]): + f.write('\tGlobalSection(NestedProjects) = preSolution\r\n') + for e in all_entries: + if not isinstance(e, MSVSFolder): + continue # Does not apply to projects, only folders + for subentry in e.entries: + f.write('\t\t%s = %s\r\n' % (subentry.get_guid(), e.get_guid())) + f.write('\tEndGlobalSection\r\n') + + f.write('EndGlobal\r\n') + + f.close() diff --git a/deps/gyp/pylib/gyp/MSVSProject.py b/deps/gyp/pylib/gyp/MSVSProject.py new file mode 100644 index 000000000..db1ceede3 --- /dev/null +++ b/deps/gyp/pylib/gyp/MSVSProject.py @@ -0,0 +1,208 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Visual Studio project reader/writer.""" + +import gyp.common +import gyp.easy_xml as easy_xml + +#------------------------------------------------------------------------------ + + +class Tool(object): + """Visual Studio tool.""" + + def __init__(self, name, attrs=None): + """Initializes the tool. + + Args: + name: Tool name. + attrs: Dict of tool attributes; may be None. + """ + self._attrs = attrs or {} + self._attrs['Name'] = name + + def _GetSpecification(self): + """Creates an element for the tool. + + Returns: + A new xml.dom.Element for the tool. + """ + return ['Tool', self._attrs] + +class Filter(object): + """Visual Studio filter - that is, a virtual folder.""" + + def __init__(self, name, contents=None): + """Initializes the folder. + + Args: + name: Filter (folder) name. + contents: List of filenames and/or Filter objects contained. + """ + self.name = name + self.contents = list(contents or []) + + +#------------------------------------------------------------------------------ + + +class Writer(object): + """Visual Studio XML project writer.""" + + def __init__(self, project_path, version, name, guid=None, platforms=None): + """Initializes the project. + + Args: + project_path: Path to the project file. + version: Format version to emit. + name: Name of the project. + guid: GUID to use for project, if not None. + platforms: Array of string, the supported platforms. If null, ['Win32'] + """ + self.project_path = project_path + self.version = version + self.name = name + self.guid = guid + + # Default to Win32 for platforms. + if not platforms: + platforms = ['Win32'] + + # Initialize the specifications of the various sections. + self.platform_section = ['Platforms'] + for platform in platforms: + self.platform_section.append(['Platform', {'Name': platform}]) + self.tool_files_section = ['ToolFiles'] + self.configurations_section = ['Configurations'] + self.files_section = ['Files'] + + # Keep a dict keyed on filename to speed up access. + self.files_dict = dict() + + def AddToolFile(self, path): + """Adds a tool file to the project. + + Args: + path: Relative path from project to tool file. + """ + self.tool_files_section.append(['ToolFile', {'RelativePath': path}]) + + def _GetSpecForConfiguration(self, config_type, config_name, attrs, tools): + """Returns the specification for a configuration. + + Args: + config_type: Type of configuration node. + config_name: Configuration name. + attrs: Dict of configuration attributes; may be None. + tools: List of tools (strings or Tool objects); may be None. + Returns: + """ + # Handle defaults + if not attrs: + attrs = {} + if not tools: + tools = [] + + # Add configuration node and its attributes + node_attrs = attrs.copy() + node_attrs['Name'] = config_name + specification = [config_type, node_attrs] + + # Add tool nodes and their attributes + if tools: + for t in tools: + if isinstance(t, Tool): + specification.append(t._GetSpecification()) + else: + specification.append(Tool(t)._GetSpecification()) + return specification + + + def AddConfig(self, name, attrs=None, tools=None): + """Adds a configuration to the project. + + Args: + name: Configuration name. + attrs: Dict of configuration attributes; may be None. + tools: List of tools (strings or Tool objects); may be None. + """ + spec = self._GetSpecForConfiguration('Configuration', name, attrs, tools) + self.configurations_section.append(spec) + + def _AddFilesToNode(self, parent, files): + """Adds files and/or filters to the parent node. + + Args: + parent: Destination node + files: A list of Filter objects and/or relative paths to files. + + Will call itself recursively, if the files list contains Filter objects. + """ + for f in files: + if isinstance(f, Filter): + node = ['Filter', {'Name': f.name}] + self._AddFilesToNode(node, f.contents) + else: + node = ['File', {'RelativePath': f}] + self.files_dict[f] = node + parent.append(node) + + def AddFiles(self, files): + """Adds files to the project. + + Args: + files: A list of Filter objects and/or relative paths to files. + + This makes a copy of the file/filter tree at the time of this call. If you + later add files to a Filter object which was passed into a previous call + to AddFiles(), it will not be reflected in this project. + """ + self._AddFilesToNode(self.files_section, files) + # TODO(rspangler) This also doesn't handle adding files to an existing + # filter. That is, it doesn't merge the trees. + + def AddFileConfig(self, path, config, attrs=None, tools=None): + """Adds a configuration to a file. + + Args: + path: Relative path to the file. + config: Name of configuration to add. + attrs: Dict of configuration attributes; may be None. + tools: List of tools (strings or Tool objects); may be None. + + Raises: + ValueError: Relative path does not match any file added via AddFiles(). + """ + # Find the file node with the right relative path + parent = self.files_dict.get(path) + if not parent: + raise ValueError('AddFileConfig: file "%s" not in project.' % path) + + # Add the config to the file node + spec = self._GetSpecForConfiguration('FileConfiguration', config, attrs, + tools) + parent.append(spec) + + def WriteIfChanged(self): + """Writes the project file.""" + # First create XML content definition + content = [ + 'VisualStudioProject', + {'ProjectType': 'Visual C++', + 'Version': self.version.ProjectVersion(), + 'Name': self.name, + 'ProjectGUID': self.guid, + 'RootNamespace': self.name, + 'Keyword': 'Win32Proj' + }, + self.platform_section, + self.tool_files_section, + self.configurations_section, + ['References'], # empty section + self.files_section, + ['Globals'] # empty section + ] + easy_xml.WriteXmlIfChanged(content, self.project_path, + encoding="Windows-1252") diff --git a/deps/gyp/pylib/gyp/MSVSSettings.py b/deps/gyp/pylib/gyp/MSVSSettings.py new file mode 100644 index 000000000..205b3b5b9 --- /dev/null +++ b/deps/gyp/pylib/gyp/MSVSSettings.py @@ -0,0 +1,1078 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Code to validate and convert settings of the Microsoft build tools. + +This file contains code to validate and convert settings of the Microsoft +build tools. The function ConvertToMSBuildSettings(), ValidateMSVSSettings(), +and ValidateMSBuildSettings() are the entry points. + +This file was created by comparing the projects created by Visual Studio 2008 +and Visual Studio 2010 for all available settings through the user interface. +The MSBuild schemas were also considered. They are typically found in the +MSBuild install directory, e.g. c:\Program Files (x86)\MSBuild +""" + +import sys +import re + +# Dictionaries of settings validators. The key is the tool name, the value is +# a dictionary mapping setting names to validation functions. +_msvs_validators = {} +_msbuild_validators = {} + + +# A dictionary of settings converters. The key is the tool name, the value is +# a dictionary mapping setting names to conversion functions. +_msvs_to_msbuild_converters = {} + + +# Tool name mapping from MSVS to MSBuild. +_msbuild_name_of_tool = {} + + +class _Tool(object): + """Represents a tool used by MSVS or MSBuild. + + Attributes: + msvs_name: The name of the tool in MSVS. + msbuild_name: The name of the tool in MSBuild. + """ + + def __init__(self, msvs_name, msbuild_name): + self.msvs_name = msvs_name + self.msbuild_name = msbuild_name + + +def _AddTool(tool): + """Adds a tool to the four dictionaries used to process settings. + + This only defines the tool. Each setting also needs to be added. + + Args: + tool: The _Tool object to be added. + """ + _msvs_validators[tool.msvs_name] = {} + _msbuild_validators[tool.msbuild_name] = {} + _msvs_to_msbuild_converters[tool.msvs_name] = {} + _msbuild_name_of_tool[tool.msvs_name] = tool.msbuild_name + + +def _GetMSBuildToolSettings(msbuild_settings, tool): + """Returns an MSBuild tool dictionary. Creates it if needed.""" + return msbuild_settings.setdefault(tool.msbuild_name, {}) + + +class _Type(object): + """Type of settings (Base class).""" + + def ValidateMSVS(self, value): + """Verifies that the value is legal for MSVS. + + Args: + value: the value to check for this type. + + Raises: + ValueError if value is not valid for MSVS. + """ + + def ValidateMSBuild(self, value): + """Verifies that the value is legal for MSBuild. + + Args: + value: the value to check for this type. + + Raises: + ValueError if value is not valid for MSBuild. + """ + + def ConvertToMSBuild(self, value): + """Returns the MSBuild equivalent of the MSVS value given. + + Args: + value: the MSVS value to convert. + + Returns: + the MSBuild equivalent. + + Raises: + ValueError if value is not valid. + """ + return value + + +class _String(_Type): + """A setting that's just a string.""" + + def ValidateMSVS(self, value): + if not isinstance(value, basestring): + raise ValueError('expected string; got %r' % value) + + def ValidateMSBuild(self, value): + if not isinstance(value, basestring): + raise ValueError('expected string; got %r' % value) + + def ConvertToMSBuild(self, value): + # Convert the macros + return ConvertVCMacrosToMSBuild(value) + + +class _StringList(_Type): + """A settings that's a list of strings.""" + + def ValidateMSVS(self, value): + if not isinstance(value, basestring) and not isinstance(value, list): + raise ValueError('expected string list; got %r' % value) + + def ValidateMSBuild(self, value): + if not isinstance(value, basestring) and not isinstance(value, list): + raise ValueError('expected string list; got %r' % value) + + def ConvertToMSBuild(self, value): + # Convert the macros + if isinstance(value, list): + return [ConvertVCMacrosToMSBuild(i) for i in value] + else: + return ConvertVCMacrosToMSBuild(value) + + +class _Boolean(_Type): + """Boolean settings, can have the values 'false' or 'true'.""" + + def _Validate(self, value): + if value != 'true' and value != 'false': + raise ValueError('expected bool; got %r' % value) + + def ValidateMSVS(self, value): + self._Validate(value) + + def ValidateMSBuild(self, value): + self._Validate(value) + + def ConvertToMSBuild(self, value): + self._Validate(value) + return value + + +class _Integer(_Type): + """Integer settings.""" + + def __init__(self, msbuild_base=10): + _Type.__init__(self) + self._msbuild_base = msbuild_base + + def ValidateMSVS(self, value): + # Try to convert, this will raise ValueError if invalid. + self.ConvertToMSBuild(value) + + def ValidateMSBuild(self, value): + # Try to convert, this will raise ValueError if invalid. + int(value, self._msbuild_base) + + def ConvertToMSBuild(self, value): + msbuild_format = (self._msbuild_base == 10) and '%d' or '0x%04x' + return msbuild_format % int(value) + + +class _Enumeration(_Type): + """Type of settings that is an enumeration. + + In MSVS, the values are indexes like '0', '1', and '2'. + MSBuild uses text labels that are more representative, like 'Win32'. + + Constructor args: + label_list: an array of MSBuild labels that correspond to the MSVS index. + In the rare cases where MSVS has skipped an index value, None is + used in the array to indicate the unused spot. + new: an array of labels that are new to MSBuild. + """ + + def __init__(self, label_list, new=None): + _Type.__init__(self) + self._label_list = label_list + self._msbuild_values = set(value for value in label_list + if value is not None) + if new is not None: + self._msbuild_values.update(new) + + def ValidateMSVS(self, value): + # Try to convert. It will raise an exception if not valid. + self.ConvertToMSBuild(value) + + def ValidateMSBuild(self, value): + if value not in self._msbuild_values: + raise ValueError('unrecognized enumerated value %s' % value) + + def ConvertToMSBuild(self, value): + index = int(value) + if index < 0 or index >= len(self._label_list): + raise ValueError('index value (%d) not in expected range [0, %d)' % + (index, len(self._label_list))) + label = self._label_list[index] + if label is None: + raise ValueError('converted value for %s not specified.' % value) + return label + + +# Instantiate the various generic types. +_boolean = _Boolean() +_integer = _Integer() +# For now, we don't do any special validation on these types: +_string = _String() +_file_name = _String() +_folder_name = _String() +_file_list = _StringList() +_folder_list = _StringList() +_string_list = _StringList() +# Some boolean settings went from numerical values to boolean. The +# mapping is 0: default, 1: false, 2: true. +_newly_boolean = _Enumeration(['', 'false', 'true']) + + +def _Same(tool, name, setting_type): + """Defines a setting that has the same name in MSVS and MSBuild. + + Args: + tool: a dictionary that gives the names of the tool for MSVS and MSBuild. + name: the name of the setting. + setting_type: the type of this setting. + """ + _Renamed(tool, name, name, setting_type) + + +def _Renamed(tool, msvs_name, msbuild_name, setting_type): + """Defines a setting for which the name has changed. + + Args: + tool: a dictionary that gives the names of the tool for MSVS and MSBuild. + msvs_name: the name of the MSVS setting. + msbuild_name: the name of the MSBuild setting. + setting_type: the type of this setting. + """ + + def _Translate(value, msbuild_settings): + msbuild_tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool) + msbuild_tool_settings[msbuild_name] = setting_type.ConvertToMSBuild(value) + + _msvs_validators[tool.msvs_name][msvs_name] = setting_type.ValidateMSVS + _msbuild_validators[tool.msbuild_name][msbuild_name] = ( + setting_type.ValidateMSBuild) + _msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate + + +def _Moved(tool, settings_name, msbuild_tool_name, setting_type): + _MovedAndRenamed(tool, settings_name, msbuild_tool_name, settings_name, + setting_type) + + +def _MovedAndRenamed(tool, msvs_settings_name, msbuild_tool_name, + msbuild_settings_name, setting_type): + """Defines a setting that may have moved to a new section. + + Args: + tool: a dictionary that gives the names of the tool for MSVS and MSBuild. + msvs_settings_name: the MSVS name of the setting. + msbuild_tool_name: the name of the MSBuild tool to place the setting under. + msbuild_settings_name: the MSBuild name of the setting. + setting_type: the type of this setting. + """ + + def _Translate(value, msbuild_settings): + tool_settings = msbuild_settings.setdefault(msbuild_tool_name, {}) + tool_settings[msbuild_settings_name] = setting_type.ConvertToMSBuild(value) + + _msvs_validators[tool.msvs_name][msvs_settings_name] = ( + setting_type.ValidateMSVS) + validator = setting_type.ValidateMSBuild + _msbuild_validators[msbuild_tool_name][msbuild_settings_name] = validator + _msvs_to_msbuild_converters[tool.msvs_name][msvs_settings_name] = _Translate + + +def _MSVSOnly(tool, name, setting_type): + """Defines a setting that is only found in MSVS. + + Args: + tool: a dictionary that gives the names of the tool for MSVS and MSBuild. + name: the name of the setting. + setting_type: the type of this setting. + """ + + def _Translate(unused_value, unused_msbuild_settings): + # Since this is for MSVS only settings, no translation will happen. + pass + + _msvs_validators[tool.msvs_name][name] = setting_type.ValidateMSVS + _msvs_to_msbuild_converters[tool.msvs_name][name] = _Translate + + +def _MSBuildOnly(tool, name, setting_type): + """Defines a setting that is only found in MSBuild. + + Args: + tool: a dictionary that gives the names of the tool for MSVS and MSBuild. + name: the name of the setting. + setting_type: the type of this setting. + """ + _msbuild_validators[tool.msbuild_name][name] = setting_type.ValidateMSBuild + + +def _ConvertedToAdditionalOption(tool, msvs_name, flag): + """Defines a setting that's handled via a command line option in MSBuild. + + Args: + tool: a dictionary that gives the names of the tool for MSVS and MSBuild. + msvs_name: the name of the MSVS setting that if 'true' becomes a flag + flag: the flag to insert at the end of the AdditionalOptions + """ + + def _Translate(value, msbuild_settings): + if value == 'true': + tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool) + if 'AdditionalOptions' in tool_settings: + new_flags = '%s %s' % (tool_settings['AdditionalOptions'], flag) + else: + new_flags = flag + tool_settings['AdditionalOptions'] = new_flags + _msvs_validators[tool.msvs_name][msvs_name] = _boolean.ValidateMSVS + _msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate + + +def _CustomGeneratePreprocessedFile(tool, msvs_name): + def _Translate(value, msbuild_settings): + tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool) + if value == '0': + tool_settings['PreprocessToFile'] = 'false' + tool_settings['PreprocessSuppressLineNumbers'] = 'false' + elif value == '1': # /P + tool_settings['PreprocessToFile'] = 'true' + tool_settings['PreprocessSuppressLineNumbers'] = 'false' + elif value == '2': # /EP /P + tool_settings['PreprocessToFile'] = 'true' + tool_settings['PreprocessSuppressLineNumbers'] = 'true' + else: + raise ValueError('value must be one of [0, 1, 2]; got %s' % value) + # Create a bogus validator that looks for '0', '1', or '2' + msvs_validator = _Enumeration(['a', 'b', 'c']).ValidateMSVS + _msvs_validators[tool.msvs_name][msvs_name] = msvs_validator + msbuild_validator = _boolean.ValidateMSBuild + msbuild_tool_validators = _msbuild_validators[tool.msbuild_name] + msbuild_tool_validators['PreprocessToFile'] = msbuild_validator + msbuild_tool_validators['PreprocessSuppressLineNumbers'] = msbuild_validator + _msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate + + +fix_vc_macro_slashes_regex_list = ('IntDir', 'OutDir') +fix_vc_macro_slashes_regex = re.compile( + r'(\$\((?:%s)\))(?:[\\/]+)' % "|".join(fix_vc_macro_slashes_regex_list) +) + +# Regular expression to detect keys that were generated by exclusion lists +_EXCLUDED_SUFFIX_RE = re.compile('^(.*)_excluded$') + + +def _ValidateExclusionSetting(setting, settings, error_msg, stderr=sys.stderr): + """Verify that 'setting' is valid if it is generated from an exclusion list. + + If the setting appears to be generated from an exclusion list, the root name + is checked. + + Args: + setting: A string that is the setting name to validate + settings: A dictionary where the keys are valid settings + error_msg: The message to emit in the event of error + stderr: The stream receiving the error messages. + """ + # This may be unrecognized because it's an exclusion list. If the + # setting name has the _excluded suffix, then check the root name. + unrecognized = True + m = re.match(_EXCLUDED_SUFFIX_RE, setting) + if m: + root_setting = m.group(1) + unrecognized = root_setting not in settings + + if unrecognized: + # We don't know this setting. Give a warning. + print >> stderr, error_msg + + +def FixVCMacroSlashes(s): + """Replace macros which have excessive following slashes. + + These macros are known to have a built-in trailing slash. Furthermore, many + scripts hiccup on processing paths with extra slashes in the middle. + + This list is probably not exhaustive. Add as needed. + """ + if '$' in s: + s = fix_vc_macro_slashes_regex.sub(r'\1', s) + return s + + +def ConvertVCMacrosToMSBuild(s): + """Convert the the MSVS macros found in the string to the MSBuild equivalent. + + This list is probably not exhaustive. Add as needed. + """ + if '$' in s: + replace_map = { + '$(ConfigurationName)': '$(Configuration)', + '$(InputDir)': '%(RootDir)%(Directory)', + '$(InputExt)': '%(Extension)', + '$(InputFileName)': '%(Filename)%(Extension)', + '$(InputName)': '%(Filename)', + '$(InputPath)': '%(FullPath)', + '$(ParentName)': '$(ProjectFileName)', + '$(PlatformName)': '$(Platform)', + '$(SafeInputName)': '%(Filename)', + } + for old, new in replace_map.iteritems(): + s = s.replace(old, new) + s = FixVCMacroSlashes(s) + return s + + +def ConvertToMSBuildSettings(msvs_settings, stderr=sys.stderr): + """Converts MSVS settings (VS2008 and earlier) to MSBuild settings (VS2010+). + + Args: + msvs_settings: A dictionary. The key is the tool name. The values are + themselves dictionaries of settings and their values. + stderr: The stream receiving the error messages. + + Returns: + A dictionary of MSBuild settings. The key is either the MSBuild tool name + or the empty string (for the global settings). The values are themselves + dictionaries of settings and their values. + """ + msbuild_settings = {} + for msvs_tool_name, msvs_tool_settings in msvs_settings.iteritems(): + if msvs_tool_name in _msvs_to_msbuild_converters: + msvs_tool = _msvs_to_msbuild_converters[msvs_tool_name] + for msvs_setting, msvs_value in msvs_tool_settings.iteritems(): + if msvs_setting in msvs_tool: + # Invoke the translation function. + try: + msvs_tool[msvs_setting](msvs_value, msbuild_settings) + except ValueError, e: + print >> stderr, ('Warning: while converting %s/%s to MSBuild, ' + '%s' % (msvs_tool_name, msvs_setting, e)) + else: + _ValidateExclusionSetting(msvs_setting, + msvs_tool, + ('Warning: unrecognized setting %s/%s ' + 'while converting to MSBuild.' % + (msvs_tool_name, msvs_setting)), + stderr) + else: + print >> stderr, ('Warning: unrecognized tool %s while converting to ' + 'MSBuild.' % msvs_tool_name) + return msbuild_settings + + +def ValidateMSVSSettings(settings, stderr=sys.stderr): + """Validates that the names of the settings are valid for MSVS. + + Args: + settings: A dictionary. The key is the tool name. The values are + themselves dictionaries of settings and their values. + stderr: The stream receiving the error messages. + """ + _ValidateSettings(_msvs_validators, settings, stderr) + + +def ValidateMSBuildSettings(settings, stderr=sys.stderr): + """Validates that the names of the settings are valid for MSBuild. + + Args: + settings: A dictionary. The key is the tool name. The values are + themselves dictionaries of settings and their values. + stderr: The stream receiving the error messages. + """ + _ValidateSettings(_msbuild_validators, settings, stderr) + + +def _ValidateSettings(validators, settings, stderr): + """Validates that the settings are valid for MSBuild or MSVS. + + We currently only validate the names of the settings, not their values. + + Args: + validators: A dictionary of tools and their validators. + settings: A dictionary. The key is the tool name. The values are + themselves dictionaries of settings and their values. + stderr: The stream receiving the error messages. + """ + for tool_name in settings: + if tool_name in validators: + tool_validators = validators[tool_name] + for setting, value in settings[tool_name].iteritems(): + if setting in tool_validators: + try: + tool_validators[setting](value) + except ValueError, e: + print >> stderr, ('Warning: for %s/%s, %s' % + (tool_name, setting, e)) + else: + _ValidateExclusionSetting(setting, + tool_validators, + ('Warning: unrecognized setting %s/%s' % + (tool_name, setting)), + stderr) + + else: + print >> stderr, ('Warning: unrecognized tool %s' % tool_name) + + +# MSVS and MBuild names of the tools. +_compile = _Tool('VCCLCompilerTool', 'ClCompile') +_link = _Tool('VCLinkerTool', 'Link') +_midl = _Tool('VCMIDLTool', 'Midl') +_rc = _Tool('VCResourceCompilerTool', 'ResourceCompile') +_lib = _Tool('VCLibrarianTool', 'Lib') +_manifest = _Tool('VCManifestTool', 'Manifest') + + +_AddTool(_compile) +_AddTool(_link) +_AddTool(_midl) +_AddTool(_rc) +_AddTool(_lib) +_AddTool(_manifest) +# Add sections only found in the MSBuild settings. +_msbuild_validators[''] = {} +_msbuild_validators['ProjectReference'] = {} +_msbuild_validators['ManifestResourceCompile'] = {} + +# Descriptions of the compiler options, i.e. VCCLCompilerTool in MSVS and +# ClCompile in MSBuild. +# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\cl.xml" for +# the schema of the MSBuild ClCompile settings. + +# Options that have the same name in MSVS and MSBuild +_Same(_compile, 'AdditionalIncludeDirectories', _folder_list) # /I +_Same(_compile, 'AdditionalOptions', _string_list) +_Same(_compile, 'AdditionalUsingDirectories', _folder_list) # /AI +_Same(_compile, 'AssemblerListingLocation', _file_name) # /Fa +_Same(_compile, 'BrowseInformationFile', _file_name) +_Same(_compile, 'BufferSecurityCheck', _boolean) # /GS +_Same(_compile, 'DisableLanguageExtensions', _boolean) # /Za +_Same(_compile, 'DisableSpecificWarnings', _string_list) # /wd +_Same(_compile, 'EnableFiberSafeOptimizations', _boolean) # /GT +_Same(_compile, 'EnablePREfast', _boolean) # /analyze Visible='false' +_Same(_compile, 'ExpandAttributedSource', _boolean) # /Fx +_Same(_compile, 'FloatingPointExceptions', _boolean) # /fp:except +_Same(_compile, 'ForceConformanceInForLoopScope', _boolean) # /Zc:forScope +_Same(_compile, 'ForcedIncludeFiles', _file_list) # /FI +_Same(_compile, 'ForcedUsingFiles', _file_list) # /FU +_Same(_compile, 'GenerateXMLDocumentationFiles', _boolean) # /doc +_Same(_compile, 'IgnoreStandardIncludePath', _boolean) # /X +_Same(_compile, 'MinimalRebuild', _boolean) # /Gm +_Same(_compile, 'OmitDefaultLibName', _boolean) # /Zl +_Same(_compile, 'OmitFramePointers', _boolean) # /Oy +_Same(_compile, 'PreprocessorDefinitions', _string_list) # /D +_Same(_compile, 'ProgramDataBaseFileName', _file_name) # /Fd +_Same(_compile, 'RuntimeTypeInfo', _boolean) # /GR +_Same(_compile, 'ShowIncludes', _boolean) # /showIncludes +_Same(_compile, 'SmallerTypeCheck', _boolean) # /RTCc +_Same(_compile, 'StringPooling', _boolean) # /GF +_Same(_compile, 'SuppressStartupBanner', _boolean) # /nologo +_Same(_compile, 'TreatWChar_tAsBuiltInType', _boolean) # /Zc:wchar_t +_Same(_compile, 'UndefineAllPreprocessorDefinitions', _boolean) # /u +_Same(_compile, 'UndefinePreprocessorDefinitions', _string_list) # /U +_Same(_compile, 'UseFullPaths', _boolean) # /FC +_Same(_compile, 'WholeProgramOptimization', _boolean) # /GL +_Same(_compile, 'XMLDocumentationFileName', _file_name) + +_Same(_compile, 'AssemblerOutput', + _Enumeration(['NoListing', + 'AssemblyCode', # /FA + 'All', # /FAcs + 'AssemblyAndMachineCode', # /FAc + 'AssemblyAndSourceCode'])) # /FAs +_Same(_compile, 'BasicRuntimeChecks', + _Enumeration(['Default', + 'StackFrameRuntimeCheck', # /RTCs + 'UninitializedLocalUsageCheck', # /RTCu + 'EnableFastChecks'])) # /RTC1 +_Same(_compile, 'BrowseInformation', + _Enumeration(['false', + 'true', # /FR + 'true'])) # /Fr +_Same(_compile, 'CallingConvention', + _Enumeration(['Cdecl', # /Gd + 'FastCall', # /Gr + 'StdCall'])) # /Gz +_Same(_compile, 'CompileAs', + _Enumeration(['Default', + 'CompileAsC', # /TC + 'CompileAsCpp'])) # /TP +_Same(_compile, 'DebugInformationFormat', + _Enumeration(['', # Disabled + 'OldStyle', # /Z7 + None, + 'ProgramDatabase', # /Zi + 'EditAndContinue'])) # /ZI +_Same(_compile, 'EnableEnhancedInstructionSet', + _Enumeration(['NotSet', + 'StreamingSIMDExtensions', # /arch:SSE + 'StreamingSIMDExtensions2', # /arch:SSE2 + 'AdvancedVectorExtensions', # /arch:AVX (vs2012+) + 'NoExtensions',])) # /arch:IA32 (vs2012+) +_Same(_compile, 'ErrorReporting', + _Enumeration(['None', # /errorReport:none + 'Prompt', # /errorReport:prompt + 'Queue'], # /errorReport:queue + new=['Send'])) # /errorReport:send" +_Same(_compile, 'ExceptionHandling', + _Enumeration(['false', + 'Sync', # /EHsc + 'Async'], # /EHa + new=['SyncCThrow'])) # /EHs +_Same(_compile, 'FavorSizeOrSpeed', + _Enumeration(['Neither', + 'Speed', # /Ot + 'Size'])) # /Os +_Same(_compile, 'FloatingPointModel', + _Enumeration(['Precise', # /fp:precise + 'Strict', # /fp:strict + 'Fast'])) # /fp:fast +_Same(_compile, 'InlineFunctionExpansion', + _Enumeration(['Default', + 'OnlyExplicitInline', # /Ob1 + 'AnySuitable'], # /Ob2 + new=['Disabled'])) # /Ob0 +_Same(_compile, 'Optimization', + _Enumeration(['Disabled', # /Od + 'MinSpace', # /O1 + 'MaxSpeed', # /O2 + 'Full'])) # /Ox +_Same(_compile, 'RuntimeLibrary', + _Enumeration(['MultiThreaded', # /MT + 'MultiThreadedDebug', # /MTd + 'MultiThreadedDLL', # /MD + 'MultiThreadedDebugDLL'])) # /MDd +_Same(_compile, 'StructMemberAlignment', + _Enumeration(['Default', + '1Byte', # /Zp1 + '2Bytes', # /Zp2 + '4Bytes', # /Zp4 + '8Bytes', # /Zp8 + '16Bytes'])) # /Zp16 +_Same(_compile, 'WarningLevel', + _Enumeration(['TurnOffAllWarnings', # /W0 + 'Level1', # /W1 + 'Level2', # /W2 + 'Level3', # /W3 + 'Level4'], # /W4 + new=['EnableAllWarnings'])) # /Wall + +# Options found in MSVS that have been renamed in MSBuild. +_Renamed(_compile, 'EnableFunctionLevelLinking', 'FunctionLevelLinking', + _boolean) # /Gy +_Renamed(_compile, 'EnableIntrinsicFunctions', 'IntrinsicFunctions', + _boolean) # /Oi +_Renamed(_compile, 'KeepComments', 'PreprocessKeepComments', _boolean) # /C +_Renamed(_compile, 'ObjectFile', 'ObjectFileName', _file_name) # /Fo +_Renamed(_compile, 'OpenMP', 'OpenMPSupport', _boolean) # /openmp +_Renamed(_compile, 'PrecompiledHeaderThrough', 'PrecompiledHeaderFile', + _file_name) # Used with /Yc and /Yu +_Renamed(_compile, 'PrecompiledHeaderFile', 'PrecompiledHeaderOutputFile', + _file_name) # /Fp +_Renamed(_compile, 'UsePrecompiledHeader', 'PrecompiledHeader', + _Enumeration(['NotUsing', # VS recognized '' for this value too. + 'Create', # /Yc + 'Use'])) # /Yu +_Renamed(_compile, 'WarnAsError', 'TreatWarningAsError', _boolean) # /WX + +_ConvertedToAdditionalOption(_compile, 'DefaultCharIsUnsigned', '/J') + +# MSVS options not found in MSBuild. +_MSVSOnly(_compile, 'Detect64BitPortabilityProblems', _boolean) +_MSVSOnly(_compile, 'UseUnicodeResponseFiles', _boolean) + +# MSBuild options not found in MSVS. +_MSBuildOnly(_compile, 'BuildingInIDE', _boolean) +_MSBuildOnly(_compile, 'CompileAsManaged', + _Enumeration([], new=['false', + 'true', # /clr + 'Pure', # /clr:pure + 'Safe', # /clr:safe + 'OldSyntax'])) # /clr:oldSyntax +_MSBuildOnly(_compile, 'CreateHotpatchableImage', _boolean) # /hotpatch +_MSBuildOnly(_compile, 'MultiProcessorCompilation', _boolean) # /MP +_MSBuildOnly(_compile, 'PreprocessOutputPath', _string) # /Fi +_MSBuildOnly(_compile, 'ProcessorNumber', _integer) # the number of processors +_MSBuildOnly(_compile, 'TrackerLogDirectory', _folder_name) +_MSBuildOnly(_compile, 'TreatSpecificWarningsAsErrors', _string_list) # /we +_MSBuildOnly(_compile, 'UseUnicodeForAssemblerListing', _boolean) # /FAu + +# Defines a setting that needs very customized processing +_CustomGeneratePreprocessedFile(_compile, 'GeneratePreprocessedFile') + + +# Directives for converting MSVS VCLinkerTool to MSBuild Link. +# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\link.xml" for +# the schema of the MSBuild Link settings. + +# Options that have the same name in MSVS and MSBuild +_Same(_link, 'AdditionalDependencies', _file_list) +_Same(_link, 'AdditionalLibraryDirectories', _folder_list) # /LIBPATH +# /MANIFESTDEPENDENCY: +_Same(_link, 'AdditionalManifestDependencies', _file_list) +_Same(_link, 'AdditionalOptions', _string_list) +_Same(_link, 'AddModuleNamesToAssembly', _file_list) # /ASSEMBLYMODULE +_Same(_link, 'AllowIsolation', _boolean) # /ALLOWISOLATION +_Same(_link, 'AssemblyLinkResource', _file_list) # /ASSEMBLYLINKRESOURCE +_Same(_link, 'BaseAddress', _string) # /BASE +_Same(_link, 'CLRUnmanagedCodeCheck', _boolean) # /CLRUNMANAGEDCODECHECK +_Same(_link, 'DelayLoadDLLs', _file_list) # /DELAYLOAD +_Same(_link, 'DelaySign', _boolean) # /DELAYSIGN +_Same(_link, 'EmbedManagedResourceFile', _file_list) # /ASSEMBLYRESOURCE +_Same(_link, 'EnableUAC', _boolean) # /MANIFESTUAC +_Same(_link, 'EntryPointSymbol', _string) # /ENTRY +_Same(_link, 'ForceSymbolReferences', _file_list) # /INCLUDE +_Same(_link, 'FunctionOrder', _file_name) # /ORDER +_Same(_link, 'GenerateDebugInformation', _boolean) # /DEBUG +_Same(_link, 'GenerateMapFile', _boolean) # /MAP +_Same(_link, 'HeapCommitSize', _string) +_Same(_link, 'HeapReserveSize', _string) # /HEAP +_Same(_link, 'IgnoreAllDefaultLibraries', _boolean) # /NODEFAULTLIB +_Same(_link, 'IgnoreEmbeddedIDL', _boolean) # /IGNOREIDL +_Same(_link, 'ImportLibrary', _file_name) # /IMPLIB +_Same(_link, 'KeyContainer', _file_name) # /KEYCONTAINER +_Same(_link, 'KeyFile', _file_name) # /KEYFILE +_Same(_link, 'ManifestFile', _file_name) # /ManifestFile +_Same(_link, 'MapExports', _boolean) # /MAPINFO:EXPORTS +_Same(_link, 'MapFileName', _file_name) +_Same(_link, 'MergedIDLBaseFileName', _file_name) # /IDLOUT +_Same(_link, 'MergeSections', _string) # /MERGE +_Same(_link, 'MidlCommandFile', _file_name) # /MIDL +_Same(_link, 'ModuleDefinitionFile', _file_name) # /DEF +_Same(_link, 'OutputFile', _file_name) # /OUT +_Same(_link, 'PerUserRedirection', _boolean) +_Same(_link, 'Profile', _boolean) # /PROFILE +_Same(_link, 'ProfileGuidedDatabase', _file_name) # /PGD +_Same(_link, 'ProgramDatabaseFile', _file_name) # /PDB +_Same(_link, 'RegisterOutput', _boolean) +_Same(_link, 'SetChecksum', _boolean) # /RELEASE +_Same(_link, 'StackCommitSize', _string) +_Same(_link, 'StackReserveSize', _string) # /STACK +_Same(_link, 'StripPrivateSymbols', _file_name) # /PDBSTRIPPED +_Same(_link, 'SupportUnloadOfDelayLoadedDLL', _boolean) # /DELAY:UNLOAD +_Same(_link, 'SuppressStartupBanner', _boolean) # /NOLOGO +_Same(_link, 'SwapRunFromCD', _boolean) # /SWAPRUN:CD +_Same(_link, 'TurnOffAssemblyGeneration', _boolean) # /NOASSEMBLY +_Same(_link, 'TypeLibraryFile', _file_name) # /TLBOUT +_Same(_link, 'TypeLibraryResourceID', _integer) # /TLBID +_Same(_link, 'UACUIAccess', _boolean) # /uiAccess='true' +_Same(_link, 'Version', _string) # /VERSION + +_Same(_link, 'EnableCOMDATFolding', _newly_boolean) # /OPT:ICF +_Same(_link, 'FixedBaseAddress', _newly_boolean) # /FIXED +_Same(_link, 'LargeAddressAware', _newly_boolean) # /LARGEADDRESSAWARE +_Same(_link, 'OptimizeReferences', _newly_boolean) # /OPT:REF +_Same(_link, 'RandomizedBaseAddress', _newly_boolean) # /DYNAMICBASE +_Same(_link, 'TerminalServerAware', _newly_boolean) # /TSAWARE + +_subsystem_enumeration = _Enumeration( + ['NotSet', + 'Console', # /SUBSYSTEM:CONSOLE + 'Windows', # /SUBSYSTEM:WINDOWS + 'Native', # /SUBSYSTEM:NATIVE + 'EFI Application', # /SUBSYSTEM:EFI_APPLICATION + 'EFI Boot Service Driver', # /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER + 'EFI ROM', # /SUBSYSTEM:EFI_ROM + 'EFI Runtime', # /SUBSYSTEM:EFI_RUNTIME_DRIVER + 'WindowsCE'], # /SUBSYSTEM:WINDOWSCE + new=['POSIX']) # /SUBSYSTEM:POSIX + +_target_machine_enumeration = _Enumeration( + ['NotSet', + 'MachineX86', # /MACHINE:X86 + None, + 'MachineARM', # /MACHINE:ARM + 'MachineEBC', # /MACHINE:EBC + 'MachineIA64', # /MACHINE:IA64 + None, + 'MachineMIPS', # /MACHINE:MIPS + 'MachineMIPS16', # /MACHINE:MIPS16 + 'MachineMIPSFPU', # /MACHINE:MIPSFPU + 'MachineMIPSFPU16', # /MACHINE:MIPSFPU16 + None, + None, + None, + 'MachineSH4', # /MACHINE:SH4 + None, + 'MachineTHUMB', # /MACHINE:THUMB + 'MachineX64']) # /MACHINE:X64 + +_Same(_link, 'AssemblyDebug', + _Enumeration(['', + 'true', # /ASSEMBLYDEBUG + 'false'])) # /ASSEMBLYDEBUG:DISABLE +_Same(_link, 'CLRImageType', + _Enumeration(['Default', + 'ForceIJWImage', # /CLRIMAGETYPE:IJW + 'ForcePureILImage', # /Switch="CLRIMAGETYPE:PURE + 'ForceSafeILImage'])) # /Switch="CLRIMAGETYPE:SAFE +_Same(_link, 'CLRThreadAttribute', + _Enumeration(['DefaultThreadingAttribute', # /CLRTHREADATTRIBUTE:NONE + 'MTAThreadingAttribute', # /CLRTHREADATTRIBUTE:MTA + 'STAThreadingAttribute'])) # /CLRTHREADATTRIBUTE:STA +_Same(_link, 'DataExecutionPrevention', + _Enumeration(['', + 'false', # /NXCOMPAT:NO + 'true'])) # /NXCOMPAT +_Same(_link, 'Driver', + _Enumeration(['NotSet', + 'Driver', # /Driver + 'UpOnly', # /DRIVER:UPONLY + 'WDM'])) # /DRIVER:WDM +_Same(_link, 'LinkTimeCodeGeneration', + _Enumeration(['Default', + 'UseLinkTimeCodeGeneration', # /LTCG + 'PGInstrument', # /LTCG:PGInstrument + 'PGOptimization', # /LTCG:PGOptimize + 'PGUpdate'])) # /LTCG:PGUpdate +_Same(_link, 'ShowProgress', + _Enumeration(['NotSet', + 'LinkVerbose', # /VERBOSE + 'LinkVerboseLib'], # /VERBOSE:Lib + new=['LinkVerboseICF', # /VERBOSE:ICF + 'LinkVerboseREF', # /VERBOSE:REF + 'LinkVerboseSAFESEH', # /VERBOSE:SAFESEH + 'LinkVerboseCLR'])) # /VERBOSE:CLR +_Same(_link, 'SubSystem', _subsystem_enumeration) +_Same(_link, 'TargetMachine', _target_machine_enumeration) +_Same(_link, 'UACExecutionLevel', + _Enumeration(['AsInvoker', # /level='asInvoker' + 'HighestAvailable', # /level='highestAvailable' + 'RequireAdministrator'])) # /level='requireAdministrator' +_Same(_link, 'MinimumRequiredVersion', _string) +_Same(_link, 'TreatLinkerWarningAsErrors', _boolean) # /WX + + +# Options found in MSVS that have been renamed in MSBuild. +_Renamed(_link, 'ErrorReporting', 'LinkErrorReporting', + _Enumeration(['NoErrorReport', # /ERRORREPORT:NONE + 'PromptImmediately', # /ERRORREPORT:PROMPT + 'QueueForNextLogin'], # /ERRORREPORT:QUEUE + new=['SendErrorReport'])) # /ERRORREPORT:SEND +_Renamed(_link, 'IgnoreDefaultLibraryNames', 'IgnoreSpecificDefaultLibraries', + _file_list) # /NODEFAULTLIB +_Renamed(_link, 'ResourceOnlyDLL', 'NoEntryPoint', _boolean) # /NOENTRY +_Renamed(_link, 'SwapRunFromNet', 'SwapRunFromNET', _boolean) # /SWAPRUN:NET + +_Moved(_link, 'GenerateManifest', '', _boolean) +_Moved(_link, 'IgnoreImportLibrary', '', _boolean) +_Moved(_link, 'LinkIncremental', '', _newly_boolean) +_Moved(_link, 'LinkLibraryDependencies', 'ProjectReference', _boolean) +_Moved(_link, 'UseLibraryDependencyInputs', 'ProjectReference', _boolean) + +# MSVS options not found in MSBuild. +_MSVSOnly(_link, 'OptimizeForWindows98', _newly_boolean) +_MSVSOnly(_link, 'UseUnicodeResponseFiles', _boolean) + +# MSBuild options not found in MSVS. +_MSBuildOnly(_link, 'BuildingInIDE', _boolean) +_MSBuildOnly(_link, 'ImageHasSafeExceptionHandlers', _boolean) # /SAFESEH +_MSBuildOnly(_link, 'LinkDLL', _boolean) # /DLL Visible='false' +_MSBuildOnly(_link, 'LinkStatus', _boolean) # /LTCG:STATUS +_MSBuildOnly(_link, 'PreventDllBinding', _boolean) # /ALLOWBIND +_MSBuildOnly(_link, 'SupportNobindOfDelayLoadedDLL', _boolean) # /DELAY:NOBIND +_MSBuildOnly(_link, 'TrackerLogDirectory', _folder_name) +_MSBuildOnly(_link, 'MSDOSStubFileName', _file_name) # /STUB Visible='false' +_MSBuildOnly(_link, 'SectionAlignment', _integer) # /ALIGN +_MSBuildOnly(_link, 'SpecifySectionAttributes', _string) # /SECTION +_MSBuildOnly(_link, 'ForceFileOutput', + _Enumeration([], new=['Enabled', # /FORCE + # /FORCE:MULTIPLE + 'MultiplyDefinedSymbolOnly', + 'UndefinedSymbolOnly'])) # /FORCE:UNRESOLVED +_MSBuildOnly(_link, 'CreateHotPatchableImage', + _Enumeration([], new=['Enabled', # /FUNCTIONPADMIN + 'X86Image', # /FUNCTIONPADMIN:5 + 'X64Image', # /FUNCTIONPADMIN:6 + 'ItaniumImage'])) # /FUNCTIONPADMIN:16 +_MSBuildOnly(_link, 'CLRSupportLastError', + _Enumeration([], new=['Enabled', # /CLRSupportLastError + 'Disabled', # /CLRSupportLastError:NO + # /CLRSupportLastError:SYSTEMDLL + 'SystemDlls'])) + + +# Directives for converting VCResourceCompilerTool to ResourceCompile. +# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\rc.xml" for +# the schema of the MSBuild ResourceCompile settings. + +_Same(_rc, 'AdditionalOptions', _string_list) +_Same(_rc, 'AdditionalIncludeDirectories', _folder_list) # /I +_Same(_rc, 'Culture', _Integer(msbuild_base=16)) +_Same(_rc, 'IgnoreStandardIncludePath', _boolean) # /X +_Same(_rc, 'PreprocessorDefinitions', _string_list) # /D +_Same(_rc, 'ResourceOutputFileName', _string) # /fo +_Same(_rc, 'ShowProgress', _boolean) # /v +# There is no UI in VisualStudio 2008 to set the following properties. +# However they are found in CL and other tools. Include them here for +# completeness, as they are very likely to have the same usage pattern. +_Same(_rc, 'SuppressStartupBanner', _boolean) # /nologo +_Same(_rc, 'UndefinePreprocessorDefinitions', _string_list) # /u + +# MSBuild options not found in MSVS. +_MSBuildOnly(_rc, 'NullTerminateStrings', _boolean) # /n +_MSBuildOnly(_rc, 'TrackerLogDirectory', _folder_name) + + +# Directives for converting VCMIDLTool to Midl. +# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\midl.xml" for +# the schema of the MSBuild Midl settings. + +_Same(_midl, 'AdditionalIncludeDirectories', _folder_list) # /I +_Same(_midl, 'AdditionalOptions', _string_list) +_Same(_midl, 'CPreprocessOptions', _string) # /cpp_opt +_Same(_midl, 'ErrorCheckAllocations', _boolean) # /error allocation +_Same(_midl, 'ErrorCheckBounds', _boolean) # /error bounds_check +_Same(_midl, 'ErrorCheckEnumRange', _boolean) # /error enum +_Same(_midl, 'ErrorCheckRefPointers', _boolean) # /error ref +_Same(_midl, 'ErrorCheckStubData', _boolean) # /error stub_data +_Same(_midl, 'GenerateStublessProxies', _boolean) # /Oicf +_Same(_midl, 'GenerateTypeLibrary', _boolean) +_Same(_midl, 'HeaderFileName', _file_name) # /h +_Same(_midl, 'IgnoreStandardIncludePath', _boolean) # /no_def_idir +_Same(_midl, 'InterfaceIdentifierFileName', _file_name) # /iid +_Same(_midl, 'MkTypLibCompatible', _boolean) # /mktyplib203 +_Same(_midl, 'OutputDirectory', _string) # /out +_Same(_midl, 'PreprocessorDefinitions', _string_list) # /D +_Same(_midl, 'ProxyFileName', _file_name) # /proxy +_Same(_midl, 'RedirectOutputAndErrors', _file_name) # /o +_Same(_midl, 'SuppressStartupBanner', _boolean) # /nologo +_Same(_midl, 'TypeLibraryName', _file_name) # /tlb +_Same(_midl, 'UndefinePreprocessorDefinitions', _string_list) # /U +_Same(_midl, 'WarnAsError', _boolean) # /WX + +_Same(_midl, 'DefaultCharType', + _Enumeration(['Unsigned', # /char unsigned + 'Signed', # /char signed + 'Ascii'])) # /char ascii7 +_Same(_midl, 'TargetEnvironment', + _Enumeration(['NotSet', + 'Win32', # /env win32 + 'Itanium', # /env ia64 + 'X64'])) # /env x64 +_Same(_midl, 'EnableErrorChecks', + _Enumeration(['EnableCustom', + 'None', # /error none + 'All'])) # /error all +_Same(_midl, 'StructMemberAlignment', + _Enumeration(['NotSet', + '1', # Zp1 + '2', # Zp2 + '4', # Zp4 + '8'])) # Zp8 +_Same(_midl, 'WarningLevel', + _Enumeration(['0', # /W0 + '1', # /W1 + '2', # /W2 + '3', # /W3 + '4'])) # /W4 + +_Renamed(_midl, 'DLLDataFileName', 'DllDataFileName', _file_name) # /dlldata +_Renamed(_midl, 'ValidateParameters', 'ValidateAllParameters', + _boolean) # /robust + +# MSBuild options not found in MSVS. +_MSBuildOnly(_midl, 'ApplicationConfigurationMode', _boolean) # /app_config +_MSBuildOnly(_midl, 'ClientStubFile', _file_name) # /cstub +_MSBuildOnly(_midl, 'GenerateClientFiles', + _Enumeration([], new=['Stub', # /client stub + 'None'])) # /client none +_MSBuildOnly(_midl, 'GenerateServerFiles', + _Enumeration([], new=['Stub', # /client stub + 'None'])) # /client none +_MSBuildOnly(_midl, 'LocaleID', _integer) # /lcid DECIMAL +_MSBuildOnly(_midl, 'ServerStubFile', _file_name) # /sstub +_MSBuildOnly(_midl, 'SuppressCompilerWarnings', _boolean) # /no_warn +_MSBuildOnly(_midl, 'TrackerLogDirectory', _folder_name) +_MSBuildOnly(_midl, 'TypeLibFormat', + _Enumeration([], new=['NewFormat', # /newtlb + 'OldFormat'])) # /oldtlb + + +# Directives for converting VCLibrarianTool to Lib. +# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\lib.xml" for +# the schema of the MSBuild Lib settings. + +_Same(_lib, 'AdditionalDependencies', _file_list) +_Same(_lib, 'AdditionalLibraryDirectories', _folder_list) # /LIBPATH +_Same(_lib, 'AdditionalOptions', _string_list) +_Same(_lib, 'ExportNamedFunctions', _string_list) # /EXPORT +_Same(_lib, 'ForceSymbolReferences', _string) # /INCLUDE +_Same(_lib, 'IgnoreAllDefaultLibraries', _boolean) # /NODEFAULTLIB +_Same(_lib, 'IgnoreSpecificDefaultLibraries', _file_list) # /NODEFAULTLIB +_Same(_lib, 'ModuleDefinitionFile', _file_name) # /DEF +_Same(_lib, 'OutputFile', _file_name) # /OUT +_Same(_lib, 'SuppressStartupBanner', _boolean) # /NOLOGO +_Same(_lib, 'UseUnicodeResponseFiles', _boolean) +_Same(_lib, 'LinkTimeCodeGeneration', _boolean) # /LTCG +_Same(_lib, 'TargetMachine', _target_machine_enumeration) + +# TODO(jeanluc) _link defines the same value that gets moved to +# ProjectReference. We may want to validate that they are consistent. +_Moved(_lib, 'LinkLibraryDependencies', 'ProjectReference', _boolean) + +_MSBuildOnly(_lib, 'DisplayLibrary', _string) # /LIST Visible='false' +_MSBuildOnly(_lib, 'ErrorReporting', + _Enumeration([], new=['PromptImmediately', # /ERRORREPORT:PROMPT + 'QueueForNextLogin', # /ERRORREPORT:QUEUE + 'SendErrorReport', # /ERRORREPORT:SEND + 'NoErrorReport'])) # /ERRORREPORT:NONE +_MSBuildOnly(_lib, 'MinimumRequiredVersion', _string) +_MSBuildOnly(_lib, 'Name', _file_name) # /NAME +_MSBuildOnly(_lib, 'RemoveObjects', _file_list) # /REMOVE +_MSBuildOnly(_lib, 'SubSystem', _subsystem_enumeration) +_MSBuildOnly(_lib, 'TrackerLogDirectory', _folder_name) +_MSBuildOnly(_lib, 'TreatLibWarningAsErrors', _boolean) # /WX +_MSBuildOnly(_lib, 'Verbose', _boolean) + + +# Directives for converting VCManifestTool to Mt. +# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\mt.xml" for +# the schema of the MSBuild Lib settings. + +# Options that have the same name in MSVS and MSBuild +_Same(_manifest, 'AdditionalManifestFiles', _file_list) # /manifest +_Same(_manifest, 'AdditionalOptions', _string_list) +_Same(_manifest, 'AssemblyIdentity', _string) # /identity: +_Same(_manifest, 'ComponentFileName', _file_name) # /dll +_Same(_manifest, 'GenerateCatalogFiles', _boolean) # /makecdfs +_Same(_manifest, 'InputResourceManifests', _string) # /inputresource +_Same(_manifest, 'OutputManifestFile', _file_name) # /out +_Same(_manifest, 'RegistrarScriptFile', _file_name) # /rgs +_Same(_manifest, 'ReplacementsFile', _file_name) # /replacements +_Same(_manifest, 'SuppressStartupBanner', _boolean) # /nologo +_Same(_manifest, 'TypeLibraryFile', _file_name) # /tlb: +_Same(_manifest, 'UpdateFileHashes', _boolean) # /hashupdate +_Same(_manifest, 'UpdateFileHashesSearchPath', _file_name) +_Same(_manifest, 'VerboseOutput', _boolean) # /verbose + +# Options that have moved location. +_MovedAndRenamed(_manifest, 'ManifestResourceFile', + 'ManifestResourceCompile', + 'ResourceOutputFileName', + _file_name) +_Moved(_manifest, 'EmbedManifest', '', _boolean) + +# MSVS options not found in MSBuild. +_MSVSOnly(_manifest, 'DependencyInformationFile', _file_name) +_MSVSOnly(_manifest, 'UseFAT32Workaround', _boolean) +_MSVSOnly(_manifest, 'UseUnicodeResponseFiles', _boolean) + +# MSBuild options not found in MSVS. +_MSBuildOnly(_manifest, 'EnableDPIAwareness', _boolean) +_MSBuildOnly(_manifest, 'GenerateCategoryTags', _boolean) # /category +_MSBuildOnly(_manifest, 'ManifestFromManagedAssembly', + _file_name) # /managedassemblyname +_MSBuildOnly(_manifest, 'OutputResourceManifests', _string) # /outputresource +_MSBuildOnly(_manifest, 'SuppressDependencyElement', _boolean) # /nodependency +_MSBuildOnly(_manifest, 'TrackerLogDirectory', _folder_name) diff --git a/deps/gyp/pylib/gyp/MSVSSettings_test.py b/deps/gyp/pylib/gyp/MSVSSettings_test.py new file mode 100755 index 000000000..9bd37ec34 --- /dev/null +++ b/deps/gyp/pylib/gyp/MSVSSettings_test.py @@ -0,0 +1,1483 @@ +#!/usr/bin/env python + +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Unit tests for the MSVSSettings.py file.""" + +import StringIO +import unittest +import gyp.MSVSSettings as MSVSSettings + + +class TestSequenceFunctions(unittest.TestCase): + + def setUp(self): + self.stderr = StringIO.StringIO() + + def _ExpectedWarnings(self, expected): + """Compares recorded lines to expected warnings.""" + self.stderr.seek(0) + actual = self.stderr.read().split('\n') + actual = [line for line in actual if line] + self.assertEqual(sorted(expected), sorted(actual)) + + def testValidateMSVSSettings_tool_names(self): + """Tests that only MSVS tool names are allowed.""" + MSVSSettings.ValidateMSVSSettings( + {'VCCLCompilerTool': {}, + 'VCLinkerTool': {}, + 'VCMIDLTool': {}, + 'foo': {}, + 'VCResourceCompilerTool': {}, + 'VCLibrarianTool': {}, + 'VCManifestTool': {}, + 'ClCompile': {}}, + self.stderr) + self._ExpectedWarnings([ + 'Warning: unrecognized tool foo', + 'Warning: unrecognized tool ClCompile']) + + def testValidateMSVSSettings_settings(self): + """Tests that for invalid MSVS settings.""" + MSVSSettings.ValidateMSVSSettings( + {'VCCLCompilerTool': { + 'AdditionalIncludeDirectories': 'folder1;folder2', + 'AdditionalOptions': ['string1', 'string2'], + 'AdditionalUsingDirectories': 'folder1;folder2', + 'AssemblerListingLocation': 'a_file_name', + 'AssemblerOutput': '0', + 'BasicRuntimeChecks': '5', + 'BrowseInformation': 'fdkslj', + 'BrowseInformationFile': 'a_file_name', + 'BufferSecurityCheck': 'true', + 'CallingConvention': '-1', + 'CompileAs': '1', + 'DebugInformationFormat': '2', + 'DefaultCharIsUnsigned': 'true', + 'Detect64BitPortabilityProblems': 'true', + 'DisableLanguageExtensions': 'true', + 'DisableSpecificWarnings': 'string1;string2', + 'EnableEnhancedInstructionSet': '1', + 'EnableFiberSafeOptimizations': 'true', + 'EnableFunctionLevelLinking': 'true', + 'EnableIntrinsicFunctions': 'true', + 'EnablePREfast': 'true', + 'Enableprefast': 'bogus', + 'ErrorReporting': '1', + 'ExceptionHandling': '1', + 'ExpandAttributedSource': 'true', + 'FavorSizeOrSpeed': '1', + 'FloatingPointExceptions': 'true', + 'FloatingPointModel': '1', + 'ForceConformanceInForLoopScope': 'true', + 'ForcedIncludeFiles': 'file1;file2', + 'ForcedUsingFiles': 'file1;file2', + 'GeneratePreprocessedFile': '1', + 'GenerateXMLDocumentationFiles': 'true', + 'IgnoreStandardIncludePath': 'true', + 'InlineFunctionExpansion': '1', + 'KeepComments': 'true', + 'MinimalRebuild': 'true', + 'ObjectFile': 'a_file_name', + 'OmitDefaultLibName': 'true', + 'OmitFramePointers': 'true', + 'OpenMP': 'true', + 'Optimization': '1', + 'PrecompiledHeaderFile': 'a_file_name', + 'PrecompiledHeaderThrough': 'a_file_name', + 'PreprocessorDefinitions': 'string1;string2', + 'ProgramDataBaseFileName': 'a_file_name', + 'RuntimeLibrary': '1', + 'RuntimeTypeInfo': 'true', + 'ShowIncludes': 'true', + 'SmallerTypeCheck': 'true', + 'StringPooling': 'true', + 'StructMemberAlignment': '1', + 'SuppressStartupBanner': 'true', + 'TreatWChar_tAsBuiltInType': 'true', + 'UndefineAllPreprocessorDefinitions': 'true', + 'UndefinePreprocessorDefinitions': 'string1;string2', + 'UseFullPaths': 'true', + 'UsePrecompiledHeader': '1', + 'UseUnicodeResponseFiles': 'true', + 'WarnAsError': 'true', + 'WarningLevel': '1', + 'WholeProgramOptimization': 'true', + 'XMLDocumentationFileName': 'a_file_name', + 'ZZXYZ': 'bogus'}, + 'VCLinkerTool': { + 'AdditionalDependencies': 'file1;file2', + 'AdditionalDependencies_excluded': 'file3', + 'AdditionalLibraryDirectories': 'folder1;folder2', + 'AdditionalManifestDependencies': 'file1;file2', + 'AdditionalOptions': 'a string1', + 'AddModuleNamesToAssembly': 'file1;file2', + 'AllowIsolation': 'true', + 'AssemblyDebug': '2', + 'AssemblyLinkResource': 'file1;file2', + 'BaseAddress': 'a string1', + 'CLRImageType': '2', + 'CLRThreadAttribute': '2', + 'CLRUnmanagedCodeCheck': 'true', + 'DataExecutionPrevention': '2', + 'DelayLoadDLLs': 'file1;file2', + 'DelaySign': 'true', + 'Driver': '2', + 'EmbedManagedResourceFile': 'file1;file2', + 'EnableCOMDATFolding': '2', + 'EnableUAC': 'true', + 'EntryPointSymbol': 'a string1', + 'ErrorReporting': '2', + 'FixedBaseAddress': '2', + 'ForceSymbolReferences': 'file1;file2', + 'FunctionOrder': 'a_file_name', + 'GenerateDebugInformation': 'true', + 'GenerateManifest': 'true', + 'GenerateMapFile': 'true', + 'HeapCommitSize': 'a string1', + 'HeapReserveSize': 'a string1', + 'IgnoreAllDefaultLibraries': 'true', + 'IgnoreDefaultLibraryNames': 'file1;file2', + 'IgnoreEmbeddedIDL': 'true', + 'IgnoreImportLibrary': 'true', + 'ImportLibrary': 'a_file_name', + 'KeyContainer': 'a_file_name', + 'KeyFile': 'a_file_name', + 'LargeAddressAware': '2', + 'LinkIncremental': '2', + 'LinkLibraryDependencies': 'true', + 'LinkTimeCodeGeneration': '2', + 'ManifestFile': 'a_file_name', + 'MapExports': 'true', + 'MapFileName': 'a_file_name', + 'MergedIDLBaseFileName': 'a_file_name', + 'MergeSections': 'a string1', + 'MidlCommandFile': 'a_file_name', + 'ModuleDefinitionFile': 'a_file_name', + 'OptimizeForWindows98': '1', + 'OptimizeReferences': '2', + 'OutputFile': 'a_file_name', + 'PerUserRedirection': 'true', + 'Profile': 'true', + 'ProfileGuidedDatabase': 'a_file_name', + 'ProgramDatabaseFile': 'a_file_name', + 'RandomizedBaseAddress': '2', + 'RegisterOutput': 'true', + 'ResourceOnlyDLL': 'true', + 'SetChecksum': 'true', + 'ShowProgress': '2', + 'StackCommitSize': 'a string1', + 'StackReserveSize': 'a string1', + 'StripPrivateSymbols': 'a_file_name', + 'SubSystem': '2', + 'SupportUnloadOfDelayLoadedDLL': 'true', + 'SuppressStartupBanner': 'true', + 'SwapRunFromCD': 'true', + 'SwapRunFromNet': 'true', + 'TargetMachine': '2', + 'TerminalServerAware': '2', + 'TurnOffAssemblyGeneration': 'true', + 'TypeLibraryFile': 'a_file_name', + 'TypeLibraryResourceID': '33', + 'UACExecutionLevel': '2', + 'UACUIAccess': 'true', + 'UseLibraryDependencyInputs': 'true', + 'UseUnicodeResponseFiles': 'true', + 'Version': 'a string1'}, + 'VCMIDLTool': { + 'AdditionalIncludeDirectories': 'folder1;folder2', + 'AdditionalOptions': 'a string1', + 'CPreprocessOptions': 'a string1', + 'DefaultCharType': '1', + 'DLLDataFileName': 'a_file_name', + 'EnableErrorChecks': '1', + 'ErrorCheckAllocations': 'true', + 'ErrorCheckBounds': 'true', + 'ErrorCheckEnumRange': 'true', + 'ErrorCheckRefPointers': 'true', + 'ErrorCheckStubData': 'true', + 'GenerateStublessProxies': 'true', + 'GenerateTypeLibrary': 'true', + 'HeaderFileName': 'a_file_name', + 'IgnoreStandardIncludePath': 'true', + 'InterfaceIdentifierFileName': 'a_file_name', + 'MkTypLibCompatible': 'true', + 'notgood': 'bogus', + 'OutputDirectory': 'a string1', + 'PreprocessorDefinitions': 'string1;string2', + 'ProxyFileName': 'a_file_name', + 'RedirectOutputAndErrors': 'a_file_name', + 'StructMemberAlignment': '1', + 'SuppressStartupBanner': 'true', + 'TargetEnvironment': '1', + 'TypeLibraryName': 'a_file_name', + 'UndefinePreprocessorDefinitions': 'string1;string2', + 'ValidateParameters': 'true', + 'WarnAsError': 'true', + 'WarningLevel': '1'}, + 'VCResourceCompilerTool': { + 'AdditionalOptions': 'a string1', + 'AdditionalIncludeDirectories': 'folder1;folder2', + 'Culture': '1003', + 'IgnoreStandardIncludePath': 'true', + 'notgood2': 'bogus', + 'PreprocessorDefinitions': 'string1;string2', + 'ResourceOutputFileName': 'a string1', + 'ShowProgress': 'true', + 'SuppressStartupBanner': 'true', + 'UndefinePreprocessorDefinitions': 'string1;string2'}, + 'VCLibrarianTool': { + 'AdditionalDependencies': 'file1;file2', + 'AdditionalLibraryDirectories': 'folder1;folder2', + 'AdditionalOptions': 'a string1', + 'ExportNamedFunctions': 'string1;string2', + 'ForceSymbolReferences': 'a string1', + 'IgnoreAllDefaultLibraries': 'true', + 'IgnoreSpecificDefaultLibraries': 'file1;file2', + 'LinkLibraryDependencies': 'true', + 'ModuleDefinitionFile': 'a_file_name', + 'OutputFile': 'a_file_name', + 'SuppressStartupBanner': 'true', + 'UseUnicodeResponseFiles': 'true'}, + 'VCManifestTool': { + 'AdditionalManifestFiles': 'file1;file2', + 'AdditionalOptions': 'a string1', + 'AssemblyIdentity': 'a string1', + 'ComponentFileName': 'a_file_name', + 'DependencyInformationFile': 'a_file_name', + 'GenerateCatalogFiles': 'true', + 'InputResourceManifests': 'a string1', + 'ManifestResourceFile': 'a_file_name', + 'OutputManifestFile': 'a_file_name', + 'RegistrarScriptFile': 'a_file_name', + 'ReplacementsFile': 'a_file_name', + 'SuppressStartupBanner': 'true', + 'TypeLibraryFile': 'a_file_name', + 'UpdateFileHashes': 'truel', + 'UpdateFileHashesSearchPath': 'a_file_name', + 'UseFAT32Workaround': 'true', + 'UseUnicodeResponseFiles': 'true', + 'VerboseOutput': 'true'}}, + self.stderr) + self._ExpectedWarnings([ + 'Warning: for VCCLCompilerTool/BasicRuntimeChecks, ' + 'index value (5) not in expected range [0, 4)', + 'Warning: for VCCLCompilerTool/BrowseInformation, ' + "invalid literal for int() with base 10: 'fdkslj'", + 'Warning: for VCCLCompilerTool/CallingConvention, ' + 'index value (-1) not in expected range [0, 3)', + 'Warning: for VCCLCompilerTool/DebugInformationFormat, ' + 'converted value for 2 not specified.', + 'Warning: unrecognized setting VCCLCompilerTool/Enableprefast', + 'Warning: unrecognized setting VCCLCompilerTool/ZZXYZ', + 'Warning: for VCLinkerTool/TargetMachine, ' + 'converted value for 2 not specified.', + 'Warning: unrecognized setting VCMIDLTool/notgood', + 'Warning: unrecognized setting VCResourceCompilerTool/notgood2', + 'Warning: for VCManifestTool/UpdateFileHashes, ' + "expected bool; got 'truel'" + '']) + + def testValidateMSBuildSettings_settings(self): + """Tests that for invalid MSBuild settings.""" + MSVSSettings.ValidateMSBuildSettings( + {'ClCompile': { + 'AdditionalIncludeDirectories': 'folder1;folder2', + 'AdditionalOptions': ['string1', 'string2'], + 'AdditionalUsingDirectories': 'folder1;folder2', + 'AssemblerListingLocation': 'a_file_name', + 'AssemblerOutput': 'NoListing', + 'BasicRuntimeChecks': 'StackFrameRuntimeCheck', + 'BrowseInformation': 'false', + 'BrowseInformationFile': 'a_file_name', + 'BufferSecurityCheck': 'true', + 'BuildingInIDE': 'true', + 'CallingConvention': 'Cdecl', + 'CompileAs': 'CompileAsC', + 'CompileAsManaged': 'Pure', + 'CreateHotpatchableImage': 'true', + 'DebugInformationFormat': 'ProgramDatabase', + 'DisableLanguageExtensions': 'true', + 'DisableSpecificWarnings': 'string1;string2', + 'EnableEnhancedInstructionSet': 'StreamingSIMDExtensions', + 'EnableFiberSafeOptimizations': 'true', + 'EnablePREfast': 'true', + 'Enableprefast': 'bogus', + 'ErrorReporting': 'Prompt', + 'ExceptionHandling': 'SyncCThrow', + 'ExpandAttributedSource': 'true', + 'FavorSizeOrSpeed': 'Neither', + 'FloatingPointExceptions': 'true', + 'FloatingPointModel': 'Precise', + 'ForceConformanceInForLoopScope': 'true', + 'ForcedIncludeFiles': 'file1;file2', + 'ForcedUsingFiles': 'file1;file2', + 'FunctionLevelLinking': 'false', + 'GenerateXMLDocumentationFiles': 'true', + 'IgnoreStandardIncludePath': 'true', + 'InlineFunctionExpansion': 'OnlyExplicitInline', + 'IntrinsicFunctions': 'false', + 'MinimalRebuild': 'true', + 'MultiProcessorCompilation': 'true', + 'ObjectFileName': 'a_file_name', + 'OmitDefaultLibName': 'true', + 'OmitFramePointers': 'true', + 'OpenMPSupport': 'true', + 'Optimization': 'Disabled', + 'PrecompiledHeader': 'NotUsing', + 'PrecompiledHeaderFile': 'a_file_name', + 'PrecompiledHeaderOutputFile': 'a_file_name', + 'PreprocessKeepComments': 'true', + 'PreprocessorDefinitions': 'string1;string2', + 'PreprocessOutputPath': 'a string1', + 'PreprocessSuppressLineNumbers': 'false', + 'PreprocessToFile': 'false', + 'ProcessorNumber': '33', + 'ProgramDataBaseFileName': 'a_file_name', + 'RuntimeLibrary': 'MultiThreaded', + 'RuntimeTypeInfo': 'true', + 'ShowIncludes': 'true', + 'SmallerTypeCheck': 'true', + 'StringPooling': 'true', + 'StructMemberAlignment': '1Byte', + 'SuppressStartupBanner': 'true', + 'TrackerLogDirectory': 'a_folder', + 'TreatSpecificWarningsAsErrors': 'string1;string2', + 'TreatWarningAsError': 'true', + 'TreatWChar_tAsBuiltInType': 'true', + 'UndefineAllPreprocessorDefinitions': 'true', + 'UndefinePreprocessorDefinitions': 'string1;string2', + 'UseFullPaths': 'true', + 'UseUnicodeForAssemblerListing': 'true', + 'WarningLevel': 'TurnOffAllWarnings', + 'WholeProgramOptimization': 'true', + 'XMLDocumentationFileName': 'a_file_name', + 'ZZXYZ': 'bogus'}, + 'Link': { + 'AdditionalDependencies': 'file1;file2', + 'AdditionalLibraryDirectories': 'folder1;folder2', + 'AdditionalManifestDependencies': 'file1;file2', + 'AdditionalOptions': 'a string1', + 'AddModuleNamesToAssembly': 'file1;file2', + 'AllowIsolation': 'true', + 'AssemblyDebug': '', + 'AssemblyLinkResource': 'file1;file2', + 'BaseAddress': 'a string1', + 'BuildingInIDE': 'true', + 'CLRImageType': 'ForceIJWImage', + 'CLRSupportLastError': 'Enabled', + 'CLRThreadAttribute': 'MTAThreadingAttribute', + 'CLRUnmanagedCodeCheck': 'true', + 'CreateHotPatchableImage': 'X86Image', + 'DataExecutionPrevention': 'false', + 'DelayLoadDLLs': 'file1;file2', + 'DelaySign': 'true', + 'Driver': 'NotSet', + 'EmbedManagedResourceFile': 'file1;file2', + 'EnableCOMDATFolding': 'false', + 'EnableUAC': 'true', + 'EntryPointSymbol': 'a string1', + 'FixedBaseAddress': 'false', + 'ForceFileOutput': 'Enabled', + 'ForceSymbolReferences': 'file1;file2', + 'FunctionOrder': 'a_file_name', + 'GenerateDebugInformation': 'true', + 'GenerateMapFile': 'true', + 'HeapCommitSize': 'a string1', + 'HeapReserveSize': 'a string1', + 'IgnoreAllDefaultLibraries': 'true', + 'IgnoreEmbeddedIDL': 'true', + 'IgnoreSpecificDefaultLibraries': 'a_file_list', + 'ImageHasSafeExceptionHandlers': 'true', + 'ImportLibrary': 'a_file_name', + 'KeyContainer': 'a_file_name', + 'KeyFile': 'a_file_name', + 'LargeAddressAware': 'false', + 'LinkDLL': 'true', + 'LinkErrorReporting': 'SendErrorReport', + 'LinkStatus': 'true', + 'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration', + 'ManifestFile': 'a_file_name', + 'MapExports': 'true', + 'MapFileName': 'a_file_name', + 'MergedIDLBaseFileName': 'a_file_name', + 'MergeSections': 'a string1', + 'MidlCommandFile': 'a_file_name', + 'MinimumRequiredVersion': 'a string1', + 'ModuleDefinitionFile': 'a_file_name', + 'MSDOSStubFileName': 'a_file_name', + 'NoEntryPoint': 'true', + 'OptimizeReferences': 'false', + 'OutputFile': 'a_file_name', + 'PerUserRedirection': 'true', + 'PreventDllBinding': 'true', + 'Profile': 'true', + 'ProfileGuidedDatabase': 'a_file_name', + 'ProgramDatabaseFile': 'a_file_name', + 'RandomizedBaseAddress': 'false', + 'RegisterOutput': 'true', + 'SectionAlignment': '33', + 'SetChecksum': 'true', + 'ShowProgress': 'LinkVerboseREF', + 'SpecifySectionAttributes': 'a string1', + 'StackCommitSize': 'a string1', + 'StackReserveSize': 'a string1', + 'StripPrivateSymbols': 'a_file_name', + 'SubSystem': 'Console', + 'SupportNobindOfDelayLoadedDLL': 'true', + 'SupportUnloadOfDelayLoadedDLL': 'true', + 'SuppressStartupBanner': 'true', + 'SwapRunFromCD': 'true', + 'SwapRunFromNET': 'true', + 'TargetMachine': 'MachineX86', + 'TerminalServerAware': 'false', + 'TrackerLogDirectory': 'a_folder', + 'TreatLinkerWarningAsErrors': 'true', + 'TurnOffAssemblyGeneration': 'true', + 'TypeLibraryFile': 'a_file_name', + 'TypeLibraryResourceID': '33', + 'UACExecutionLevel': 'AsInvoker', + 'UACUIAccess': 'true', + 'Version': 'a string1'}, + 'ResourceCompile': { + 'AdditionalIncludeDirectories': 'folder1;folder2', + 'AdditionalOptions': 'a string1', + 'Culture': '0x236', + 'IgnoreStandardIncludePath': 'true', + 'NullTerminateStrings': 'true', + 'PreprocessorDefinitions': 'string1;string2', + 'ResourceOutputFileName': 'a string1', + 'ShowProgress': 'true', + 'SuppressStartupBanner': 'true', + 'TrackerLogDirectory': 'a_folder', + 'UndefinePreprocessorDefinitions': 'string1;string2'}, + 'Midl': { + 'AdditionalIncludeDirectories': 'folder1;folder2', + 'AdditionalOptions': 'a string1', + 'ApplicationConfigurationMode': 'true', + 'ClientStubFile': 'a_file_name', + 'CPreprocessOptions': 'a string1', + 'DefaultCharType': 'Signed', + 'DllDataFileName': 'a_file_name', + 'EnableErrorChecks': 'EnableCustom', + 'ErrorCheckAllocations': 'true', + 'ErrorCheckBounds': 'true', + 'ErrorCheckEnumRange': 'true', + 'ErrorCheckRefPointers': 'true', + 'ErrorCheckStubData': 'true', + 'GenerateClientFiles': 'Stub', + 'GenerateServerFiles': 'None', + 'GenerateStublessProxies': 'true', + 'GenerateTypeLibrary': 'true', + 'HeaderFileName': 'a_file_name', + 'IgnoreStandardIncludePath': 'true', + 'InterfaceIdentifierFileName': 'a_file_name', + 'LocaleID': '33', + 'MkTypLibCompatible': 'true', + 'OutputDirectory': 'a string1', + 'PreprocessorDefinitions': 'string1;string2', + 'ProxyFileName': 'a_file_name', + 'RedirectOutputAndErrors': 'a_file_name', + 'ServerStubFile': 'a_file_name', + 'StructMemberAlignment': 'NotSet', + 'SuppressCompilerWarnings': 'true', + 'SuppressStartupBanner': 'true', + 'TargetEnvironment': 'Itanium', + 'TrackerLogDirectory': 'a_folder', + 'TypeLibFormat': 'NewFormat', + 'TypeLibraryName': 'a_file_name', + 'UndefinePreprocessorDefinitions': 'string1;string2', + 'ValidateAllParameters': 'true', + 'WarnAsError': 'true', + 'WarningLevel': '1'}, + 'Lib': { + 'AdditionalDependencies': 'file1;file2', + 'AdditionalLibraryDirectories': 'folder1;folder2', + 'AdditionalOptions': 'a string1', + 'DisplayLibrary': 'a string1', + 'ErrorReporting': 'PromptImmediately', + 'ExportNamedFunctions': 'string1;string2', + 'ForceSymbolReferences': 'a string1', + 'IgnoreAllDefaultLibraries': 'true', + 'IgnoreSpecificDefaultLibraries': 'file1;file2', + 'LinkTimeCodeGeneration': 'true', + 'MinimumRequiredVersion': 'a string1', + 'ModuleDefinitionFile': 'a_file_name', + 'Name': 'a_file_name', + 'OutputFile': 'a_file_name', + 'RemoveObjects': 'file1;file2', + 'SubSystem': 'Console', + 'SuppressStartupBanner': 'true', + 'TargetMachine': 'MachineX86i', + 'TrackerLogDirectory': 'a_folder', + 'TreatLibWarningAsErrors': 'true', + 'UseUnicodeResponseFiles': 'true', + 'Verbose': 'true'}, + 'Manifest': { + 'AdditionalManifestFiles': 'file1;file2', + 'AdditionalOptions': 'a string1', + 'AssemblyIdentity': 'a string1', + 'ComponentFileName': 'a_file_name', + 'EnableDPIAwareness': 'fal', + 'GenerateCatalogFiles': 'truel', + 'GenerateCategoryTags': 'true', + 'InputResourceManifests': 'a string1', + 'ManifestFromManagedAssembly': 'a_file_name', + 'notgood3': 'bogus', + 'OutputManifestFile': 'a_file_name', + 'OutputResourceManifests': 'a string1', + 'RegistrarScriptFile': 'a_file_name', + 'ReplacementsFile': 'a_file_name', + 'SuppressDependencyElement': 'true', + 'SuppressStartupBanner': 'true', + 'TrackerLogDirectory': 'a_folder', + 'TypeLibraryFile': 'a_file_name', + 'UpdateFileHashes': 'true', + 'UpdateFileHashesSearchPath': 'a_file_name', + 'VerboseOutput': 'true'}, + 'ProjectReference': { + 'LinkLibraryDependencies': 'true', + 'UseLibraryDependencyInputs': 'true'}, + 'ManifestResourceCompile': { + 'ResourceOutputFileName': 'a_file_name'}, + '': { + 'EmbedManifest': 'true', + 'GenerateManifest': 'true', + 'IgnoreImportLibrary': 'true', + 'LinkIncremental': 'false'}}, + self.stderr) + self._ExpectedWarnings([ + 'Warning: unrecognized setting ClCompile/Enableprefast', + 'Warning: unrecognized setting ClCompile/ZZXYZ', + 'Warning: unrecognized setting Manifest/notgood3', + 'Warning: for Manifest/GenerateCatalogFiles, ' + "expected bool; got 'truel'", + 'Warning: for Lib/TargetMachine, unrecognized enumerated value ' + 'MachineX86i', + "Warning: for Manifest/EnableDPIAwareness, expected bool; got 'fal'"]) + + def testConvertToMSBuildSettings_empty(self): + """Tests an empty conversion.""" + msvs_settings = {} + expected_msbuild_settings = {} + actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings( + msvs_settings, + self.stderr) + self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) + self._ExpectedWarnings([]) + + def testConvertToMSBuildSettings_minimal(self): + """Tests a minimal conversion.""" + msvs_settings = { + 'VCCLCompilerTool': { + 'AdditionalIncludeDirectories': 'dir1', + 'AdditionalOptions': '/foo', + 'BasicRuntimeChecks': '0', + }, + 'VCLinkerTool': { + 'LinkTimeCodeGeneration': '1', + 'ErrorReporting': '1', + 'DataExecutionPrevention': '2', + }, + } + expected_msbuild_settings = { + 'ClCompile': { + 'AdditionalIncludeDirectories': 'dir1', + 'AdditionalOptions': '/foo', + 'BasicRuntimeChecks': 'Default', + }, + 'Link': { + 'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration', + 'LinkErrorReporting': 'PromptImmediately', + 'DataExecutionPrevention': 'true', + }, + } + actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings( + msvs_settings, + self.stderr) + self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) + self._ExpectedWarnings([]) + + def testConvertToMSBuildSettings_warnings(self): + """Tests conversion that generates warnings.""" + msvs_settings = { + 'VCCLCompilerTool': { + 'AdditionalIncludeDirectories': '1', + 'AdditionalOptions': '2', + # These are incorrect values: + 'BasicRuntimeChecks': '12', + 'BrowseInformation': '21', + 'UsePrecompiledHeader': '13', + 'GeneratePreprocessedFile': '14'}, + 'VCLinkerTool': { + # These are incorrect values: + 'Driver': '10', + 'LinkTimeCodeGeneration': '31', + 'ErrorReporting': '21', + 'FixedBaseAddress': '6'}, + 'VCResourceCompilerTool': { + # Custom + 'Culture': '1003'}} + expected_msbuild_settings = { + 'ClCompile': { + 'AdditionalIncludeDirectories': '1', + 'AdditionalOptions': '2'}, + 'Link': {}, + 'ResourceCompile': { + # Custom + 'Culture': '0x03eb'}} + actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings( + msvs_settings, + self.stderr) + self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) + self._ExpectedWarnings([ + 'Warning: while converting VCCLCompilerTool/BasicRuntimeChecks to ' + 'MSBuild, index value (12) not in expected range [0, 4)', + 'Warning: while converting VCCLCompilerTool/BrowseInformation to ' + 'MSBuild, index value (21) not in expected range [0, 3)', + 'Warning: while converting VCCLCompilerTool/UsePrecompiledHeader to ' + 'MSBuild, index value (13) not in expected range [0, 3)', + 'Warning: while converting VCCLCompilerTool/GeneratePreprocessedFile to ' + 'MSBuild, value must be one of [0, 1, 2]; got 14', + + 'Warning: while converting VCLinkerTool/Driver to ' + 'MSBuild, index value (10) not in expected range [0, 4)', + 'Warning: while converting VCLinkerTool/LinkTimeCodeGeneration to ' + 'MSBuild, index value (31) not in expected range [0, 5)', + 'Warning: while converting VCLinkerTool/ErrorReporting to ' + 'MSBuild, index value (21) not in expected range [0, 3)', + 'Warning: while converting VCLinkerTool/FixedBaseAddress to ' + 'MSBuild, index value (6) not in expected range [0, 3)', + ]) + + def testConvertToMSBuildSettings_full_synthetic(self): + """Tests conversion of all the MSBuild settings.""" + msvs_settings = { + 'VCCLCompilerTool': { + 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', + 'AdditionalOptions': 'a_string', + 'AdditionalUsingDirectories': 'folder1;folder2;folder3', + 'AssemblerListingLocation': 'a_file_name', + 'AssemblerOutput': '0', + 'BasicRuntimeChecks': '1', + 'BrowseInformation': '2', + 'BrowseInformationFile': 'a_file_name', + 'BufferSecurityCheck': 'true', + 'CallingConvention': '0', + 'CompileAs': '1', + 'DebugInformationFormat': '4', + 'DefaultCharIsUnsigned': 'true', + 'Detect64BitPortabilityProblems': 'true', + 'DisableLanguageExtensions': 'true', + 'DisableSpecificWarnings': 'd1;d2;d3', + 'EnableEnhancedInstructionSet': '0', + 'EnableFiberSafeOptimizations': 'true', + 'EnableFunctionLevelLinking': 'true', + 'EnableIntrinsicFunctions': 'true', + 'EnablePREfast': 'true', + 'ErrorReporting': '1', + 'ExceptionHandling': '2', + 'ExpandAttributedSource': 'true', + 'FavorSizeOrSpeed': '0', + 'FloatingPointExceptions': 'true', + 'FloatingPointModel': '1', + 'ForceConformanceInForLoopScope': 'true', + 'ForcedIncludeFiles': 'file1;file2;file3', + 'ForcedUsingFiles': 'file1;file2;file3', + 'GeneratePreprocessedFile': '1', + 'GenerateXMLDocumentationFiles': 'true', + 'IgnoreStandardIncludePath': 'true', + 'InlineFunctionExpansion': '2', + 'KeepComments': 'true', + 'MinimalRebuild': 'true', + 'ObjectFile': 'a_file_name', + 'OmitDefaultLibName': 'true', + 'OmitFramePointers': 'true', + 'OpenMP': 'true', + 'Optimization': '3', + 'PrecompiledHeaderFile': 'a_file_name', + 'PrecompiledHeaderThrough': 'a_file_name', + 'PreprocessorDefinitions': 'd1;d2;d3', + 'ProgramDataBaseFileName': 'a_file_name', + 'RuntimeLibrary': '0', + 'RuntimeTypeInfo': 'true', + 'ShowIncludes': 'true', + 'SmallerTypeCheck': 'true', + 'StringPooling': 'true', + 'StructMemberAlignment': '1', + 'SuppressStartupBanner': 'true', + 'TreatWChar_tAsBuiltInType': 'true', + 'UndefineAllPreprocessorDefinitions': 'true', + 'UndefinePreprocessorDefinitions': 'd1;d2;d3', + 'UseFullPaths': 'true', + 'UsePrecompiledHeader': '1', + 'UseUnicodeResponseFiles': 'true', + 'WarnAsError': 'true', + 'WarningLevel': '2', + 'WholeProgramOptimization': 'true', + 'XMLDocumentationFileName': 'a_file_name'}, + 'VCLinkerTool': { + 'AdditionalDependencies': 'file1;file2;file3', + 'AdditionalLibraryDirectories': 'folder1;folder2;folder3', + 'AdditionalLibraryDirectories_excluded': 'folder1;folder2;folder3', + 'AdditionalManifestDependencies': 'file1;file2;file3', + 'AdditionalOptions': 'a_string', + 'AddModuleNamesToAssembly': 'file1;file2;file3', + 'AllowIsolation': 'true', + 'AssemblyDebug': '0', + 'AssemblyLinkResource': 'file1;file2;file3', + 'BaseAddress': 'a_string', + 'CLRImageType': '1', + 'CLRThreadAttribute': '2', + 'CLRUnmanagedCodeCheck': 'true', + 'DataExecutionPrevention': '0', + 'DelayLoadDLLs': 'file1;file2;file3', + 'DelaySign': 'true', + 'Driver': '1', + 'EmbedManagedResourceFile': 'file1;file2;file3', + 'EnableCOMDATFolding': '0', + 'EnableUAC': 'true', + 'EntryPointSymbol': 'a_string', + 'ErrorReporting': '0', + 'FixedBaseAddress': '1', + 'ForceSymbolReferences': 'file1;file2;file3', + 'FunctionOrder': 'a_file_name', + 'GenerateDebugInformation': 'true', + 'GenerateManifest': 'true', + 'GenerateMapFile': 'true', + 'HeapCommitSize': 'a_string', + 'HeapReserveSize': 'a_string', + 'IgnoreAllDefaultLibraries': 'true', + 'IgnoreDefaultLibraryNames': 'file1;file2;file3', + 'IgnoreEmbeddedIDL': 'true', + 'IgnoreImportLibrary': 'true', + 'ImportLibrary': 'a_file_name', + 'KeyContainer': 'a_file_name', + 'KeyFile': 'a_file_name', + 'LargeAddressAware': '2', + 'LinkIncremental': '1', + 'LinkLibraryDependencies': 'true', + 'LinkTimeCodeGeneration': '2', + 'ManifestFile': 'a_file_name', + 'MapExports': 'true', + 'MapFileName': 'a_file_name', + 'MergedIDLBaseFileName': 'a_file_name', + 'MergeSections': 'a_string', + 'MidlCommandFile': 'a_file_name', + 'ModuleDefinitionFile': 'a_file_name', + 'OptimizeForWindows98': '1', + 'OptimizeReferences': '0', + 'OutputFile': 'a_file_name', + 'PerUserRedirection': 'true', + 'Profile': 'true', + 'ProfileGuidedDatabase': 'a_file_name', + 'ProgramDatabaseFile': 'a_file_name', + 'RandomizedBaseAddress': '1', + 'RegisterOutput': 'true', + 'ResourceOnlyDLL': 'true', + 'SetChecksum': 'true', + 'ShowProgress': '0', + 'StackCommitSize': 'a_string', + 'StackReserveSize': 'a_string', + 'StripPrivateSymbols': 'a_file_name', + 'SubSystem': '2', + 'SupportUnloadOfDelayLoadedDLL': 'true', + 'SuppressStartupBanner': 'true', + 'SwapRunFromCD': 'true', + 'SwapRunFromNet': 'true', + 'TargetMachine': '3', + 'TerminalServerAware': '2', + 'TurnOffAssemblyGeneration': 'true', + 'TypeLibraryFile': 'a_file_name', + 'TypeLibraryResourceID': '33', + 'UACExecutionLevel': '1', + 'UACUIAccess': 'true', + 'UseLibraryDependencyInputs': 'false', + 'UseUnicodeResponseFiles': 'true', + 'Version': 'a_string'}, + 'VCResourceCompilerTool': { + 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', + 'AdditionalOptions': 'a_string', + 'Culture': '1003', + 'IgnoreStandardIncludePath': 'true', + 'PreprocessorDefinitions': 'd1;d2;d3', + 'ResourceOutputFileName': 'a_string', + 'ShowProgress': 'true', + 'SuppressStartupBanner': 'true', + 'UndefinePreprocessorDefinitions': 'd1;d2;d3'}, + 'VCMIDLTool': { + 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', + 'AdditionalOptions': 'a_string', + 'CPreprocessOptions': 'a_string', + 'DefaultCharType': '0', + 'DLLDataFileName': 'a_file_name', + 'EnableErrorChecks': '2', + 'ErrorCheckAllocations': 'true', + 'ErrorCheckBounds': 'true', + 'ErrorCheckEnumRange': 'true', + 'ErrorCheckRefPointers': 'true', + 'ErrorCheckStubData': 'true', + 'GenerateStublessProxies': 'true', + 'GenerateTypeLibrary': 'true', + 'HeaderFileName': 'a_file_name', + 'IgnoreStandardIncludePath': 'true', + 'InterfaceIdentifierFileName': 'a_file_name', + 'MkTypLibCompatible': 'true', + 'OutputDirectory': 'a_string', + 'PreprocessorDefinitions': 'd1;d2;d3', + 'ProxyFileName': 'a_file_name', + 'RedirectOutputAndErrors': 'a_file_name', + 'StructMemberAlignment': '3', + 'SuppressStartupBanner': 'true', + 'TargetEnvironment': '1', + 'TypeLibraryName': 'a_file_name', + 'UndefinePreprocessorDefinitions': 'd1;d2;d3', + 'ValidateParameters': 'true', + 'WarnAsError': 'true', + 'WarningLevel': '4'}, + 'VCLibrarianTool': { + 'AdditionalDependencies': 'file1;file2;file3', + 'AdditionalLibraryDirectories': 'folder1;folder2;folder3', + 'AdditionalLibraryDirectories_excluded': 'folder1;folder2;folder3', + 'AdditionalOptions': 'a_string', + 'ExportNamedFunctions': 'd1;d2;d3', + 'ForceSymbolReferences': 'a_string', + 'IgnoreAllDefaultLibraries': 'true', + 'IgnoreSpecificDefaultLibraries': 'file1;file2;file3', + 'LinkLibraryDependencies': 'true', + 'ModuleDefinitionFile': 'a_file_name', + 'OutputFile': 'a_file_name', + 'SuppressStartupBanner': 'true', + 'UseUnicodeResponseFiles': 'true'}, + 'VCManifestTool': { + 'AdditionalManifestFiles': 'file1;file2;file3', + 'AdditionalOptions': 'a_string', + 'AssemblyIdentity': 'a_string', + 'ComponentFileName': 'a_file_name', + 'DependencyInformationFile': 'a_file_name', + 'EmbedManifest': 'true', + 'GenerateCatalogFiles': 'true', + 'InputResourceManifests': 'a_string', + 'ManifestResourceFile': 'my_name', + 'OutputManifestFile': 'a_file_name', + 'RegistrarScriptFile': 'a_file_name', + 'ReplacementsFile': 'a_file_name', + 'SuppressStartupBanner': 'true', + 'TypeLibraryFile': 'a_file_name', + 'UpdateFileHashes': 'true', + 'UpdateFileHashesSearchPath': 'a_file_name', + 'UseFAT32Workaround': 'true', + 'UseUnicodeResponseFiles': 'true', + 'VerboseOutput': 'true'}} + expected_msbuild_settings = { + 'ClCompile': { + 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', + 'AdditionalOptions': 'a_string /J', + 'AdditionalUsingDirectories': 'folder1;folder2;folder3', + 'AssemblerListingLocation': 'a_file_name', + 'AssemblerOutput': 'NoListing', + 'BasicRuntimeChecks': 'StackFrameRuntimeCheck', + 'BrowseInformation': 'true', + 'BrowseInformationFile': 'a_file_name', + 'BufferSecurityCheck': 'true', + 'CallingConvention': 'Cdecl', + 'CompileAs': 'CompileAsC', + 'DebugInformationFormat': 'EditAndContinue', + 'DisableLanguageExtensions': 'true', + 'DisableSpecificWarnings': 'd1;d2;d3', + 'EnableEnhancedInstructionSet': 'NotSet', + 'EnableFiberSafeOptimizations': 'true', + 'EnablePREfast': 'true', + 'ErrorReporting': 'Prompt', + 'ExceptionHandling': 'Async', + 'ExpandAttributedSource': 'true', + 'FavorSizeOrSpeed': 'Neither', + 'FloatingPointExceptions': 'true', + 'FloatingPointModel': 'Strict', + 'ForceConformanceInForLoopScope': 'true', + 'ForcedIncludeFiles': 'file1;file2;file3', + 'ForcedUsingFiles': 'file1;file2;file3', + 'FunctionLevelLinking': 'true', + 'GenerateXMLDocumentationFiles': 'true', + 'IgnoreStandardIncludePath': 'true', + 'InlineFunctionExpansion': 'AnySuitable', + 'IntrinsicFunctions': 'true', + 'MinimalRebuild': 'true', + 'ObjectFileName': 'a_file_name', + 'OmitDefaultLibName': 'true', + 'OmitFramePointers': 'true', + 'OpenMPSupport': 'true', + 'Optimization': 'Full', + 'PrecompiledHeader': 'Create', + 'PrecompiledHeaderFile': 'a_file_name', + 'PrecompiledHeaderOutputFile': 'a_file_name', + 'PreprocessKeepComments': 'true', + 'PreprocessorDefinitions': 'd1;d2;d3', + 'PreprocessSuppressLineNumbers': 'false', + 'PreprocessToFile': 'true', + 'ProgramDataBaseFileName': 'a_file_name', + 'RuntimeLibrary': 'MultiThreaded', + 'RuntimeTypeInfo': 'true', + 'ShowIncludes': 'true', + 'SmallerTypeCheck': 'true', + 'StringPooling': 'true', + 'StructMemberAlignment': '1Byte', + 'SuppressStartupBanner': 'true', + 'TreatWarningAsError': 'true', + 'TreatWChar_tAsBuiltInType': 'true', + 'UndefineAllPreprocessorDefinitions': 'true', + 'UndefinePreprocessorDefinitions': 'd1;d2;d3', + 'UseFullPaths': 'true', + 'WarningLevel': 'Level2', + 'WholeProgramOptimization': 'true', + 'XMLDocumentationFileName': 'a_file_name'}, + 'Link': { + 'AdditionalDependencies': 'file1;file2;file3', + 'AdditionalLibraryDirectories': 'folder1;folder2;folder3', + 'AdditionalManifestDependencies': 'file1;file2;file3', + 'AdditionalOptions': 'a_string', + 'AddModuleNamesToAssembly': 'file1;file2;file3', + 'AllowIsolation': 'true', + 'AssemblyDebug': '', + 'AssemblyLinkResource': 'file1;file2;file3', + 'BaseAddress': 'a_string', + 'CLRImageType': 'ForceIJWImage', + 'CLRThreadAttribute': 'STAThreadingAttribute', + 'CLRUnmanagedCodeCheck': 'true', + 'DataExecutionPrevention': '', + 'DelayLoadDLLs': 'file1;file2;file3', + 'DelaySign': 'true', + 'Driver': 'Driver', + 'EmbedManagedResourceFile': 'file1;file2;file3', + 'EnableCOMDATFolding': '', + 'EnableUAC': 'true', + 'EntryPointSymbol': 'a_string', + 'FixedBaseAddress': 'false', + 'ForceSymbolReferences': 'file1;file2;file3', + 'FunctionOrder': 'a_file_name', + 'GenerateDebugInformation': 'true', + 'GenerateMapFile': 'true', + 'HeapCommitSize': 'a_string', + 'HeapReserveSize': 'a_string', + 'IgnoreAllDefaultLibraries': 'true', + 'IgnoreEmbeddedIDL': 'true', + 'IgnoreSpecificDefaultLibraries': 'file1;file2;file3', + 'ImportLibrary': 'a_file_name', + 'KeyContainer': 'a_file_name', + 'KeyFile': 'a_file_name', + 'LargeAddressAware': 'true', + 'LinkErrorReporting': 'NoErrorReport', + 'LinkTimeCodeGeneration': 'PGInstrument', + 'ManifestFile': 'a_file_name', + 'MapExports': 'true', + 'MapFileName': 'a_file_name', + 'MergedIDLBaseFileName': 'a_file_name', + 'MergeSections': 'a_string', + 'MidlCommandFile': 'a_file_name', + 'ModuleDefinitionFile': 'a_file_name', + 'NoEntryPoint': 'true', + 'OptimizeReferences': '', + 'OutputFile': 'a_file_name', + 'PerUserRedirection': 'true', + 'Profile': 'true', + 'ProfileGuidedDatabase': 'a_file_name', + 'ProgramDatabaseFile': 'a_file_name', + 'RandomizedBaseAddress': 'false', + 'RegisterOutput': 'true', + 'SetChecksum': 'true', + 'ShowProgress': 'NotSet', + 'StackCommitSize': 'a_string', + 'StackReserveSize': 'a_string', + 'StripPrivateSymbols': 'a_file_name', + 'SubSystem': 'Windows', + 'SupportUnloadOfDelayLoadedDLL': 'true', + 'SuppressStartupBanner': 'true', + 'SwapRunFromCD': 'true', + 'SwapRunFromNET': 'true', + 'TargetMachine': 'MachineARM', + 'TerminalServerAware': 'true', + 'TurnOffAssemblyGeneration': 'true', + 'TypeLibraryFile': 'a_file_name', + 'TypeLibraryResourceID': '33', + 'UACExecutionLevel': 'HighestAvailable', + 'UACUIAccess': 'true', + 'Version': 'a_string'}, + 'ResourceCompile': { + 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', + 'AdditionalOptions': 'a_string', + 'Culture': '0x03eb', + 'IgnoreStandardIncludePath': 'true', + 'PreprocessorDefinitions': 'd1;d2;d3', + 'ResourceOutputFileName': 'a_string', + 'ShowProgress': 'true', + 'SuppressStartupBanner': 'true', + 'UndefinePreprocessorDefinitions': 'd1;d2;d3'}, + 'Midl': { + 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', + 'AdditionalOptions': 'a_string', + 'CPreprocessOptions': 'a_string', + 'DefaultCharType': 'Unsigned', + 'DllDataFileName': 'a_file_name', + 'EnableErrorChecks': 'All', + 'ErrorCheckAllocations': 'true', + 'ErrorCheckBounds': 'true', + 'ErrorCheckEnumRange': 'true', + 'ErrorCheckRefPointers': 'true', + 'ErrorCheckStubData': 'true', + 'GenerateStublessProxies': 'true', + 'GenerateTypeLibrary': 'true', + 'HeaderFileName': 'a_file_name', + 'IgnoreStandardIncludePath': 'true', + 'InterfaceIdentifierFileName': 'a_file_name', + 'MkTypLibCompatible': 'true', + 'OutputDirectory': 'a_string', + 'PreprocessorDefinitions': 'd1;d2;d3', + 'ProxyFileName': 'a_file_name', + 'RedirectOutputAndErrors': 'a_file_name', + 'StructMemberAlignment': '4', + 'SuppressStartupBanner': 'true', + 'TargetEnvironment': 'Win32', + 'TypeLibraryName': 'a_file_name', + 'UndefinePreprocessorDefinitions': 'd1;d2;d3', + 'ValidateAllParameters': 'true', + 'WarnAsError': 'true', + 'WarningLevel': '4'}, + 'Lib': { + 'AdditionalDependencies': 'file1;file2;file3', + 'AdditionalLibraryDirectories': 'folder1;folder2;folder3', + 'AdditionalOptions': 'a_string', + 'ExportNamedFunctions': 'd1;d2;d3', + 'ForceSymbolReferences': 'a_string', + 'IgnoreAllDefaultLibraries': 'true', + 'IgnoreSpecificDefaultLibraries': 'file1;file2;file3', + 'ModuleDefinitionFile': 'a_file_name', + 'OutputFile': 'a_file_name', + 'SuppressStartupBanner': 'true', + 'UseUnicodeResponseFiles': 'true'}, + 'Manifest': { + 'AdditionalManifestFiles': 'file1;file2;file3', + 'AdditionalOptions': 'a_string', + 'AssemblyIdentity': 'a_string', + 'ComponentFileName': 'a_file_name', + 'GenerateCatalogFiles': 'true', + 'InputResourceManifests': 'a_string', + 'OutputManifestFile': 'a_file_name', + 'RegistrarScriptFile': 'a_file_name', + 'ReplacementsFile': 'a_file_name', + 'SuppressStartupBanner': 'true', + 'TypeLibraryFile': 'a_file_name', + 'UpdateFileHashes': 'true', + 'UpdateFileHashesSearchPath': 'a_file_name', + 'VerboseOutput': 'true'}, + 'ManifestResourceCompile': { + 'ResourceOutputFileName': 'my_name'}, + 'ProjectReference': { + 'LinkLibraryDependencies': 'true', + 'UseLibraryDependencyInputs': 'false'}, + '': { + 'EmbedManifest': 'true', + 'GenerateManifest': 'true', + 'IgnoreImportLibrary': 'true', + 'LinkIncremental': 'false'}} + actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings( + msvs_settings, + self.stderr) + self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) + self._ExpectedWarnings([]) + + def testConvertToMSBuildSettings_actual(self): + """Tests the conversion of an actual project. + + A VS2008 project with most of the options defined was created through the + VS2008 IDE. It was then converted to VS2010. The tool settings found in + the .vcproj and .vcxproj files were converted to the two dictionaries + msvs_settings and expected_msbuild_settings. + + Note that for many settings, the VS2010 converter adds macros like + %(AdditionalIncludeDirectories) to make sure than inherited values are + included. Since the Gyp projects we generate do not use inheritance, + we removed these macros. They were: + ClCompile: + AdditionalIncludeDirectories: ';%(AdditionalIncludeDirectories)' + AdditionalOptions: ' %(AdditionalOptions)' + AdditionalUsingDirectories: ';%(AdditionalUsingDirectories)' + DisableSpecificWarnings: ';%(DisableSpecificWarnings)', + ForcedIncludeFiles: ';%(ForcedIncludeFiles)', + ForcedUsingFiles: ';%(ForcedUsingFiles)', + PreprocessorDefinitions: ';%(PreprocessorDefinitions)', + UndefinePreprocessorDefinitions: + ';%(UndefinePreprocessorDefinitions)', + Link: + AdditionalDependencies: ';%(AdditionalDependencies)', + AdditionalLibraryDirectories: ';%(AdditionalLibraryDirectories)', + AdditionalManifestDependencies: + ';%(AdditionalManifestDependencies)', + AdditionalOptions: ' %(AdditionalOptions)', + AddModuleNamesToAssembly: ';%(AddModuleNamesToAssembly)', + AssemblyLinkResource: ';%(AssemblyLinkResource)', + DelayLoadDLLs: ';%(DelayLoadDLLs)', + EmbedManagedResourceFile: ';%(EmbedManagedResourceFile)', + ForceSymbolReferences: ';%(ForceSymbolReferences)', + IgnoreSpecificDefaultLibraries: + ';%(IgnoreSpecificDefaultLibraries)', + ResourceCompile: + AdditionalIncludeDirectories: ';%(AdditionalIncludeDirectories)', + AdditionalOptions: ' %(AdditionalOptions)', + PreprocessorDefinitions: ';%(PreprocessorDefinitions)', + Manifest: + AdditionalManifestFiles: ';%(AdditionalManifestFiles)', + AdditionalOptions: ' %(AdditionalOptions)', + InputResourceManifests: ';%(InputResourceManifests)', + """ + msvs_settings = { + 'VCCLCompilerTool': { + 'AdditionalIncludeDirectories': 'dir1', + 'AdditionalOptions': '/more', + 'AdditionalUsingDirectories': 'test', + 'AssemblerListingLocation': '$(IntDir)\\a', + 'AssemblerOutput': '1', + 'BasicRuntimeChecks': '3', + 'BrowseInformation': '1', + 'BrowseInformationFile': '$(IntDir)\\e', + 'BufferSecurityCheck': 'false', + 'CallingConvention': '1', + 'CompileAs': '1', + 'DebugInformationFormat': '4', + 'DefaultCharIsUnsigned': 'true', + 'Detect64BitPortabilityProblems': 'true', + 'DisableLanguageExtensions': 'true', + 'DisableSpecificWarnings': 'abc', + 'EnableEnhancedInstructionSet': '1', + 'EnableFiberSafeOptimizations': 'true', + 'EnableFunctionLevelLinking': 'true', + 'EnableIntrinsicFunctions': 'true', + 'EnablePREfast': 'true', + 'ErrorReporting': '2', + 'ExceptionHandling': '2', + 'ExpandAttributedSource': 'true', + 'FavorSizeOrSpeed': '2', + 'FloatingPointExceptions': 'true', + 'FloatingPointModel': '1', + 'ForceConformanceInForLoopScope': 'false', + 'ForcedIncludeFiles': 'def', + 'ForcedUsingFiles': 'ge', + 'GeneratePreprocessedFile': '2', + 'GenerateXMLDocumentationFiles': 'true', + 'IgnoreStandardIncludePath': 'true', + 'InlineFunctionExpansion': '1', + 'KeepComments': 'true', + 'MinimalRebuild': 'true', + 'ObjectFile': '$(IntDir)\\b', + 'OmitDefaultLibName': 'true', + 'OmitFramePointers': 'true', + 'OpenMP': 'true', + 'Optimization': '3', + 'PrecompiledHeaderFile': '$(IntDir)\\$(TargetName).pche', + 'PrecompiledHeaderThrough': 'StdAfx.hd', + 'PreprocessorDefinitions': 'WIN32;_DEBUG;_CONSOLE', + 'ProgramDataBaseFileName': '$(IntDir)\\vc90b.pdb', + 'RuntimeLibrary': '3', + 'RuntimeTypeInfo': 'false', + 'ShowIncludes': 'true', + 'SmallerTypeCheck': 'true', + 'StringPooling': 'true', + 'StructMemberAlignment': '3', + 'SuppressStartupBanner': 'false', + 'TreatWChar_tAsBuiltInType': 'false', + 'UndefineAllPreprocessorDefinitions': 'true', + 'UndefinePreprocessorDefinitions': 'wer', + 'UseFullPaths': 'true', + 'UsePrecompiledHeader': '0', + 'UseUnicodeResponseFiles': 'false', + 'WarnAsError': 'true', + 'WarningLevel': '3', + 'WholeProgramOptimization': 'true', + 'XMLDocumentationFileName': '$(IntDir)\\c'}, + 'VCLinkerTool': { + 'AdditionalDependencies': 'zx', + 'AdditionalLibraryDirectories': 'asd', + 'AdditionalManifestDependencies': 's2', + 'AdditionalOptions': '/mor2', + 'AddModuleNamesToAssembly': 'd1', + 'AllowIsolation': 'false', + 'AssemblyDebug': '1', + 'AssemblyLinkResource': 'd5', + 'BaseAddress': '23423', + 'CLRImageType': '3', + 'CLRThreadAttribute': '1', + 'CLRUnmanagedCodeCheck': 'true', + 'DataExecutionPrevention': '0', + 'DelayLoadDLLs': 'd4', + 'DelaySign': 'true', + 'Driver': '2', + 'EmbedManagedResourceFile': 'd2', + 'EnableCOMDATFolding': '1', + 'EnableUAC': 'false', + 'EntryPointSymbol': 'f5', + 'ErrorReporting': '2', + 'FixedBaseAddress': '1', + 'ForceSymbolReferences': 'd3', + 'FunctionOrder': 'fssdfsd', + 'GenerateDebugInformation': 'true', + 'GenerateManifest': 'false', + 'GenerateMapFile': 'true', + 'HeapCommitSize': '13', + 'HeapReserveSize': '12', + 'IgnoreAllDefaultLibraries': 'true', + 'IgnoreDefaultLibraryNames': 'flob;flok', + 'IgnoreEmbeddedIDL': 'true', + 'IgnoreImportLibrary': 'true', + 'ImportLibrary': 'f4', + 'KeyContainer': 'f7', + 'KeyFile': 'f6', + 'LargeAddressAware': '2', + 'LinkIncremental': '0', + 'LinkLibraryDependencies': 'false', + 'LinkTimeCodeGeneration': '1', + 'ManifestFile': + '$(IntDir)\\$(TargetFileName).2intermediate.manifest', + 'MapExports': 'true', + 'MapFileName': 'd5', + 'MergedIDLBaseFileName': 'f2', + 'MergeSections': 'f5', + 'MidlCommandFile': 'f1', + 'ModuleDefinitionFile': 'sdsd', + 'OptimizeForWindows98': '2', + 'OptimizeReferences': '2', + 'OutputFile': '$(OutDir)\\$(ProjectName)2.exe', + 'PerUserRedirection': 'true', + 'Profile': 'true', + 'ProfileGuidedDatabase': '$(TargetDir)$(TargetName).pgdd', + 'ProgramDatabaseFile': 'Flob.pdb', + 'RandomizedBaseAddress': '1', + 'RegisterOutput': 'true', + 'ResourceOnlyDLL': 'true', + 'SetChecksum': 'false', + 'ShowProgress': '1', + 'StackCommitSize': '15', + 'StackReserveSize': '14', + 'StripPrivateSymbols': 'd3', + 'SubSystem': '1', + 'SupportUnloadOfDelayLoadedDLL': 'true', + 'SuppressStartupBanner': 'false', + 'SwapRunFromCD': 'true', + 'SwapRunFromNet': 'true', + 'TargetMachine': '1', + 'TerminalServerAware': '1', + 'TurnOffAssemblyGeneration': 'true', + 'TypeLibraryFile': 'f3', + 'TypeLibraryResourceID': '12', + 'UACExecutionLevel': '2', + 'UACUIAccess': 'true', + 'UseLibraryDependencyInputs': 'true', + 'UseUnicodeResponseFiles': 'false', + 'Version': '333'}, + 'VCResourceCompilerTool': { + 'AdditionalIncludeDirectories': 'f3', + 'AdditionalOptions': '/more3', + 'Culture': '3084', + 'IgnoreStandardIncludePath': 'true', + 'PreprocessorDefinitions': '_UNICODE;UNICODE2', + 'ResourceOutputFileName': '$(IntDir)/$(InputName)3.res', + 'ShowProgress': 'true'}, + 'VCManifestTool': { + 'AdditionalManifestFiles': 'sfsdfsd', + 'AdditionalOptions': 'afdsdafsd', + 'AssemblyIdentity': 'sddfdsadfsa', + 'ComponentFileName': 'fsdfds', + 'DependencyInformationFile': '$(IntDir)\\mt.depdfd', + 'EmbedManifest': 'false', + 'GenerateCatalogFiles': 'true', + 'InputResourceManifests': 'asfsfdafs', + 'ManifestResourceFile': + '$(IntDir)\\$(TargetFileName).embed.manifest.resfdsf', + 'OutputManifestFile': '$(TargetPath).manifestdfs', + 'RegistrarScriptFile': 'sdfsfd', + 'ReplacementsFile': 'sdffsd', + 'SuppressStartupBanner': 'false', + 'TypeLibraryFile': 'sfsd', + 'UpdateFileHashes': 'true', + 'UpdateFileHashesSearchPath': 'sfsd', + 'UseFAT32Workaround': 'true', + 'UseUnicodeResponseFiles': 'false', + 'VerboseOutput': 'true'}} + expected_msbuild_settings = { + 'ClCompile': { + 'AdditionalIncludeDirectories': 'dir1', + 'AdditionalOptions': '/more /J', + 'AdditionalUsingDirectories': 'test', + 'AssemblerListingLocation': '$(IntDir)a', + 'AssemblerOutput': 'AssemblyCode', + 'BasicRuntimeChecks': 'EnableFastChecks', + 'BrowseInformation': 'true', + 'BrowseInformationFile': '$(IntDir)e', + 'BufferSecurityCheck': 'false', + 'CallingConvention': 'FastCall', + 'CompileAs': 'CompileAsC', + 'DebugInformationFormat': 'EditAndContinue', + 'DisableLanguageExtensions': 'true', + 'DisableSpecificWarnings': 'abc', + 'EnableEnhancedInstructionSet': 'StreamingSIMDExtensions', + 'EnableFiberSafeOptimizations': 'true', + 'EnablePREfast': 'true', + 'ErrorReporting': 'Queue', + 'ExceptionHandling': 'Async', + 'ExpandAttributedSource': 'true', + 'FavorSizeOrSpeed': 'Size', + 'FloatingPointExceptions': 'true', + 'FloatingPointModel': 'Strict', + 'ForceConformanceInForLoopScope': 'false', + 'ForcedIncludeFiles': 'def', + 'ForcedUsingFiles': 'ge', + 'FunctionLevelLinking': 'true', + 'GenerateXMLDocumentationFiles': 'true', + 'IgnoreStandardIncludePath': 'true', + 'InlineFunctionExpansion': 'OnlyExplicitInline', + 'IntrinsicFunctions': 'true', + 'MinimalRebuild': 'true', + 'ObjectFileName': '$(IntDir)b', + 'OmitDefaultLibName': 'true', + 'OmitFramePointers': 'true', + 'OpenMPSupport': 'true', + 'Optimization': 'Full', + 'PrecompiledHeader': 'NotUsing', # Actual conversion gives '' + 'PrecompiledHeaderFile': 'StdAfx.hd', + 'PrecompiledHeaderOutputFile': '$(IntDir)$(TargetName).pche', + 'PreprocessKeepComments': 'true', + 'PreprocessorDefinitions': 'WIN32;_DEBUG;_CONSOLE', + 'PreprocessSuppressLineNumbers': 'true', + 'PreprocessToFile': 'true', + 'ProgramDataBaseFileName': '$(IntDir)vc90b.pdb', + 'RuntimeLibrary': 'MultiThreadedDebugDLL', + 'RuntimeTypeInfo': 'false', + 'ShowIncludes': 'true', + 'SmallerTypeCheck': 'true', + 'StringPooling': 'true', + 'StructMemberAlignment': '4Bytes', + 'SuppressStartupBanner': 'false', + 'TreatWarningAsError': 'true', + 'TreatWChar_tAsBuiltInType': 'false', + 'UndefineAllPreprocessorDefinitions': 'true', + 'UndefinePreprocessorDefinitions': 'wer', + 'UseFullPaths': 'true', + 'WarningLevel': 'Level3', + 'WholeProgramOptimization': 'true', + 'XMLDocumentationFileName': '$(IntDir)c'}, + 'Link': { + 'AdditionalDependencies': 'zx', + 'AdditionalLibraryDirectories': 'asd', + 'AdditionalManifestDependencies': 's2', + 'AdditionalOptions': '/mor2', + 'AddModuleNamesToAssembly': 'd1', + 'AllowIsolation': 'false', + 'AssemblyDebug': 'true', + 'AssemblyLinkResource': 'd5', + 'BaseAddress': '23423', + 'CLRImageType': 'ForceSafeILImage', + 'CLRThreadAttribute': 'MTAThreadingAttribute', + 'CLRUnmanagedCodeCheck': 'true', + 'DataExecutionPrevention': '', + 'DelayLoadDLLs': 'd4', + 'DelaySign': 'true', + 'Driver': 'UpOnly', + 'EmbedManagedResourceFile': 'd2', + 'EnableCOMDATFolding': 'false', + 'EnableUAC': 'false', + 'EntryPointSymbol': 'f5', + 'FixedBaseAddress': 'false', + 'ForceSymbolReferences': 'd3', + 'FunctionOrder': 'fssdfsd', + 'GenerateDebugInformation': 'true', + 'GenerateMapFile': 'true', + 'HeapCommitSize': '13', + 'HeapReserveSize': '12', + 'IgnoreAllDefaultLibraries': 'true', + 'IgnoreEmbeddedIDL': 'true', + 'IgnoreSpecificDefaultLibraries': 'flob;flok', + 'ImportLibrary': 'f4', + 'KeyContainer': 'f7', + 'KeyFile': 'f6', + 'LargeAddressAware': 'true', + 'LinkErrorReporting': 'QueueForNextLogin', + 'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration', + 'ManifestFile': '$(IntDir)$(TargetFileName).2intermediate.manifest', + 'MapExports': 'true', + 'MapFileName': 'd5', + 'MergedIDLBaseFileName': 'f2', + 'MergeSections': 'f5', + 'MidlCommandFile': 'f1', + 'ModuleDefinitionFile': 'sdsd', + 'NoEntryPoint': 'true', + 'OptimizeReferences': 'true', + 'OutputFile': '$(OutDir)$(ProjectName)2.exe', + 'PerUserRedirection': 'true', + 'Profile': 'true', + 'ProfileGuidedDatabase': '$(TargetDir)$(TargetName).pgdd', + 'ProgramDatabaseFile': 'Flob.pdb', + 'RandomizedBaseAddress': 'false', + 'RegisterOutput': 'true', + 'SetChecksum': 'false', + 'ShowProgress': 'LinkVerbose', + 'StackCommitSize': '15', + 'StackReserveSize': '14', + 'StripPrivateSymbols': 'd3', + 'SubSystem': 'Console', + 'SupportUnloadOfDelayLoadedDLL': 'true', + 'SuppressStartupBanner': 'false', + 'SwapRunFromCD': 'true', + 'SwapRunFromNET': 'true', + 'TargetMachine': 'MachineX86', + 'TerminalServerAware': 'false', + 'TurnOffAssemblyGeneration': 'true', + 'TypeLibraryFile': 'f3', + 'TypeLibraryResourceID': '12', + 'UACExecutionLevel': 'RequireAdministrator', + 'UACUIAccess': 'true', + 'Version': '333'}, + 'ResourceCompile': { + 'AdditionalIncludeDirectories': 'f3', + 'AdditionalOptions': '/more3', + 'Culture': '0x0c0c', + 'IgnoreStandardIncludePath': 'true', + 'PreprocessorDefinitions': '_UNICODE;UNICODE2', + 'ResourceOutputFileName': '$(IntDir)%(Filename)3.res', + 'ShowProgress': 'true'}, + 'Manifest': { + 'AdditionalManifestFiles': 'sfsdfsd', + 'AdditionalOptions': 'afdsdafsd', + 'AssemblyIdentity': 'sddfdsadfsa', + 'ComponentFileName': 'fsdfds', + 'GenerateCatalogFiles': 'true', + 'InputResourceManifests': 'asfsfdafs', + 'OutputManifestFile': '$(TargetPath).manifestdfs', + 'RegistrarScriptFile': 'sdfsfd', + 'ReplacementsFile': 'sdffsd', + 'SuppressStartupBanner': 'false', + 'TypeLibraryFile': 'sfsd', + 'UpdateFileHashes': 'true', + 'UpdateFileHashesSearchPath': 'sfsd', + 'VerboseOutput': 'true'}, + 'ProjectReference': { + 'LinkLibraryDependencies': 'false', + 'UseLibraryDependencyInputs': 'true'}, + '': { + 'EmbedManifest': 'false', + 'GenerateManifest': 'false', + 'IgnoreImportLibrary': 'true', + 'LinkIncremental': '' + }, + 'ManifestResourceCompile': { + 'ResourceOutputFileName': + '$(IntDir)$(TargetFileName).embed.manifest.resfdsf'} + } + actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings( + msvs_settings, + self.stderr) + self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) + self._ExpectedWarnings([]) + + +if __name__ == '__main__': + unittest.main() diff --git a/deps/gyp/pylib/gyp/MSVSToolFile.py b/deps/gyp/pylib/gyp/MSVSToolFile.py new file mode 100644 index 000000000..74e529a17 --- /dev/null +++ b/deps/gyp/pylib/gyp/MSVSToolFile.py @@ -0,0 +1,58 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Visual Studio project reader/writer.""" + +import gyp.common +import gyp.easy_xml as easy_xml + + +class Writer(object): + """Visual Studio XML tool file writer.""" + + def __init__(self, tool_file_path, name): + """Initializes the tool file. + + Args: + tool_file_path: Path to the tool file. + name: Name of the tool file. + """ + self.tool_file_path = tool_file_path + self.name = name + self.rules_section = ['Rules'] + + def AddCustomBuildRule(self, name, cmd, description, + additional_dependencies, + outputs, extensions): + """Adds a rule to the tool file. + + Args: + name: Name of the rule. + description: Description of the rule. + cmd: Command line of the rule. + additional_dependencies: other files which may trigger the rule. + outputs: outputs of the rule. + extensions: extensions handled by the rule. + """ + rule = ['CustomBuildRule', + {'Name': name, + 'ExecutionDescription': description, + 'CommandLine': cmd, + 'Outputs': ';'.join(outputs), + 'FileExtensions': ';'.join(extensions), + 'AdditionalDependencies': + ';'.join(additional_dependencies) + }] + self.rules_section.append(rule) + + def WriteIfChanged(self): + """Writes the tool file.""" + content = ['VisualStudioToolFile', + {'Version': '8.00', + 'Name': self.name + }, + self.rules_section + ] + easy_xml.WriteXmlIfChanged(content, self.tool_file_path, + encoding="Windows-1252") diff --git a/deps/gyp/pylib/gyp/MSVSUserFile.py b/deps/gyp/pylib/gyp/MSVSUserFile.py new file mode 100644 index 000000000..6c07e9a89 --- /dev/null +++ b/deps/gyp/pylib/gyp/MSVSUserFile.py @@ -0,0 +1,147 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Visual Studio user preferences file writer.""" + +import os +import re +import socket # for gethostname + +import gyp.common +import gyp.easy_xml as easy_xml + + +#------------------------------------------------------------------------------ + +def _FindCommandInPath(command): + """If there are no slashes in the command given, this function + searches the PATH env to find the given command, and converts it + to an absolute path. We have to do this because MSVS is looking + for an actual file to launch a debugger on, not just a command + line. Note that this happens at GYP time, so anything needing to + be built needs to have a full path.""" + if '/' in command or '\\' in command: + # If the command already has path elements (either relative or + # absolute), then assume it is constructed properly. + return command + else: + # Search through the path list and find an existing file that + # we can access. + paths = os.environ.get('PATH','').split(os.pathsep) + for path in paths: + item = os.path.join(path, command) + if os.path.isfile(item) and os.access(item, os.X_OK): + return item + return command + +def _QuoteWin32CommandLineArgs(args): + new_args = [] + for arg in args: + # Replace all double-quotes with double-double-quotes to escape + # them for cmd shell, and then quote the whole thing if there + # are any. + if arg.find('"') != -1: + arg = '""'.join(arg.split('"')) + arg = '"%s"' % arg + + # Otherwise, if there are any spaces, quote the whole arg. + elif re.search(r'[ \t\n]', arg): + arg = '"%s"' % arg + new_args.append(arg) + return new_args + +class Writer(object): + """Visual Studio XML user user file writer.""" + + def __init__(self, user_file_path, version, name): + """Initializes the user file. + + Args: + user_file_path: Path to the user file. + version: Version info. + name: Name of the user file. + """ + self.user_file_path = user_file_path + self.version = version + self.name = name + self.configurations = {} + + def AddConfig(self, name): + """Adds a configuration to the project. + + Args: + name: Configuration name. + """ + self.configurations[name] = ['Configuration', {'Name': name}] + + def AddDebugSettings(self, config_name, command, environment = {}, + working_directory=""): + """Adds a DebugSettings node to the user file for a particular config. + + Args: + command: command line to run. First element in the list is the + executable. All elements of the command will be quoted if + necessary. + working_directory: other files which may trigger the rule. (optional) + """ + command = _QuoteWin32CommandLineArgs(command) + + abs_command = _FindCommandInPath(command[0]) + + if environment and isinstance(environment, dict): + env_list = ['%s="%s"' % (key, val) + for (key,val) in environment.iteritems()] + environment = ' '.join(env_list) + else: + environment = '' + + n_cmd = ['DebugSettings', + {'Command': abs_command, + 'WorkingDirectory': working_directory, + 'CommandArguments': " ".join(command[1:]), + 'RemoteMachine': socket.gethostname(), + 'Environment': environment, + 'EnvironmentMerge': 'true', + # Currently these are all "dummy" values that we're just setting + # in the default manner that MSVS does it. We could use some of + # these to add additional capabilities, I suppose, but they might + # not have parity with other platforms then. + 'Attach': 'false', + 'DebuggerType': '3', # 'auto' debugger + 'Remote': '1', + 'RemoteCommand': '', + 'HttpUrl': '', + 'PDBPath': '', + 'SQLDebugging': '', + 'DebuggerFlavor': '0', + 'MPIRunCommand': '', + 'MPIRunArguments': '', + 'MPIRunWorkingDirectory': '', + 'ApplicationCommand': '', + 'ApplicationArguments': '', + 'ShimCommand': '', + 'MPIAcceptMode': '', + 'MPIAcceptFilter': '' + }] + + # Find the config, and add it if it doesn't exist. + if config_name not in self.configurations: + self.AddConfig(config_name) + + # Add the DebugSettings onto the appropriate config. + self.configurations[config_name].append(n_cmd) + + def WriteIfChanged(self): + """Writes the user file.""" + configs = ['Configurations'] + for config, spec in sorted(self.configurations.iteritems()): + configs.append(spec) + + content = ['VisualStudioUserFile', + {'Version': self.version.ProjectVersion(), + 'Name': self.name + }, + configs] + easy_xml.WriteXmlIfChanged(content, self.user_file_path, + encoding="Windows-1252") diff --git a/deps/gyp/pylib/gyp/MSVSUtil.py b/deps/gyp/pylib/gyp/MSVSUtil.py new file mode 100644 index 000000000..fbf3ed2e3 --- /dev/null +++ b/deps/gyp/pylib/gyp/MSVSUtil.py @@ -0,0 +1,268 @@ +# Copyright (c) 2013 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Utility functions shared amongst the Windows generators.""" + +import copy +import os + + +_TARGET_TYPE_EXT = { + 'executable': '.exe', + 'loadable_module': '.dll', + 'shared_library': '.dll', +} + + +def _GetLargePdbShimCcPath(): + """Returns the path of the large_pdb_shim.cc file.""" + this_dir = os.path.abspath(os.path.dirname(__file__)) + src_dir = os.path.abspath(os.path.join(this_dir, '..', '..')) + win_data_dir = os.path.join(src_dir, 'data', 'win') + large_pdb_shim_cc = os.path.join(win_data_dir, 'large-pdb-shim.cc') + return large_pdb_shim_cc + + +def _DeepCopySomeKeys(in_dict, keys): + """Performs a partial deep-copy on |in_dict|, only copying the keys in |keys|. + + Arguments: + in_dict: The dictionary to copy. + keys: The keys to be copied. If a key is in this list and doesn't exist in + |in_dict| this is not an error. + Returns: + The partially deep-copied dictionary. + """ + d = {} + for key in keys: + if key not in in_dict: + continue + d[key] = copy.deepcopy(in_dict[key]) + return d + + +def _SuffixName(name, suffix): + """Add a suffix to the end of a target. + + Arguments: + name: name of the target (foo#target) + suffix: the suffix to be added + Returns: + Target name with suffix added (foo_suffix#target) + """ + parts = name.rsplit('#', 1) + parts[0] = '%s_%s' % (parts[0], suffix) + return '#'.join(parts) + + +def _ShardName(name, number): + """Add a shard number to the end of a target. + + Arguments: + name: name of the target (foo#target) + number: shard number + Returns: + Target name with shard added (foo_1#target) + """ + return _SuffixName(name, str(number)) + + +def ShardTargets(target_list, target_dicts): + """Shard some targets apart to work around the linkers limits. + + Arguments: + target_list: List of target pairs: 'base/base.gyp:base'. + target_dicts: Dict of target properties keyed on target pair. + Returns: + Tuple of the new sharded versions of the inputs. + """ + # Gather the targets to shard, and how many pieces. + targets_to_shard = {} + for t in target_dicts: + shards = int(target_dicts[t].get('msvs_shard', 0)) + if shards: + targets_to_shard[t] = shards + # Shard target_list. + new_target_list = [] + for t in target_list: + if t in targets_to_shard: + for i in range(targets_to_shard[t]): + new_target_list.append(_ShardName(t, i)) + else: + new_target_list.append(t) + # Shard target_dict. + new_target_dicts = {} + for t in target_dicts: + if t in targets_to_shard: + for i in range(targets_to_shard[t]): + name = _ShardName(t, i) + new_target_dicts[name] = copy.copy(target_dicts[t]) + new_target_dicts[name]['target_name'] = _ShardName( + new_target_dicts[name]['target_name'], i) + sources = new_target_dicts[name].get('sources', []) + new_sources = [] + for pos in range(i, len(sources), targets_to_shard[t]): + new_sources.append(sources[pos]) + new_target_dicts[name]['sources'] = new_sources + else: + new_target_dicts[t] = target_dicts[t] + # Shard dependencies. + for t in new_target_dicts: + for deptype in ('dependencies', 'dependencies_original'): + dependencies = copy.copy(new_target_dicts[t].get(deptype, [])) + new_dependencies = [] + for d in dependencies: + if d in targets_to_shard: + for i in range(targets_to_shard[d]): + new_dependencies.append(_ShardName(d, i)) + else: + new_dependencies.append(d) + new_target_dicts[t][deptype] = new_dependencies + + return (new_target_list, new_target_dicts) + + +def _GetPdbPath(target_dict, config_name, vars): + """Returns the path to the PDB file that will be generated by a given + configuration. + + The lookup proceeds as follows: + - Look for an explicit path in the VCLinkerTool configuration block. + - Look for an 'msvs_large_pdb_path' variable. + - Use '<(PRODUCT_DIR)/<(product_name).(exe|dll).pdb' if 'product_name' is + specified. + - Use '<(PRODUCT_DIR)/<(target_name).(exe|dll).pdb'. + + Arguments: + target_dict: The target dictionary to be searched. + config_name: The name of the configuration of interest. + vars: A dictionary of common GYP variables with generator-specific values. + Returns: + The path of the corresponding PDB file. + """ + config = target_dict['configurations'][config_name] + msvs = config.setdefault('msvs_settings', {}) + + linker = msvs.get('VCLinkerTool', {}) + + pdb_path = linker.get('ProgramDatabaseFile') + if pdb_path: + return pdb_path + + variables = target_dict.get('variables', {}) + pdb_path = variables.get('msvs_large_pdb_path', None) + if pdb_path: + return pdb_path + + + pdb_base = target_dict.get('product_name', target_dict['target_name']) + pdb_base = '%s%s.pdb' % (pdb_base, _TARGET_TYPE_EXT[target_dict['type']]) + pdb_path = vars['PRODUCT_DIR'] + '/' + pdb_base + + return pdb_path + + +def InsertLargePdbShims(target_list, target_dicts, vars): + """Insert a shim target that forces the linker to use 4KB pagesize PDBs. + + This is a workaround for targets with PDBs greater than 1GB in size, the + limit for the 1KB pagesize PDBs created by the linker by default. + + Arguments: + target_list: List of target pairs: 'base/base.gyp:base'. + target_dicts: Dict of target properties keyed on target pair. + vars: A dictionary of common GYP variables with generator-specific values. + Returns: + Tuple of the shimmed version of the inputs. + """ + # Determine which targets need shimming. + targets_to_shim = [] + for t in target_dicts: + target_dict = target_dicts[t] + + # We only want to shim targets that have msvs_large_pdb enabled. + if not int(target_dict.get('msvs_large_pdb', 0)): + continue + # This is intended for executable, shared_library and loadable_module + # targets where every configuration is set up to produce a PDB output. + # If any of these conditions is not true then the shim logic will fail + # below. + targets_to_shim.append(t) + + large_pdb_shim_cc = _GetLargePdbShimCcPath() + + for t in targets_to_shim: + target_dict = target_dicts[t] + target_name = target_dict.get('target_name') + + base_dict = _DeepCopySomeKeys(target_dict, + ['configurations', 'default_configuration', 'toolset']) + + # This is the dict for copying the source file (part of the GYP tree) + # to the intermediate directory of the project. This is necessary because + # we can't always build a relative path to the shim source file (on Windows + # GYP and the project may be on different drives), and Ninja hates absolute + # paths (it ends up generating the .obj and .obj.d alongside the source + # file, polluting GYPs tree). + copy_suffix = 'large_pdb_copy' + copy_target_name = target_name + '_' + copy_suffix + full_copy_target_name = _SuffixName(t, copy_suffix) + shim_cc_basename = os.path.basename(large_pdb_shim_cc) + shim_cc_dir = vars['SHARED_INTERMEDIATE_DIR'] + '/' + copy_target_name + shim_cc_path = shim_cc_dir + '/' + shim_cc_basename + copy_dict = copy.deepcopy(base_dict) + copy_dict['target_name'] = copy_target_name + copy_dict['type'] = 'none' + copy_dict['sources'] = [ large_pdb_shim_cc ] + copy_dict['copies'] = [{ + 'destination': shim_cc_dir, + 'files': [ large_pdb_shim_cc ] + }] + + # This is the dict for the PDB generating shim target. It depends on the + # copy target. + shim_suffix = 'large_pdb_shim' + shim_target_name = target_name + '_' + shim_suffix + full_shim_target_name = _SuffixName(t, shim_suffix) + shim_dict = copy.deepcopy(base_dict) + shim_dict['target_name'] = shim_target_name + shim_dict['type'] = 'static_library' + shim_dict['sources'] = [ shim_cc_path ] + shim_dict['dependencies'] = [ full_copy_target_name ] + + # Set up the shim to output its PDB to the same location as the final linker + # target. + for config_name, config in shim_dict.get('configurations').iteritems(): + pdb_path = _GetPdbPath(target_dict, config_name, vars) + + # A few keys that we don't want to propagate. + for key in ['msvs_precompiled_header', 'msvs_precompiled_source', 'test']: + config.pop(key, None) + + msvs = config.setdefault('msvs_settings', {}) + + # Update the compiler directives in the shim target. + compiler = msvs.setdefault('VCCLCompilerTool', {}) + compiler['DebugInformationFormat'] = '3' + compiler['ProgramDataBaseFileName'] = pdb_path + + # Set the explicit PDB path in the appropriate configuration of the + # original target. + config = target_dict['configurations'][config_name] + msvs = config.setdefault('msvs_settings', {}) + linker = msvs.setdefault('VCLinkerTool', {}) + linker['GenerateDebugInformation'] = 'true' + linker['ProgramDatabaseFile'] = pdb_path + + # Add the new targets. They must go to the beginning of the list so that + # the dependency generation works as expected in ninja. + target_list.insert(0, full_copy_target_name) + target_list.insert(0, full_shim_target_name) + target_dicts[full_copy_target_name] = copy_dict + target_dicts[full_shim_target_name] = shim_dict + + # Update the original target to depend on the shim target. + target_dict.setdefault('dependencies', []).append(full_shim_target_name) + + return (target_list, target_dicts) diff --git a/deps/gyp/pylib/gyp/MSVSVersion.py b/deps/gyp/pylib/gyp/MSVSVersion.py new file mode 100644 index 000000000..bcd6122f2 --- /dev/null +++ b/deps/gyp/pylib/gyp/MSVSVersion.py @@ -0,0 +1,409 @@ +# Copyright (c) 2013 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Handle version information related to Visual Stuio.""" + +import errno +import os +import re +import subprocess +import sys +import gyp +import glob + + +class VisualStudioVersion(object): + """Information regarding a version of Visual Studio.""" + + def __init__(self, short_name, description, + solution_version, project_version, flat_sln, uses_vcxproj, + path, sdk_based, default_toolset=None): + self.short_name = short_name + self.description = description + self.solution_version = solution_version + self.project_version = project_version + self.flat_sln = flat_sln + self.uses_vcxproj = uses_vcxproj + self.path = path + self.sdk_based = sdk_based + self.default_toolset = default_toolset + + def ShortName(self): + return self.short_name + + def Description(self): + """Get the full description of the version.""" + return self.description + + def SolutionVersion(self): + """Get the version number of the sln files.""" + return self.solution_version + + def ProjectVersion(self): + """Get the version number of the vcproj or vcxproj files.""" + return self.project_version + + def FlatSolution(self): + return self.flat_sln + + def UsesVcxproj(self): + """Returns true if this version uses a vcxproj file.""" + return self.uses_vcxproj + + def ProjectExtension(self): + """Returns the file extension for the project.""" + return self.uses_vcxproj and '.vcxproj' or '.vcproj' + + def Path(self): + """Returns the path to Visual Studio installation.""" + return self.path + + def ToolPath(self, tool): + """Returns the path to a given compiler tool. """ + return os.path.normpath(os.path.join(self.path, "VC/bin", tool)) + + def DefaultToolset(self): + """Returns the msbuild toolset version that will be used in the absence + of a user override.""" + return self.default_toolset + + def SetupScript(self, target_arch): + """Returns a command (with arguments) to be used to set up the + environment.""" + # Check if we are running in the SDK command line environment and use + # the setup script from the SDK if so. |target_arch| should be either + # 'x86' or 'x64'. + assert target_arch in ('x86', 'x64') + sdk_dir = os.environ.get('WindowsSDKDir') + if self.sdk_based and sdk_dir: + return [os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd')), + '/' + target_arch] + else: + # We don't use VC/vcvarsall.bat for x86 because vcvarsall calls + # vcvars32, which it can only find if VS??COMNTOOLS is set, which it + # isn't always. + if target_arch == 'x86': + if self.short_name == '2013' and ( + os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or + os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'): + # VS2013 non-Express has a x64-x86 cross that we want to prefer. + return [os.path.normpath( + os.path.join(self.path, 'VC/vcvarsall.bat')), 'amd64_x86'] + # Otherwise, the standard x86 compiler. + return [os.path.normpath( + os.path.join(self.path, 'Common7/Tools/vsvars32.bat'))] + else: + assert target_arch == 'x64' + arg = 'x86_amd64' + # Use the 64-on-64 compiler if we're not using an express + # edition and we're running on a 64bit OS. + if self.short_name[-1] != 'e' and ( + os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or + os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'): + arg = 'amd64' + return [os.path.normpath( + os.path.join(self.path, 'VC/vcvarsall.bat')), arg] + + +def _RegistryQueryBase(sysdir, key, value): + """Use reg.exe to read a particular key. + + While ideally we might use the win32 module, we would like gyp to be + python neutral, so for instance cygwin python lacks this module. + + Arguments: + sysdir: The system subdirectory to attempt to launch reg.exe from. + key: The registry key to read from. + value: The particular value to read. + Return: + stdout from reg.exe, or None for failure. + """ + # Skip if not on Windows or Python Win32 setup issue + if sys.platform not in ('win32', 'cygwin'): + return None + # Setup params to pass to and attempt to launch reg.exe + cmd = [os.path.join(os.environ.get('WINDIR', ''), sysdir, 'reg.exe'), + 'query', key] + if value: + cmd.extend(['/v', value]) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + # Obtain the stdout from reg.exe, reading to the end so p.returncode is valid + # Note that the error text may be in [1] in some cases + text = p.communicate()[0] + # Check return code from reg.exe; officially 0==success and 1==error + if p.returncode: + return None + return text + + +def _RegistryQuery(key, value=None): + """Use reg.exe to read a particular key through _RegistryQueryBase. + + First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If + that fails, it falls back to System32. Sysnative is available on Vista and + up and available on Windows Server 2003 and XP through KB patch 942589. Note + that Sysnative will always fail if using 64-bit python due to it being a + virtual directory and System32 will work correctly in the first place. + + KB 942589 - http://support.microsoft.com/kb/942589/en-us. + + Arguments: + key: The registry key. + value: The particular registry value to read (optional). + Return: + stdout from reg.exe, or None for failure. + """ + text = None + try: + text = _RegistryQueryBase('Sysnative', key, value) + except OSError, e: + if e.errno == errno.ENOENT: + text = _RegistryQueryBase('System32', key, value) + else: + raise + return text + + +def _RegistryGetValue(key, value): + """Use reg.exe to obtain the value of a registry key. + + Args: + key: The registry key. + value: The particular registry value to read. + Return: + contents of the registry key's value, or None on failure. + """ + text = _RegistryQuery(key, value) + if not text: + return None + # Extract value. + match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text) + if not match: + return None + return match.group(1) + + +def _RegistryKeyExists(key): + """Use reg.exe to see if a key exists. + + Args: + key: The registry key to check. + Return: + True if the key exists + """ + if not _RegistryQuery(key): + return False + return True + + +def _CreateVersion(name, path, sdk_based=False): + """Sets up MSVS project generation. + + Setup is based off the GYP_MSVS_VERSION environment variable or whatever is + autodetected if GYP_MSVS_VERSION is not explicitly specified. If a version is + passed in that doesn't match a value in versions python will throw a error. + """ + if path: + path = os.path.normpath(path) + versions = { + '2013': VisualStudioVersion('2013', + 'Visual Studio 2013', + solution_version='13.00', + project_version='12.0', + flat_sln=False, + uses_vcxproj=True, + path=path, + sdk_based=sdk_based, + default_toolset='v120'), + '2013e': VisualStudioVersion('2013e', + 'Visual Studio 2013', + solution_version='13.00', + project_version='12.0', + flat_sln=True, + uses_vcxproj=True, + path=path, + sdk_based=sdk_based, + default_toolset='v120'), + '2012': VisualStudioVersion('2012', + 'Visual Studio 2012', + solution_version='12.00', + project_version='4.0', + flat_sln=False, + uses_vcxproj=True, + path=path, + sdk_based=sdk_based, + default_toolset='v110'), + '2012e': VisualStudioVersion('2012e', + 'Visual Studio 2012', + solution_version='12.00', + project_version='4.0', + flat_sln=True, + uses_vcxproj=True, + path=path, + sdk_based=sdk_based, + default_toolset='v110'), + '2010': VisualStudioVersion('2010', + 'Visual Studio 2010', + solution_version='11.00', + project_version='4.0', + flat_sln=False, + uses_vcxproj=True, + path=path, + sdk_based=sdk_based), + '2010e': VisualStudioVersion('2010e', + 'Visual C++ Express 2010', + solution_version='11.00', + project_version='4.0', + flat_sln=True, + uses_vcxproj=True, + path=path, + sdk_based=sdk_based), + '2008': VisualStudioVersion('2008', + 'Visual Studio 2008', + solution_version='10.00', + project_version='9.00', + flat_sln=False, + uses_vcxproj=False, + path=path, + sdk_based=sdk_based), + '2008e': VisualStudioVersion('2008e', + 'Visual Studio 2008', + solution_version='10.00', + project_version='9.00', + flat_sln=True, + uses_vcxproj=False, + path=path, + sdk_based=sdk_based), + '2005': VisualStudioVersion('2005', + 'Visual Studio 2005', + solution_version='9.00', + project_version='8.00', + flat_sln=False, + uses_vcxproj=False, + path=path, + sdk_based=sdk_based), + '2005e': VisualStudioVersion('2005e', + 'Visual Studio 2005', + solution_version='9.00', + project_version='8.00', + flat_sln=True, + uses_vcxproj=False, + path=path, + sdk_based=sdk_based), + } + return versions[str(name)] + + +def _ConvertToCygpath(path): + """Convert to cygwin path if we are using cygwin.""" + if sys.platform == 'cygwin': + p = subprocess.Popen(['cygpath', path], stdout=subprocess.PIPE) + path = p.communicate()[0].strip() + return path + + +def _DetectVisualStudioVersions(versions_to_check, force_express): + """Collect the list of installed visual studio versions. + + Returns: + A list of visual studio versions installed in descending order of + usage preference. + Base this on the registry and a quick check if devenv.exe exists. + Only versions 8-10 are considered. + Possibilities are: + 2005(e) - Visual Studio 2005 (8) + 2008(e) - Visual Studio 2008 (9) + 2010(e) - Visual Studio 2010 (10) + 2012(e) - Visual Studio 2012 (11) + 2013(e) - Visual Studio 2013 (11) + Where (e) is e for express editions of MSVS and blank otherwise. + """ + version_to_year = { + '8.0': '2005', + '9.0': '2008', + '10.0': '2010', + '11.0': '2012', + '12.0': '2013', + } + versions = [] + for version in versions_to_check: + # Old method of searching for which VS version is installed + # We don't use the 2010-encouraged-way because we also want to get the + # path to the binaries, which it doesn't offer. + keys = [r'HKLM\Software\Microsoft\VisualStudio\%s' % version, + r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version, + r'HKLM\Software\Microsoft\VCExpress\%s' % version, + r'HKLM\Software\Wow6432Node\Microsoft\VCExpress\%s' % version] + for index in range(len(keys)): + path = _RegistryGetValue(keys[index], 'InstallDir') + if not path: + continue + path = _ConvertToCygpath(path) + # Check for full. + full_path = os.path.join(path, 'devenv.exe') + express_path = os.path.join(path, '*express.exe') + if not force_express and os.path.exists(full_path): + # Add this one. + versions.append(_CreateVersion(version_to_year[version], + os.path.join(path, '..', '..'))) + # Check for express. + elif glob.glob(express_path): + # Add this one. + versions.append(_CreateVersion(version_to_year[version] + 'e', + os.path.join(path, '..', '..'))) + + # The old method above does not work when only SDK is installed. + keys = [r'HKLM\Software\Microsoft\VisualStudio\SxS\VC7', + r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VC7'] + for index in range(len(keys)): + path = _RegistryGetValue(keys[index], version) + if not path: + continue + path = _ConvertToCygpath(path) + versions.append(_CreateVersion(version_to_year[version] + 'e', + os.path.join(path, '..'), sdk_based=True)) + + return versions + + +def SelectVisualStudioVersion(version='auto'): + """Select which version of Visual Studio projects to generate. + + Arguments: + version: Hook to allow caller to force a particular version (vs auto). + Returns: + An object representing a visual studio project format version. + """ + # In auto mode, check environment variable for override. + if version == 'auto': + version = os.environ.get('GYP_MSVS_VERSION', 'auto') + version_map = { + 'auto': ('12.0', '10.0', '9.0', '8.0', '11.0'), + '2005': ('8.0',), + '2005e': ('8.0',), + '2008': ('9.0',), + '2008e': ('9.0',), + '2010': ('10.0',), + '2010e': ('10.0',), + '2012': ('11.0',), + '2012e': ('11.0',), + '2013': ('12.0',), + '2013e': ('12.0',), + } + override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH') + if override_path: + msvs_version = os.environ.get('GYP_MSVS_VERSION') + if not msvs_version: + raise ValueError('GYP_MSVS_OVERRIDE_PATH requires GYP_MSVS_VERSION to be ' + 'set to a particular version (e.g. 2010e).') + return _CreateVersion(msvs_version, override_path, sdk_based=True) + version = str(version) + versions = _DetectVisualStudioVersions(version_map[version], 'e' in version) + if not versions: + if version == 'auto': + # Default to 2005 if we couldn't find anything + return _CreateVersion('2005', None) + else: + return _CreateVersion(version, None) + return versions[0] diff --git a/deps/gyp/pylib/gyp/__init__.py b/deps/gyp/pylib/gyp/__init__.py new file mode 100755 index 000000000..30edea567 --- /dev/null +++ b/deps/gyp/pylib/gyp/__init__.py @@ -0,0 +1,537 @@ +#!/usr/bin/env python + +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import copy +import gyp.input +import optparse +import os.path +import re +import shlex +import sys +import traceback +from gyp.common import GypError + +# Default debug modes for GYP +debug = {} + +# List of "official" debug modes, but you can use anything you like. +DEBUG_GENERAL = 'general' +DEBUG_VARIABLES = 'variables' +DEBUG_INCLUDES = 'includes' + + +def DebugOutput(mode, message, *args): + if 'all' in gyp.debug or mode in gyp.debug: + ctx = ('unknown', 0, 'unknown') + try: + f = traceback.extract_stack(limit=2) + if f: + ctx = f[0][:3] + except: + pass + if args: + message %= args + print '%s:%s:%d:%s %s' % (mode.upper(), os.path.basename(ctx[0]), + ctx[1], ctx[2], message) + +def FindBuildFiles(): + extension = '.gyp' + files = os.listdir(os.getcwd()) + build_files = [] + for file in files: + if file.endswith(extension): + build_files.append(file) + return build_files + + +def Load(build_files, format, default_variables={}, + includes=[], depth='.', params=None, check=False, + circular_check=True): + """ + Loads one or more specified build files. + default_variables and includes will be copied before use. + Returns the generator for the specified format and the + data returned by loading the specified build files. + """ + if params is None: + params = {} + + flavor = None + if '-' in format: + format, params['flavor'] = format.split('-', 1) + + default_variables = copy.copy(default_variables) + + # Default variables provided by this program and its modules should be + # named WITH_CAPITAL_LETTERS to provide a distinct "best practice" namespace, + # avoiding collisions with user and automatic variables. + default_variables['GENERATOR'] = format + + # Format can be a custom python file, or by default the name of a module + # within gyp.generator. + if format.endswith('.py'): + generator_name = os.path.splitext(format)[0] + path, generator_name = os.path.split(generator_name) + + # Make sure the path to the custom generator is in sys.path + # Don't worry about removing it once we are done. Keeping the path + # to each generator that is used in sys.path is likely harmless and + # arguably a good idea. + path = os.path.abspath(path) + if path not in sys.path: + sys.path.insert(0, path) + else: + generator_name = 'gyp.generator.' + format + + # These parameters are passed in order (as opposed to by key) + # because ActivePython cannot handle key parameters to __import__. + generator = __import__(generator_name, globals(), locals(), generator_name) + for (key, val) in generator.generator_default_variables.items(): + default_variables.setdefault(key, val) + + # Give the generator the opportunity to set additional variables based on + # the params it will receive in the output phase. + if getattr(generator, 'CalculateVariables', None): + generator.CalculateVariables(default_variables, params) + + # Give the generator the opportunity to set generator_input_info based on + # the params it will receive in the output phase. + if getattr(generator, 'CalculateGeneratorInputInfo', None): + generator.CalculateGeneratorInputInfo(params) + + # Fetch the generator specific info that gets fed to input, we use getattr + # so we can default things and the generators only have to provide what + # they need. + generator_input_info = { + 'non_configuration_keys': + getattr(generator, 'generator_additional_non_configuration_keys', []), + 'path_sections': + getattr(generator, 'generator_additional_path_sections', []), + 'extra_sources_for_rules': + getattr(generator, 'generator_extra_sources_for_rules', []), + 'generator_supports_multiple_toolsets': + getattr(generator, 'generator_supports_multiple_toolsets', False), + 'generator_wants_static_library_dependencies_adjusted': + getattr(generator, + 'generator_wants_static_library_dependencies_adjusted', True), + 'generator_wants_sorted_dependencies': + getattr(generator, 'generator_wants_sorted_dependencies', False), + 'generator_filelist_paths': + getattr(generator, 'generator_filelist_paths', None), + } + + # Process the input specific to this generator. + result = gyp.input.Load(build_files, default_variables, includes[:], + depth, generator_input_info, check, circular_check, + params['parallel'], params['root_targets']) + return [generator] + result + +def NameValueListToDict(name_value_list): + """ + Takes an array of strings of the form 'NAME=VALUE' and creates a dictionary + of the pairs. If a string is simply NAME, then the value in the dictionary + is set to True. If VALUE can be converted to an integer, it is. + """ + result = { } + for item in name_value_list: + tokens = item.split('=', 1) + if len(tokens) == 2: + # If we can make it an int, use that, otherwise, use the string. + try: + token_value = int(tokens[1]) + except ValueError: + token_value = tokens[1] + # Set the variable to the supplied value. + result[tokens[0]] = token_value + else: + # No value supplied, treat it as a boolean and set it. + result[tokens[0]] = True + return result + +def ShlexEnv(env_name): + flags = os.environ.get(env_name, []) + if flags: + flags = shlex.split(flags) + return flags + +def FormatOpt(opt, value): + if opt.startswith('--'): + return '%s=%s' % (opt, value) + return opt + value + +def RegenerateAppendFlag(flag, values, predicate, env_name, options): + """Regenerate a list of command line flags, for an option of action='append'. + + The |env_name|, if given, is checked in the environment and used to generate + an initial list of options, then the options that were specified on the + command line (given in |values|) are appended. This matches the handling of + environment variables and command line flags where command line flags override + the environment, while not requiring the environment to be set when the flags + are used again. + """ + flags = [] + if options.use_environment and env_name: + for flag_value in ShlexEnv(env_name): + value = FormatOpt(flag, predicate(flag_value)) + if value in flags: + flags.remove(value) + flags.append(value) + if values: + for flag_value in values: + flags.append(FormatOpt(flag, predicate(flag_value))) + return flags + +def RegenerateFlags(options): + """Given a parsed options object, and taking the environment variables into + account, returns a list of flags that should regenerate an equivalent options + object (even in the absence of the environment variables.) + + Any path options will be normalized relative to depth. + + The format flag is not included, as it is assumed the calling generator will + set that as appropriate. + """ + def FixPath(path): + path = gyp.common.FixIfRelativePath(path, options.depth) + if not path: + return os.path.curdir + return path + + def Noop(value): + return value + + # We always want to ignore the environment when regenerating, to avoid + # duplicate or changed flags in the environment at the time of regeneration. + flags = ['--ignore-environment'] + for name, metadata in options._regeneration_metadata.iteritems(): + opt = metadata['opt'] + value = getattr(options, name) + value_predicate = metadata['type'] == 'path' and FixPath or Noop + action = metadata['action'] + env_name = metadata['env_name'] + if action == 'append': + flags.extend(RegenerateAppendFlag(opt, value, value_predicate, + env_name, options)) + elif action in ('store', None): # None is a synonym for 'store'. + if value: + flags.append(FormatOpt(opt, value_predicate(value))) + elif options.use_environment and env_name and os.environ.get(env_name): + flags.append(FormatOpt(opt, value_predicate(os.environ.get(env_name)))) + elif action in ('store_true', 'store_false'): + if ((action == 'store_true' and value) or + (action == 'store_false' and not value)): + flags.append(opt) + elif options.use_environment and env_name: + print >>sys.stderr, ('Warning: environment regeneration unimplemented ' + 'for %s flag %r env_name %r' % (action, opt, + env_name)) + else: + print >>sys.stderr, ('Warning: regeneration unimplemented for action %r ' + 'flag %r' % (action, opt)) + + return flags + +class RegeneratableOptionParser(optparse.OptionParser): + def __init__(self): + self.__regeneratable_options = {} + optparse.OptionParser.__init__(self) + + def add_option(self, *args, **kw): + """Add an option to the parser. + + This accepts the same arguments as OptionParser.add_option, plus the + following: + regenerate: can be set to False to prevent this option from being included + in regeneration. + env_name: name of environment variable that additional values for this + option come from. + type: adds type='path', to tell the regenerator that the values of + this option need to be made relative to options.depth + """ + env_name = kw.pop('env_name', None) + if 'dest' in kw and kw.pop('regenerate', True): + dest = kw['dest'] + + # The path type is needed for regenerating, for optparse we can just treat + # it as a string. + type = kw.get('type') + if type == 'path': + kw['type'] = 'string' + + self.__regeneratable_options[dest] = { + 'action': kw.get('action'), + 'type': type, + 'env_name': env_name, + 'opt': args[0], + } + + optparse.OptionParser.add_option(self, *args, **kw) + + def parse_args(self, *args): + values, args = optparse.OptionParser.parse_args(self, *args) + values._regeneration_metadata = self.__regeneratable_options + return values, args + +def gyp_main(args): + my_name = os.path.basename(sys.argv[0]) + + parser = RegeneratableOptionParser() + usage = 'usage: %s [options ...] [build_file ...]' + parser.set_usage(usage.replace('%s', '%prog')) + parser.add_option('--build', dest='configs', action='append', + help='configuration for build after project generation') + parser.add_option('--check', dest='check', action='store_true', + help='check format of gyp files') + parser.add_option('--config-dir', dest='config_dir', action='store', + env_name='GYP_CONFIG_DIR', default=None, + help='The location for configuration files like ' + 'include.gypi.') + parser.add_option('-d', '--debug', dest='debug', metavar='DEBUGMODE', + action='append', default=[], help='turn on a debugging ' + 'mode for debugging GYP. Supported modes are "variables", ' + '"includes" and "general" or "all" for all of them.') + parser.add_option('-D', dest='defines', action='append', metavar='VAR=VAL', + env_name='GYP_DEFINES', + help='sets variable VAR to value VAL') + parser.add_option('--depth', dest='depth', metavar='PATH', type='path', + help='set DEPTH gyp variable to a relative path to PATH') + parser.add_option('-f', '--format', dest='formats', action='append', + env_name='GYP_GENERATORS', regenerate=False, + help='output formats to generate') + parser.add_option('-G', dest='generator_flags', action='append', default=[], + metavar='FLAG=VAL', env_name='GYP_GENERATOR_FLAGS', + help='sets generator flag FLAG to VAL') + parser.add_option('--generator-output', dest='generator_output', + action='store', default=None, metavar='DIR', type='path', + env_name='GYP_GENERATOR_OUTPUT', + help='puts generated build files under DIR') + parser.add_option('--ignore-environment', dest='use_environment', + action='store_false', default=True, regenerate=False, + help='do not read options from environment variables') + parser.add_option('-I', '--include', dest='includes', action='append', + metavar='INCLUDE', type='path', + help='files to include in all loaded .gyp files') + # --no-circular-check disables the check for circular relationships between + # .gyp files. These relationships should not exist, but they've only been + # observed to be harmful with the Xcode generator. Chromium's .gyp files + # currently have some circular relationships on non-Mac platforms, so this + # option allows the strict behavior to be used on Macs and the lenient + # behavior to be used elsewhere. + # TODO(mark): Remove this option when http://crbug.com/35878 is fixed. + parser.add_option('--no-circular-check', dest='circular_check', + action='store_false', default=True, regenerate=False, + help="don't check for circular relationships between files") + parser.add_option('--no-parallel', action='store_true', default=False, + help='Disable multiprocessing') + parser.add_option('-S', '--suffix', dest='suffix', default='', + help='suffix to add to generated files') + parser.add_option('--toplevel-dir', dest='toplevel_dir', action='store', + default=None, metavar='DIR', type='path', + help='directory to use as the root of the source tree') + parser.add_option('-R', '--root-target', dest='root_targets', + action='append', metavar='TARGET', + help='include only TARGET and its deep dependencies') + + options, build_files_arg = parser.parse_args(args) + build_files = build_files_arg + + # Set up the configuration directory (defaults to ~/.gyp) + if not options.config_dir: + home = None + home_dot_gyp = None + if options.use_environment: + home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None) + if home_dot_gyp: + home_dot_gyp = os.path.expanduser(home_dot_gyp) + + if not home_dot_gyp: + home_vars = ['HOME'] + if sys.platform in ('cygwin', 'win32'): + home_vars.append('USERPROFILE') + for home_var in home_vars: + home = os.getenv(home_var) + if home != None: + home_dot_gyp = os.path.join(home, '.gyp') + if not os.path.exists(home_dot_gyp): + home_dot_gyp = None + else: + break + else: + home_dot_gyp = os.path.expanduser(options.config_dir) + + if home_dot_gyp and not os.path.exists(home_dot_gyp): + home_dot_gyp = None + + if not options.formats: + # If no format was given on the command line, then check the env variable. + generate_formats = [] + if options.use_environment: + generate_formats = os.environ.get('GYP_GENERATORS', []) + if generate_formats: + generate_formats = re.split('[\s,]', generate_formats) + if generate_formats: + options.formats = generate_formats + else: + # Nothing in the variable, default based on platform. + if sys.platform == 'darwin': + options.formats = ['xcode'] + elif sys.platform in ('win32', 'cygwin'): + options.formats = ['msvs'] + else: + options.formats = ['make'] + + if not options.generator_output and options.use_environment: + g_o = os.environ.get('GYP_GENERATOR_OUTPUT') + if g_o: + options.generator_output = g_o + + options.parallel = not options.no_parallel + + for mode in options.debug: + gyp.debug[mode] = 1 + + # Do an extra check to avoid work when we're not debugging. + if DEBUG_GENERAL in gyp.debug: + DebugOutput(DEBUG_GENERAL, 'running with these options:') + for option, value in sorted(options.__dict__.items()): + if option[0] == '_': + continue + if isinstance(value, basestring): + DebugOutput(DEBUG_GENERAL, " %s: '%s'", option, value) + else: + DebugOutput(DEBUG_GENERAL, " %s: %s", option, value) + + if not build_files: + build_files = FindBuildFiles() + if not build_files: + raise GypError((usage + '\n\n%s: error: no build_file') % + (my_name, my_name)) + + # TODO(mark): Chromium-specific hack! + # For Chromium, the gyp "depth" variable should always be a relative path + # to Chromium's top-level "src" directory. If no depth variable was set + # on the command line, try to find a "src" directory by looking at the + # absolute path to each build file's directory. The first "src" component + # found will be treated as though it were the path used for --depth. + if not options.depth: + for build_file in build_files: + build_file_dir = os.path.abspath(os.path.dirname(build_file)) + build_file_dir_components = build_file_dir.split(os.path.sep) + components_len = len(build_file_dir_components) + for index in xrange(components_len - 1, -1, -1): + if build_file_dir_components[index] == 'src': + options.depth = os.path.sep.join(build_file_dir_components) + break + del build_file_dir_components[index] + + # If the inner loop found something, break without advancing to another + # build file. + if options.depth: + break + + if not options.depth: + raise GypError('Could not automatically locate src directory. This is' + 'a temporary Chromium feature that will be removed. Use' + '--depth as a workaround.') + + # If toplevel-dir is not set, we assume that depth is the root of our source + # tree. + if not options.toplevel_dir: + options.toplevel_dir = options.depth + + # -D on the command line sets variable defaults - D isn't just for define, + # it's for default. Perhaps there should be a way to force (-F?) a + # variable's value so that it can't be overridden by anything else. + cmdline_default_variables = {} + defines = [] + if options.use_environment: + defines += ShlexEnv('GYP_DEFINES') + if options.defines: + defines += options.defines + cmdline_default_variables = NameValueListToDict(defines) + if DEBUG_GENERAL in gyp.debug: + DebugOutput(DEBUG_GENERAL, + "cmdline_default_variables: %s", cmdline_default_variables) + + # Set up includes. + includes = [] + + # If ~/.gyp/include.gypi exists, it'll be forcibly included into every + # .gyp file that's loaded, before anything else is included. + if home_dot_gyp != None: + default_include = os.path.join(home_dot_gyp, 'include.gypi') + if os.path.exists(default_include): + print 'Using overrides found in ' + default_include + includes.append(default_include) + + # Command-line --include files come after the default include. + if options.includes: + includes.extend(options.includes) + + # Generator flags should be prefixed with the target generator since they + # are global across all generator runs. + gen_flags = [] + if options.use_environment: + gen_flags += ShlexEnv('GYP_GENERATOR_FLAGS') + if options.generator_flags: + gen_flags += options.generator_flags + generator_flags = NameValueListToDict(gen_flags) + if DEBUG_GENERAL in gyp.debug.keys(): + DebugOutput(DEBUG_GENERAL, "generator_flags: %s", generator_flags) + + # Generate all requested formats (use a set in case we got one format request + # twice) + for format in set(options.formats): + params = {'options': options, + 'build_files': build_files, + 'generator_flags': generator_flags, + 'cwd': os.getcwd(), + 'build_files_arg': build_files_arg, + 'gyp_binary': sys.argv[0], + 'home_dot_gyp': home_dot_gyp, + 'parallel': options.parallel, + 'root_targets': options.root_targets} + + # Start with the default variables from the command line. + [generator, flat_list, targets, data] = Load(build_files, format, + cmdline_default_variables, + includes, options.depth, + params, options.check, + options.circular_check) + + # TODO(mark): Pass |data| for now because the generator needs a list of + # build files that came in. In the future, maybe it should just accept + # a list, and not the whole data dict. + # NOTE: flat_list is the flattened dependency graph specifying the order + # that targets may be built. Build systems that operate serially or that + # need to have dependencies defined before dependents reference them should + # generate targets in the order specified in flat_list. + generator.GenerateOutput(flat_list, targets, data, params) + + if options.configs: + valid_configs = targets[flat_list[0]]['configurations'].keys() + for conf in options.configs: + if conf not in valid_configs: + raise GypError('Invalid config specified via --build: %s' % conf) + generator.PerformBuild(data, options.configs, params) + + # Done + return 0 + + +def main(args): + try: + return gyp_main(args) + except GypError, e: + sys.stderr.write("gyp: %s\n" % e) + return 1 + +# NOTE: setuptools generated console_scripts calls function with no arguments +def script_main(): + return main(sys.argv[1:]) + +if __name__ == '__main__': + sys.exit(script_main()) diff --git a/deps/gyp/pylib/gyp/common.py b/deps/gyp/pylib/gyp/common.py new file mode 100644 index 000000000..df71d973e --- /dev/null +++ b/deps/gyp/pylib/gyp/common.py @@ -0,0 +1,588 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from __future__ import with_statement + +import collections +import errno +import filecmp +import os.path +import re +import tempfile +import sys + + +# A minimal memoizing decorator. It'll blow up if the args aren't immutable, +# among other "problems". +class memoize(object): + def __init__(self, func): + self.func = func + self.cache = {} + def __call__(self, *args): + try: + return self.cache[args] + except KeyError: + result = self.func(*args) + self.cache[args] = result + return result + + +class GypError(Exception): + """Error class representing an error, which is to be presented + to the user. The main entry point will catch and display this. + """ + pass + + +def ExceptionAppend(e, msg): + """Append a message to the given exception's message.""" + if not e.args: + e.args = (msg,) + elif len(e.args) == 1: + e.args = (str(e.args[0]) + ' ' + msg,) + else: + e.args = (str(e.args[0]) + ' ' + msg,) + e.args[1:] + + +def FindQualifiedTargets(target, qualified_list): + """ + Given a list of qualified targets, return the qualified targets for the + specified |target|. + """ + return [t for t in qualified_list if ParseQualifiedTarget(t)[1] == target] + + +def ParseQualifiedTarget(target): + # Splits a qualified target into a build file, target name and toolset. + + # NOTE: rsplit is used to disambiguate the Windows drive letter separator. + target_split = target.rsplit(':', 1) + if len(target_split) == 2: + [build_file, target] = target_split + else: + build_file = None + + target_split = target.rsplit('#', 1) + if len(target_split) == 2: + [target, toolset] = target_split + else: + toolset = None + + return [build_file, target, toolset] + + +def ResolveTarget(build_file, target, toolset): + # This function resolves a target into a canonical form: + # - a fully defined build file, either absolute or relative to the current + # directory + # - a target name + # - a toolset + # + # build_file is the file relative to which 'target' is defined. + # target is the qualified target. + # toolset is the default toolset for that target. + [parsed_build_file, target, parsed_toolset] = ParseQualifiedTarget(target) + + if parsed_build_file: + if build_file: + # If a relative path, parsed_build_file is relative to the directory + # containing build_file. If build_file is not in the current directory, + # parsed_build_file is not a usable path as-is. Resolve it by + # interpreting it as relative to build_file. If parsed_build_file is + # absolute, it is usable as a path regardless of the current directory, + # and os.path.join will return it as-is. + build_file = os.path.normpath(os.path.join(os.path.dirname(build_file), + parsed_build_file)) + # Further (to handle cases like ../cwd), make it relative to cwd) + if not os.path.isabs(build_file): + build_file = RelativePath(build_file, '.') + else: + build_file = parsed_build_file + + if parsed_toolset: + toolset = parsed_toolset + + return [build_file, target, toolset] + + +def BuildFile(fully_qualified_target): + # Extracts the build file from the fully qualified target. + return ParseQualifiedTarget(fully_qualified_target)[0] + + +def GetEnvironFallback(var_list, default): + """Look up a key in the environment, with fallback to secondary keys + and finally falling back to a default value.""" + for var in var_list: + if var in os.environ: + return os.environ[var] + return default + + +def QualifiedTarget(build_file, target, toolset): + # "Qualified" means the file that a target was defined in and the target + # name, separated by a colon, suffixed by a # and the toolset name: + # /path/to/file.gyp:target_name#toolset + fully_qualified = build_file + ':' + target + if toolset: + fully_qualified = fully_qualified + '#' + toolset + return fully_qualified + + +@memoize +def RelativePath(path, relative_to): + # Assuming both |path| and |relative_to| are relative to the current + # directory, returns a relative path that identifies path relative to + # relative_to. + + # Convert to normalized (and therefore absolute paths). + path = os.path.realpath(path) + relative_to = os.path.realpath(relative_to) + + # On Windows, we can't create a relative path to a different drive, so just + # use the absolute path. + if sys.platform == 'win32': + if (os.path.splitdrive(path)[0].lower() != + os.path.splitdrive(relative_to)[0].lower()): + return path + + # Split the paths into components. + path_split = path.split(os.path.sep) + relative_to_split = relative_to.split(os.path.sep) + + # Determine how much of the prefix the two paths share. + prefix_len = len(os.path.commonprefix([path_split, relative_to_split])) + + # Put enough ".." components to back up out of relative_to to the common + # prefix, and then append the part of path_split after the common prefix. + relative_split = [os.path.pardir] * (len(relative_to_split) - prefix_len) + \ + path_split[prefix_len:] + + if len(relative_split) == 0: + # The paths were the same. + return '' + + # Turn it back into a string and we're done. + return os.path.join(*relative_split) + + +@memoize +def InvertRelativePath(path, toplevel_dir=None): + """Given a path like foo/bar that is relative to toplevel_dir, return + the inverse relative path back to the toplevel_dir. + + E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path))) + should always produce the empty string, unless the path contains symlinks. + """ + if not path: + return path + toplevel_dir = '.' if toplevel_dir is None else toplevel_dir + return RelativePath(toplevel_dir, os.path.join(toplevel_dir, path)) + + +def FixIfRelativePath(path, relative_to): + # Like RelativePath but returns |path| unchanged if it is absolute. + if os.path.isabs(path): + return path + return RelativePath(path, relative_to) + + +def UnrelativePath(path, relative_to): + # Assuming that |relative_to| is relative to the current directory, and |path| + # is a path relative to the dirname of |relative_to|, returns a path that + # identifies |path| relative to the current directory. + rel_dir = os.path.dirname(relative_to) + return os.path.normpath(os.path.join(rel_dir, path)) + + +# re objects used by EncodePOSIXShellArgument. See IEEE 1003.1 XCU.2.2 at +# http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_02 +# and the documentation for various shells. + +# _quote is a pattern that should match any argument that needs to be quoted +# with double-quotes by EncodePOSIXShellArgument. It matches the following +# characters appearing anywhere in an argument: +# \t, \n, space parameter separators +# # comments +# $ expansions (quoted to always expand within one argument) +# % called out by IEEE 1003.1 XCU.2.2 +# & job control +# ' quoting +# (, ) subshell execution +# *, ?, [ pathname expansion +# ; command delimiter +# <, >, | redirection +# = assignment +# {, } brace expansion (bash) +# ~ tilde expansion +# It also matches the empty string, because "" (or '') is the only way to +# represent an empty string literal argument to a POSIX shell. +# +# This does not match the characters in _escape, because those need to be +# backslash-escaped regardless of whether they appear in a double-quoted +# string. +_quote = re.compile('[\t\n #$%&\'()*;<=>?[{|}~]|^$') + +# _escape is a pattern that should match any character that needs to be +# escaped with a backslash, whether or not the argument matched the _quote +# pattern. _escape is used with re.sub to backslash anything in _escape's +# first match group, hence the (parentheses) in the regular expression. +# +# _escape matches the following characters appearing anywhere in an argument: +# " to prevent POSIX shells from interpreting this character for quoting +# \ to prevent POSIX shells from interpreting this character for escaping +# ` to prevent POSIX shells from interpreting this character for command +# substitution +# Missing from this list is $, because the desired behavior of +# EncodePOSIXShellArgument is to permit parameter (variable) expansion. +# +# Also missing from this list is !, which bash will interpret as the history +# expansion character when history is enabled. bash does not enable history +# by default in non-interactive shells, so this is not thought to be a problem. +# ! was omitted from this list because bash interprets "\!" as a literal string +# including the backslash character (avoiding history expansion but retaining +# the backslash), which would not be correct for argument encoding. Handling +# this case properly would also be problematic because bash allows the history +# character to be changed with the histchars shell variable. Fortunately, +# as history is not enabled in non-interactive shells and +# EncodePOSIXShellArgument is only expected to encode for non-interactive +# shells, there is no room for error here by ignoring !. +_escape = re.compile(r'(["\\`])') + +def EncodePOSIXShellArgument(argument): + """Encodes |argument| suitably for consumption by POSIX shells. + + argument may be quoted and escaped as necessary to ensure that POSIX shells + treat the returned value as a literal representing the argument passed to + this function. Parameter (variable) expansions beginning with $ are allowed + to remain intact without escaping the $, to allow the argument to contain + references to variables to be expanded by the shell. + """ + + if not isinstance(argument, str): + argument = str(argument) + + if _quote.search(argument): + quote = '"' + else: + quote = '' + + encoded = quote + re.sub(_escape, r'\\\1', argument) + quote + + return encoded + + +def EncodePOSIXShellList(list): + """Encodes |list| suitably for consumption by POSIX shells. + + Returns EncodePOSIXShellArgument for each item in list, and joins them + together using the space character as an argument separator. + """ + + encoded_arguments = [] + for argument in list: + encoded_arguments.append(EncodePOSIXShellArgument(argument)) + return ' '.join(encoded_arguments) + + +def DeepDependencyTargets(target_dicts, roots): + """Returns the recursive list of target dependencies.""" + dependencies = set() + pending = set(roots) + while pending: + # Pluck out one. + r = pending.pop() + # Skip if visited already. + if r in dependencies: + continue + # Add it. + dependencies.add(r) + # Add its children. + spec = target_dicts[r] + pending.update(set(spec.get('dependencies', []))) + pending.update(set(spec.get('dependencies_original', []))) + return list(dependencies - set(roots)) + + +def BuildFileTargets(target_list, build_file): + """From a target_list, returns the subset from the specified build_file. + """ + return [p for p in target_list if BuildFile(p) == build_file] + + +def AllTargets(target_list, target_dicts, build_file): + """Returns all targets (direct and dependencies) for the specified build_file. + """ + bftargets = BuildFileTargets(target_list, build_file) + deptargets = DeepDependencyTargets(target_dicts, bftargets) + return bftargets + deptargets + + +def WriteOnDiff(filename): + """Write to a file only if the new contents differ. + + Arguments: + filename: name of the file to potentially write to. + Returns: + A file like object which will write to temporary file and only overwrite + the target if it differs (on close). + """ + + class Writer: + """Wrapper around file which only covers the target if it differs.""" + def __init__(self): + # Pick temporary file. + tmp_fd, self.tmp_path = tempfile.mkstemp( + suffix='.tmp', + prefix=os.path.split(filename)[1] + '.gyp.', + dir=os.path.split(filename)[0]) + try: + self.tmp_file = os.fdopen(tmp_fd, 'wb') + except Exception: + # Don't leave turds behind. + os.unlink(self.tmp_path) + raise + + def __getattr__(self, attrname): + # Delegate everything else to self.tmp_file + return getattr(self.tmp_file, attrname) + + def close(self): + try: + # Close tmp file. + self.tmp_file.close() + # Determine if different. + same = False + try: + same = filecmp.cmp(self.tmp_path, filename, False) + except OSError, e: + if e.errno != errno.ENOENT: + raise + + if same: + # The new file is identical to the old one, just get rid of the new + # one. + os.unlink(self.tmp_path) + else: + # The new file is different from the old one, or there is no old one. + # Rename the new file to the permanent name. + # + # tempfile.mkstemp uses an overly restrictive mode, resulting in a + # file that can only be read by the owner, regardless of the umask. + # There's no reason to not respect the umask here, which means that + # an extra hoop is required to fetch it and reset the new file's mode. + # + # No way to get the umask without setting a new one? Set a safe one + # and then set it back to the old value. + umask = os.umask(077) + os.umask(umask) + os.chmod(self.tmp_path, 0666 & ~umask) + if sys.platform == 'win32' and os.path.exists(filename): + # NOTE: on windows (but not cygwin) rename will not replace an + # existing file, so it must be preceded with a remove. Sadly there + # is no way to make the switch atomic. + os.remove(filename) + os.rename(self.tmp_path, filename) + except Exception: + # Don't leave turds behind. + os.unlink(self.tmp_path) + raise + + return Writer() + + +def EnsureDirExists(path): + """Make sure the directory for |path| exists.""" + try: + os.makedirs(os.path.dirname(path)) + except OSError: + pass + + +def GetFlavor(params): + """Returns |params.flavor| if it's set, the system's default flavor else.""" + flavors = { + 'cygwin': 'win', + 'win32': 'win', + 'darwin': 'mac', + } + + if 'flavor' in params: + return params['flavor'] + if sys.platform in flavors: + return flavors[sys.platform] + if sys.platform.startswith('sunos'): + return 'solaris' + if sys.platform.startswith('freebsd'): + return 'freebsd' + if sys.platform.startswith('openbsd'): + return 'openbsd' + if sys.platform.startswith('aix'): + return 'aix' + + return 'linux' + + +def CopyTool(flavor, out_path): + """Finds (flock|mac|win)_tool.gyp in the gyp directory and copies it + to |out_path|.""" + # aix and solaris just need flock emulation. mac and win use more complicated + # support scripts. + prefix = { + 'aix': 'flock', + 'solaris': 'flock', + 'mac': 'mac', + 'win': 'win' + }.get(flavor, None) + if not prefix: + return + + # Slurp input file. + source_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), '%s_tool.py' % prefix) + with open(source_path) as source_file: + source = source_file.readlines() + + # Add header and write it out. + tool_path = os.path.join(out_path, 'gyp-%s-tool' % prefix) + with open(tool_path, 'w') as tool_file: + tool_file.write( + ''.join([source[0], '# Generated by gyp. Do not edit.\n'] + source[1:])) + + # Make file executable. + os.chmod(tool_path, 0755) + + +# From Alex Martelli, +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 +# ASPN: Python Cookbook: Remove duplicates from a sequence +# First comment, dated 2001/10/13. +# (Also in the printed Python Cookbook.) + +def uniquer(seq, idfun=None): + if idfun is None: + idfun = lambda x: x + seen = {} + result = [] + for item in seq: + marker = idfun(item) + if marker in seen: continue + seen[marker] = 1 + result.append(item) + return result + + +# Based on http://code.activestate.com/recipes/576694/. +class OrderedSet(collections.MutableSet): + def __init__(self, iterable=None): + self.end = end = [] + end += [None, end, end] # sentinel node for doubly linked list + self.map = {} # key --> [key, prev, next] + if iterable is not None: + self |= iterable + + def __len__(self): + return len(self.map) + + def __contains__(self, key): + return key in self.map + + def add(self, key): + if key not in self.map: + end = self.end + curr = end[1] + curr[2] = end[1] = self.map[key] = [key, curr, end] + + def discard(self, key): + if key in self.map: + key, prev_item, next_item = self.map.pop(key) + prev_item[2] = next_item + next_item[1] = prev_item + + def __iter__(self): + end = self.end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + # The second argument is an addition that causes a pylint warning. + def pop(self, last=True): # pylint: disable=W0221 + if not self: + raise KeyError('set is empty') + key = self.end[1][0] if last else self.end[2][0] + self.discard(key) + return key + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, list(self)) + + def __eq__(self, other): + if isinstance(other, OrderedSet): + return len(self) == len(other) and list(self) == list(other) + return set(self) == set(other) + + # Extensions to the recipe. + def update(self, iterable): + for i in iterable: + if i not in self: + self.add(i) + + +class CycleError(Exception): + """An exception raised when an unexpected cycle is detected.""" + def __init__(self, nodes): + self.nodes = nodes + def __str__(self): + return 'CycleError: cycle involving: ' + str(self.nodes) + + +def TopologicallySorted(graph, get_edges): + """Topologically sort based on a user provided edge definition. + + Args: + graph: A list of node names. + get_edges: A function mapping from node name to a hashable collection + of node names which this node has outgoing edges to. + Returns: + A list containing all of the node in graph in topological order. + It is assumed that calling get_edges once for each node and caching is + cheaper than repeatedly calling get_edges. + Raises: + CycleError in the event of a cycle. + Example: + graph = {'a': '$(b) $(c)', 'b': 'hi', 'c': '$(b)'} + def GetEdges(node): + return re.findall(r'\$\(([^))]\)', graph[node]) + print TopologicallySorted(graph.keys(), GetEdges) + ==> + ['a', 'c', b'] + """ + get_edges = memoize(get_edges) + visited = set() + visiting = set() + ordered_nodes = [] + def Visit(node): + if node in visiting: + raise CycleError(visiting) + if node in visited: + return + visited.add(node) + visiting.add(node) + for neighbor in get_edges(node): + Visit(neighbor) + visiting.remove(node) + ordered_nodes.insert(0, node) + for node in sorted(graph): + Visit(node) + return ordered_nodes diff --git a/deps/gyp/pylib/gyp/common_test.py b/deps/gyp/pylib/gyp/common_test.py new file mode 100755 index 000000000..ad6f9a143 --- /dev/null +++ b/deps/gyp/pylib/gyp/common_test.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Unit tests for the common.py file.""" + +import gyp.common +import unittest +import sys + + +class TestTopologicallySorted(unittest.TestCase): + def test_Valid(self): + """Test that sorting works on a valid graph with one possible order.""" + graph = { + 'a': ['b', 'c'], + 'b': [], + 'c': ['d'], + 'd': ['b'], + } + def GetEdge(node): + return tuple(graph[node]) + self.assertEqual( + gyp.common.TopologicallySorted(graph.keys(), GetEdge), + ['a', 'c', 'd', 'b']) + + def test_Cycle(self): + """Test that an exception is thrown on a cyclic graph.""" + graph = { + 'a': ['b'], + 'b': ['c'], + 'c': ['d'], + 'd': ['a'], + } + def GetEdge(node): + return tuple(graph[node]) + self.assertRaises( + gyp.common.CycleError, gyp.common.TopologicallySorted, + graph.keys(), GetEdge) + + +class TestGetFlavor(unittest.TestCase): + """Test that gyp.common.GetFlavor works as intended""" + original_platform = '' + + def setUp(self): + self.original_platform = sys.platform + + def tearDown(self): + sys.platform = self.original_platform + + def assertFlavor(self, expected, argument, param): + sys.platform = argument + self.assertEqual(expected, gyp.common.GetFlavor(param)) + + def test_platform_default(self): + self.assertFlavor('freebsd', 'freebsd9' , {}) + self.assertFlavor('freebsd', 'freebsd10', {}) + self.assertFlavor('openbsd', 'openbsd5' , {}) + self.assertFlavor('solaris', 'sunos5' , {}); + self.assertFlavor('solaris', 'sunos' , {}); + self.assertFlavor('linux' , 'linux2' , {}); + self.assertFlavor('linux' , 'linux3' , {}); + + def test_param(self): + self.assertFlavor('foobar', 'linux2' , {'flavor': 'foobar'}) + + +if __name__ == '__main__': + unittest.main() diff --git a/deps/gyp/pylib/gyp/easy_xml.py b/deps/gyp/pylib/gyp/easy_xml.py new file mode 100644 index 000000000..bf949b6ac --- /dev/null +++ b/deps/gyp/pylib/gyp/easy_xml.py @@ -0,0 +1,157 @@ +# Copyright (c) 2011 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import re +import os + + +def XmlToString(content, encoding='utf-8', pretty=False): + """ Writes the XML content to disk, touching the file only if it has changed. + + Visual Studio files have a lot of pre-defined structures. This function makes + it easy to represent these structures as Python data structures, instead of + having to create a lot of function calls. + + Each XML element of the content is represented as a list composed of: + 1. The name of the element, a string, + 2. The attributes of the element, a dictionary (optional), and + 3+. The content of the element, if any. Strings are simple text nodes and + lists are child elements. + + Example 1: + + becomes + ['test'] + + Example 2: + + This is + it! + + + becomes + ['myelement', {'a':'value1', 'b':'value2'}, + ['childtype', 'This is'], + ['childtype', 'it!'], + ] + + Args: + content: The structured content to be converted. + encoding: The encoding to report on the first XML line. + pretty: True if we want pretty printing with indents and new lines. + + Returns: + The XML content as a string. + """ + # We create a huge list of all the elements of the file. + xml_parts = ['' % encoding] + if pretty: + xml_parts.append('\n') + _ConstructContentList(xml_parts, content, pretty) + + # Convert it to a string + return ''.join(xml_parts) + + +def _ConstructContentList(xml_parts, specification, pretty, level=0): + """ Appends the XML parts corresponding to the specification. + + Args: + xml_parts: A list of XML parts to be appended to. + specification: The specification of the element. See EasyXml docs. + pretty: True if we want pretty printing with indents and new lines. + level: Indentation level. + """ + # The first item in a specification is the name of the element. + if pretty: + indentation = ' ' * level + new_line = '\n' + else: + indentation = '' + new_line = '' + name = specification[0] + if not isinstance(name, str): + raise Exception('The first item of an EasyXml specification should be ' + 'a string. Specification was ' + str(specification)) + xml_parts.append(indentation + '<' + name) + + # Optionally in second position is a dictionary of the attributes. + rest = specification[1:] + if rest and isinstance(rest[0], dict): + for at, val in sorted(rest[0].iteritems()): + xml_parts.append(' %s="%s"' % (at, _XmlEscape(val, attr=True))) + rest = rest[1:] + if rest: + xml_parts.append('>') + all_strings = reduce(lambda x, y: x and isinstance(y, str), rest, True) + multi_line = not all_strings + if multi_line and new_line: + xml_parts.append(new_line) + for child_spec in rest: + # If it's a string, append a text node. + # Otherwise recurse over that child definition + if isinstance(child_spec, str): + xml_parts.append(_XmlEscape(child_spec)) + else: + _ConstructContentList(xml_parts, child_spec, pretty, level + 1) + if multi_line and indentation: + xml_parts.append(indentation) + xml_parts.append('%s' % (name, new_line)) + else: + xml_parts.append('/>%s' % new_line) + + +def WriteXmlIfChanged(content, path, encoding='utf-8', pretty=False, + win32=False): + """ Writes the XML content to disk, touching the file only if it has changed. + + Args: + content: The structured content to be written. + path: Location of the file. + encoding: The encoding to report on the first line of the XML file. + pretty: True if we want pretty printing with indents and new lines. + """ + xml_string = XmlToString(content, encoding, pretty) + if win32 and os.linesep != '\r\n': + xml_string = xml_string.replace('\n', '\r\n') + + # Get the old content + try: + f = open(path, 'r') + existing = f.read() + f.close() + except: + existing = None + + # It has changed, write it + if existing != xml_string: + f = open(path, 'w') + f.write(xml_string) + f.close() + + +_xml_escape_map = { + '"': '"', + "'": ''', + '<': '<', + '>': '>', + '&': '&', + '\n': ' ', + '\r': ' ', +} + + +_xml_escape_re = re.compile( + "(%s)" % "|".join(map(re.escape, _xml_escape_map.keys()))) + + +def _XmlEscape(value, attr=False): + """ Escape a string for inclusion in XML.""" + def replace(match): + m = match.string[match.start() : match.end()] + # don't replace single quotes in attrs + if attr and m == "'": + return m + return _xml_escape_map[m] + return _xml_escape_re.sub(replace, value) diff --git a/deps/gyp/pylib/gyp/easy_xml_test.py b/deps/gyp/pylib/gyp/easy_xml_test.py new file mode 100755 index 000000000..df6435498 --- /dev/null +++ b/deps/gyp/pylib/gyp/easy_xml_test.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +# Copyright (c) 2011 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" Unit tests for the easy_xml.py file. """ + +import gyp.easy_xml as easy_xml +import unittest +import StringIO + + +class TestSequenceFunctions(unittest.TestCase): + + def setUp(self): + self.stderr = StringIO.StringIO() + + def test_EasyXml_simple(self): + self.assertEqual( + easy_xml.XmlToString(['test']), + '') + + self.assertEqual( + easy_xml.XmlToString(['test'], encoding='Windows-1252'), + '') + + def test_EasyXml_simple_with_attributes(self): + self.assertEqual( + easy_xml.XmlToString(['test2', {'a': 'value1', 'b': 'value2'}]), + '') + + def test_EasyXml_escaping(self): + original = '\'"\r&\nfoo' + converted = '<test>\'" & foo' + converted_apos = converted.replace("'", ''') + self.assertEqual( + easy_xml.XmlToString(['test3', {'a': original}, original]), + '%s' % + (converted, converted_apos)) + + def test_EasyXml_pretty(self): + self.assertEqual( + easy_xml.XmlToString( + ['test3', + ['GrandParent', + ['Parent1', + ['Child'] + ], + ['Parent2'] + ] + ], + pretty=True), + '\n' + '\n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + '\n') + + + def test_EasyXml_complex(self): + # We want to create: + target = ( + '' + '' + '' + '{D2250C20-3A94-4FB9-AF73-11BC5B73884B}' + 'Win32Proj' + 'automated_ui_tests' + '' + '' + '' + 'Application' + 'Unicode' + '' + '') + + xml = easy_xml.XmlToString( + ['Project', + ['PropertyGroup', {'Label': 'Globals'}, + ['ProjectGuid', '{D2250C20-3A94-4FB9-AF73-11BC5B73884B}'], + ['Keyword', 'Win32Proj'], + ['RootNamespace', 'automated_ui_tests'] + ], + ['Import', {'Project': '$(VCTargetsPath)\\Microsoft.Cpp.props'}], + ['PropertyGroup', + {'Condition': "'$(Configuration)|$(Platform)'=='Debug|Win32'", + 'Label': 'Configuration'}, + ['ConfigurationType', 'Application'], + ['CharacterSet', 'Unicode'] + ] + ]) + self.assertEqual(xml, target) + + +if __name__ == '__main__': + unittest.main() diff --git a/deps/gyp/pylib/gyp/flock_tool.py b/deps/gyp/pylib/gyp/flock_tool.py new file mode 100755 index 000000000..3e7efff26 --- /dev/null +++ b/deps/gyp/pylib/gyp/flock_tool.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# Copyright (c) 2011 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""These functions are executed via gyp-flock-tool when using the Makefile +generator. Used on systems that don't have a built-in flock.""" + +import fcntl +import os +import struct +import subprocess +import sys + + +def main(args): + executor = FlockTool() + executor.Dispatch(args) + + +class FlockTool(object): + """This class emulates the 'flock' command.""" + def Dispatch(self, args): + """Dispatches a string command to a method.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + method = "Exec%s" % self._CommandifyName(args[0]) + getattr(self, method)(*args[1:]) + + def _CommandifyName(self, name_string): + """Transforms a tool name like copy-info-plist to CopyInfoPlist""" + return name_string.title().replace('-', '') + + def ExecFlock(self, lockfile, *cmd_list): + """Emulates the most basic behavior of Linux's flock(1).""" + # Rely on exception handling to report errors. + # Note that the stock python on SunOS has a bug + # where fcntl.flock(fd, LOCK_EX) always fails + # with EBADF, that's why we use this F_SETLK + # hack instead. + fd = os.open(lockfile, os.O_WRONLY|os.O_NOCTTY|os.O_CREAT, 0666) + op = struct.pack('hhllhhl', fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0) + fcntl.fcntl(fd, fcntl.F_SETLK, op) + return subprocess.call(cmd_list) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/deps/gyp/pylib/gyp/generator/__init__.py b/deps/gyp/pylib/gyp/generator/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/deps/gyp/pylib/gyp/generator/android.py b/deps/gyp/pylib/gyp/generator/android.py new file mode 100644 index 000000000..39884749b --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/android.py @@ -0,0 +1,1090 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Notes: +# +# This generates makefiles suitable for inclusion into the Android build system +# via an Android.mk file. It is based on make.py, the standard makefile +# generator. +# +# The code below generates a separate .mk file for each target, but +# all are sourced by the top-level GypAndroid.mk. This means that all +# variables in .mk-files clobber one another, and furthermore that any +# variables set potentially clash with other Android build system variables. +# Try to avoid setting global variables where possible. + +import gyp +import gyp.common +import gyp.generator.make as make # Reuse global functions from make backend. +import os +import re +import subprocess + +generator_default_variables = { + 'OS': 'android', + 'EXECUTABLE_PREFIX': '', + 'EXECUTABLE_SUFFIX': '', + 'STATIC_LIB_PREFIX': 'lib', + 'SHARED_LIB_PREFIX': 'lib', + 'STATIC_LIB_SUFFIX': '.a', + 'SHARED_LIB_SUFFIX': '.so', + 'INTERMEDIATE_DIR': '$(gyp_intermediate_dir)', + 'SHARED_INTERMEDIATE_DIR': '$(gyp_shared_intermediate_dir)', + 'PRODUCT_DIR': '$(gyp_shared_intermediate_dir)', + 'SHARED_LIB_DIR': '$(builddir)/lib.$(TOOLSET)', + 'LIB_DIR': '$(obj).$(TOOLSET)', + 'RULE_INPUT_ROOT': '%(INPUT_ROOT)s', # This gets expanded by Python. + 'RULE_INPUT_DIRNAME': '%(INPUT_DIRNAME)s', # This gets expanded by Python. + 'RULE_INPUT_PATH': '$(RULE_SOURCES)', + 'RULE_INPUT_EXT': '$(suffix $<)', + 'RULE_INPUT_NAME': '$(notdir $<)', + 'CONFIGURATION_NAME': '$(GYP_CONFIGURATION)', +} + +# Make supports multiple toolsets +generator_supports_multiple_toolsets = True + + +# Generator-specific gyp specs. +generator_additional_non_configuration_keys = [ + # Boolean to declare that this target does not want its name mangled. + 'android_unmangled_name', +] +generator_additional_path_sections = [] +generator_extra_sources_for_rules = [] + + +ALL_MODULES_FOOTER = """\ +# "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from +# all the included sub-makefiles. This is just here to clarify. +gyp_all_modules: +""" + +header = """\ +# This file is generated by gyp; do not edit. + +""" + +android_standard_include_paths = set([ + # JNI_H_INCLUDE in build/core/binary.mk + 'dalvik/libnativehelper/include/nativehelper', + # from SRC_HEADERS in build/core/config.mk + 'system/core/include', + 'hardware/libhardware/include', + 'hardware/libhardware_legacy/include', + 'hardware/ril/include', + 'dalvik/libnativehelper/include', + 'frameworks/native/include', + 'frameworks/native/opengl/include', + 'frameworks/base/include', + 'frameworks/base/opengl/include', + 'frameworks/base/native/include', + 'external/skia/include', + # TARGET_C_INCLUDES in build/core/combo/TARGET_linux-arm.mk + 'bionic/libc/arch-arm/include', + 'bionic/libc/include', + 'bionic/libstdc++/include', + 'bionic/libc/kernel/common', + 'bionic/libc/kernel/arch-arm', + 'bionic/libm/include', + 'bionic/libm/include/arm', + 'bionic/libthread_db/include', + ]) + + +# Map gyp target types to Android module classes. +MODULE_CLASSES = { + 'static_library': 'STATIC_LIBRARIES', + 'shared_library': 'SHARED_LIBRARIES', + 'executable': 'EXECUTABLES', +} + + +def IsCPPExtension(ext): + return make.COMPILABLE_EXTENSIONS.get(ext) == 'cxx' + + +def Sourceify(path): + """Convert a path to its source directory form. The Android backend does not + support options.generator_output, so this function is a noop.""" + return path + + +# Map from qualified target to path to output. +# For Android, the target of these maps is a tuple ('static', 'modulename'), +# ('dynamic', 'modulename'), or ('path', 'some/path') instead of a string, +# since we link by module. +target_outputs = {} +# Map from qualified target to any linkable output. A subset +# of target_outputs. E.g. when mybinary depends on liba, we want to +# include liba in the linker line; when otherbinary depends on +# mybinary, we just want to build mybinary first. +target_link_deps = {} + + +class AndroidMkWriter(object): + """AndroidMkWriter packages up the writing of one target-specific Android.mk. + + Its only real entry point is Write(), and is mostly used for namespacing. + """ + + def __init__(self, android_top_dir): + self.android_top_dir = android_top_dir + + def Write(self, qualified_target, relative_target, base_path, output_filename, + spec, configs, part_of_all, write_alias_target): + """The main entry point: writes a .mk file for a single target. + + Arguments: + qualified_target: target we're generating + relative_target: qualified target name relative to the root + base_path: path relative to source root we're building in, used to resolve + target-relative paths + output_filename: output .mk file name to write + spec, configs: gyp info + part_of_all: flag indicating this target is part of 'all' + write_alias_target: flag indicating whether to create short aliases for + this target + """ + gyp.common.EnsureDirExists(output_filename) + + self.fp = open(output_filename, 'w') + + self.fp.write(header) + + self.qualified_target = qualified_target + self.relative_target = relative_target + self.path = base_path + self.target = spec['target_name'] + self.type = spec['type'] + self.toolset = spec['toolset'] + + deps, link_deps = self.ComputeDeps(spec) + + # Some of the generation below can add extra output, sources, or + # link dependencies. All of the out params of the functions that + # follow use names like extra_foo. + extra_outputs = [] + extra_sources = [] + + self.android_class = MODULE_CLASSES.get(self.type, 'GYP') + self.android_module = self.ComputeAndroidModule(spec) + (self.android_stem, self.android_suffix) = self.ComputeOutputParts(spec) + self.output = self.output_binary = self.ComputeOutput(spec) + + # Standard header. + self.WriteLn('include $(CLEAR_VARS)\n') + + # Module class and name. + self.WriteLn('LOCAL_MODULE_CLASS := ' + self.android_class) + self.WriteLn('LOCAL_MODULE := ' + self.android_module) + # Only emit LOCAL_MODULE_STEM if it's different to LOCAL_MODULE. + # The library module classes fail if the stem is set. ComputeOutputParts + # makes sure that stem == modulename in these cases. + if self.android_stem != self.android_module: + self.WriteLn('LOCAL_MODULE_STEM := ' + self.android_stem) + self.WriteLn('LOCAL_MODULE_SUFFIX := ' + self.android_suffix) + self.WriteLn('LOCAL_MODULE_TAGS := optional') + if self.toolset == 'host': + self.WriteLn('LOCAL_IS_HOST_MODULE := true') + else: + self.WriteLn('LOCAL_MODULE_TARGET_ARCH := ' + '$(TARGET_$(GYP_VAR_PREFIX)ARCH)') + + # Grab output directories; needed for Actions and Rules. + if self.toolset == 'host': + self.WriteLn('gyp_intermediate_dir := ' + '$(call local-intermediates-dir)') + else: + self.WriteLn('gyp_intermediate_dir := ' + '$(call local-intermediates-dir,,$(GYP_VAR_PREFIX))') + self.WriteLn('gyp_shared_intermediate_dir := ' + '$(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))') + self.WriteLn() + + # List files this target depends on so that actions/rules/copies/sources + # can depend on the list. + # TODO: doesn't pull in things through transitive link deps; needed? + target_dependencies = [x[1] for x in deps if x[0] == 'path'] + self.WriteLn('# Make sure our deps are built first.') + self.WriteList(target_dependencies, 'GYP_TARGET_DEPENDENCIES', + local_pathify=True) + + # Actions must come first, since they can generate more OBJs for use below. + if 'actions' in spec: + self.WriteActions(spec['actions'], extra_sources, extra_outputs) + + # Rules must be early like actions. + if 'rules' in spec: + self.WriteRules(spec['rules'], extra_sources, extra_outputs) + + if 'copies' in spec: + self.WriteCopies(spec['copies'], extra_outputs) + + # GYP generated outputs. + self.WriteList(extra_outputs, 'GYP_GENERATED_OUTPUTS', local_pathify=True) + + # Set LOCAL_ADDITIONAL_DEPENDENCIES so that Android's build rules depend + # on both our dependency targets and our generated files. + self.WriteLn('# Make sure our deps and generated files are built first.') + self.WriteLn('LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) ' + '$(GYP_GENERATED_OUTPUTS)') + self.WriteLn() + + # Sources. + if spec.get('sources', []) or extra_sources: + self.WriteSources(spec, configs, extra_sources) + + self.WriteTarget(spec, configs, deps, link_deps, part_of_all, + write_alias_target) + + # Update global list of target outputs, used in dependency tracking. + target_outputs[qualified_target] = ('path', self.output_binary) + + # Update global list of link dependencies. + if self.type == 'static_library': + target_link_deps[qualified_target] = ('static', self.android_module) + elif self.type == 'shared_library': + target_link_deps[qualified_target] = ('shared', self.android_module) + + self.fp.close() + return self.android_module + + + def WriteActions(self, actions, extra_sources, extra_outputs): + """Write Makefile code for any 'actions' from the gyp input. + + extra_sources: a list that will be filled in with newly generated source + files, if any + extra_outputs: a list that will be filled in with any outputs of these + actions (used to make other pieces dependent on these + actions) + """ + for action in actions: + name = make.StringToMakefileVariable('%s_%s' % (self.relative_target, + action['action_name'])) + self.WriteLn('### Rules for action "%s":' % action['action_name']) + inputs = action['inputs'] + outputs = action['outputs'] + + # Build up a list of outputs. + # Collect the output dirs we'll need. + dirs = set() + for out in outputs: + if not out.startswith('$'): + print ('WARNING: Action for target "%s" writes output to local path ' + '"%s".' % (self.target, out)) + dir = os.path.split(out)[0] + if dir: + dirs.add(dir) + if int(action.get('process_outputs_as_sources', False)): + extra_sources += outputs + + # Prepare the actual command. + command = gyp.common.EncodePOSIXShellList(action['action']) + if 'message' in action: + quiet_cmd = 'Gyp action: %s ($@)' % action['message'] + else: + quiet_cmd = 'Gyp action: %s ($@)' % name + if len(dirs) > 0: + command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command + + cd_action = 'cd $(gyp_local_path)/%s; ' % self.path + command = cd_action + command + + # The makefile rules are all relative to the top dir, but the gyp actions + # are defined relative to their containing dir. This replaces the gyp_* + # variables for the action rule with an absolute version so that the + # output goes in the right place. + # Only write the gyp_* rules for the "primary" output (:1); + # it's superfluous for the "extra outputs", and this avoids accidentally + # writing duplicate dummy rules for those outputs. + main_output = make.QuoteSpaces(self.LocalPathify(outputs[0])) + self.WriteLn('%s: gyp_local_path := $(LOCAL_PATH)' % main_output) + self.WriteLn('%s: gyp_var_prefix := $(GYP_VAR_PREFIX)' % main_output) + self.WriteLn('%s: gyp_intermediate_dir := ' + '$(abspath $(gyp_intermediate_dir))' % main_output) + self.WriteLn('%s: gyp_shared_intermediate_dir := ' + '$(abspath $(gyp_shared_intermediate_dir))' % main_output) + + # Android's envsetup.sh adds a number of directories to the path including + # the built host binary directory. This causes actions/rules invoked by + # gyp to sometimes use these instead of system versions, e.g. bison. + # The built host binaries may not be suitable, and can cause errors. + # So, we remove them from the PATH using the ANDROID_BUILD_PATHS variable + # set by envsetup. + self.WriteLn('%s: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))' + % main_output) + + for input in inputs: + assert ' ' not in input, ( + "Spaces in action input filenames not supported (%s)" % input) + for output in outputs: + assert ' ' not in output, ( + "Spaces in action output filenames not supported (%s)" % output) + + self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES)' % + (main_output, ' '.join(map(self.LocalPathify, inputs)))) + self.WriteLn('\t@echo "%s"' % quiet_cmd) + self.WriteLn('\t$(hide)%s\n' % command) + for output in outputs[1:]: + # Make each output depend on the main output, with an empty command + # to force make to notice that the mtime has changed. + self.WriteLn('%s: %s ;' % (self.LocalPathify(output), main_output)) + + extra_outputs += outputs + self.WriteLn() + + self.WriteLn() + + + def WriteRules(self, rules, extra_sources, extra_outputs): + """Write Makefile code for any 'rules' from the gyp input. + + extra_sources: a list that will be filled in with newly generated source + files, if any + extra_outputs: a list that will be filled in with any outputs of these + rules (used to make other pieces dependent on these rules) + """ + if len(rules) == 0: + return + + for rule in rules: + if len(rule.get('rule_sources', [])) == 0: + continue + name = make.StringToMakefileVariable('%s_%s' % (self.relative_target, + rule['rule_name'])) + self.WriteLn('\n### Generated for rule "%s":' % name) + self.WriteLn('# "%s":' % rule) + + inputs = rule.get('inputs') + for rule_source in rule.get('rule_sources', []): + (rule_source_dirname, rule_source_basename) = os.path.split(rule_source) + (rule_source_root, rule_source_ext) = \ + os.path.splitext(rule_source_basename) + + outputs = [self.ExpandInputRoot(out, rule_source_root, + rule_source_dirname) + for out in rule['outputs']] + + dirs = set() + for out in outputs: + if not out.startswith('$'): + print ('WARNING: Rule for target %s writes output to local path %s' + % (self.target, out)) + dir = os.path.dirname(out) + if dir: + dirs.add(dir) + extra_outputs += outputs + if int(rule.get('process_outputs_as_sources', False)): + extra_sources.extend(outputs) + + components = [] + for component in rule['action']: + component = self.ExpandInputRoot(component, rule_source_root, + rule_source_dirname) + if '$(RULE_SOURCES)' in component: + component = component.replace('$(RULE_SOURCES)', + rule_source) + components.append(component) + + command = gyp.common.EncodePOSIXShellList(components) + cd_action = 'cd $(gyp_local_path)/%s; ' % self.path + command = cd_action + command + if dirs: + command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command + + # We set up a rule to build the first output, and then set up + # a rule for each additional output to depend on the first. + outputs = map(self.LocalPathify, outputs) + main_output = outputs[0] + self.WriteLn('%s: gyp_local_path := $(LOCAL_PATH)' % main_output) + self.WriteLn('%s: gyp_var_prefix := $(GYP_VAR_PREFIX)' % main_output) + self.WriteLn('%s: gyp_intermediate_dir := ' + '$(abspath $(gyp_intermediate_dir))' % main_output) + self.WriteLn('%s: gyp_shared_intermediate_dir := ' + '$(abspath $(gyp_shared_intermediate_dir))' % main_output) + + # See explanation in WriteActions. + self.WriteLn('%s: export PATH := ' + '$(subst $(ANDROID_BUILD_PATHS),,$(PATH))' % main_output) + + main_output_deps = self.LocalPathify(rule_source) + if inputs: + main_output_deps += ' ' + main_output_deps += ' '.join([self.LocalPathify(f) for f in inputs]) + + self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES)' % + (main_output, main_output_deps)) + self.WriteLn('\t%s\n' % command) + for output in outputs[1:]: + # Make each output depend on the main output, with an empty command + # to force make to notice that the mtime has changed. + self.WriteLn('%s: %s ;' % (output, main_output)) + self.WriteLn() + + self.WriteLn() + + + def WriteCopies(self, copies, extra_outputs): + """Write Makefile code for any 'copies' from the gyp input. + + extra_outputs: a list that will be filled in with any outputs of this action + (used to make other pieces dependent on this action) + """ + self.WriteLn('### Generated for copy rule.') + + variable = make.StringToMakefileVariable(self.relative_target + '_copies') + outputs = [] + for copy in copies: + for path in copy['files']: + # The Android build system does not allow generation of files into the + # source tree. The destination should start with a variable, which will + # typically be $(gyp_intermediate_dir) or + # $(gyp_shared_intermediate_dir). Note that we can't use an assertion + # because some of the gyp tests depend on this. + if not copy['destination'].startswith('$'): + print ('WARNING: Copy rule for target %s writes output to ' + 'local path %s' % (self.target, copy['destination'])) + + # LocalPathify() calls normpath, stripping trailing slashes. + path = Sourceify(self.LocalPathify(path)) + filename = os.path.split(path)[1] + output = Sourceify(self.LocalPathify(os.path.join(copy['destination'], + filename))) + + self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES) | $(ACP)' % + (output, path)) + self.WriteLn('\t@echo Copying: $@') + self.WriteLn('\t$(hide) mkdir -p $(dir $@)') + self.WriteLn('\t$(hide) $(ACP) -rpf $< $@') + self.WriteLn() + outputs.append(output) + self.WriteLn('%s = %s' % (variable, + ' '.join(map(make.QuoteSpaces, outputs)))) + extra_outputs.append('$(%s)' % variable) + self.WriteLn() + + + def WriteSourceFlags(self, spec, configs): + """Write out the flags and include paths used to compile source files for + the current target. + + Args: + spec, configs: input from gyp. + """ + for configname, config in sorted(configs.iteritems()): + extracted_includes = [] + + self.WriteLn('\n# Flags passed to both C and C++ files.') + cflags, includes_from_cflags = self.ExtractIncludesFromCFlags( + config.get('cflags', []) + config.get('cflags_c', [])) + extracted_includes.extend(includes_from_cflags) + self.WriteList(cflags, 'MY_CFLAGS_%s' % configname) + + self.WriteList(config.get('defines'), 'MY_DEFS_%s' % configname, + prefix='-D', quoter=make.EscapeCppDefine) + + self.WriteLn('\n# Include paths placed before CFLAGS/CPPFLAGS') + includes = list(config.get('include_dirs', [])) + includes.extend(extracted_includes) + includes = map(Sourceify, map(self.LocalPathify, includes)) + includes = self.NormalizeIncludePaths(includes) + self.WriteList(includes, 'LOCAL_C_INCLUDES_%s' % configname) + + self.WriteLn('\n# Flags passed to only C++ (and not C) files.') + self.WriteList(config.get('cflags_cc'), 'LOCAL_CPPFLAGS_%s' % configname) + + self.WriteLn('\nLOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) ' + '$(MY_DEFS_$(GYP_CONFIGURATION))') + # Undefine ANDROID for host modules + # TODO: the source code should not use macro ANDROID to tell if it's host + # or target module. + if self.toolset == 'host': + self.WriteLn('# Undefine ANDROID for host modules') + self.WriteLn('LOCAL_CFLAGS += -UANDROID') + self.WriteLn('LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) ' + '$(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))') + self.WriteLn('LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))') + # Android uses separate flags for assembly file invocations, but gyp expects + # the same CFLAGS to be applied: + self.WriteLn('LOCAL_ASFLAGS := $(LOCAL_CFLAGS)') + + + def WriteSources(self, spec, configs, extra_sources): + """Write Makefile code for any 'sources' from the gyp input. + These are source files necessary to build the current target. + We need to handle shared_intermediate directory source files as + a special case by copying them to the intermediate directory and + treating them as a genereated sources. Otherwise the Android build + rules won't pick them up. + + Args: + spec, configs: input from gyp. + extra_sources: Sources generated from Actions or Rules. + """ + sources = filter(make.Compilable, spec.get('sources', [])) + generated_not_sources = [x for x in extra_sources if not make.Compilable(x)] + extra_sources = filter(make.Compilable, extra_sources) + + # Determine and output the C++ extension used by these sources. + # We simply find the first C++ file and use that extension. + all_sources = sources + extra_sources + local_cpp_extension = '.cpp' + for source in all_sources: + (root, ext) = os.path.splitext(source) + if IsCPPExtension(ext): + local_cpp_extension = ext + break + if local_cpp_extension != '.cpp': + self.WriteLn('LOCAL_CPP_EXTENSION := %s' % local_cpp_extension) + + # We need to move any non-generated sources that are coming from the + # shared intermediate directory out of LOCAL_SRC_FILES and put them + # into LOCAL_GENERATED_SOURCES. We also need to move over any C++ files + # that don't match our local_cpp_extension, since Android will only + # generate Makefile rules for a single LOCAL_CPP_EXTENSION. + local_files = [] + for source in sources: + (root, ext) = os.path.splitext(source) + if '$(gyp_shared_intermediate_dir)' in source: + extra_sources.append(source) + elif '$(gyp_intermediate_dir)' in source: + extra_sources.append(source) + elif IsCPPExtension(ext) and ext != local_cpp_extension: + extra_sources.append(source) + else: + local_files.append(os.path.normpath(os.path.join(self.path, source))) + + # For any generated source, if it is coming from the shared intermediate + # directory then we add a Make rule to copy them to the local intermediate + # directory first. This is because the Android LOCAL_GENERATED_SOURCES + # must be in the local module intermediate directory for the compile rules + # to work properly. If the file has the wrong C++ extension, then we add + # a rule to copy that to intermediates and use the new version. + final_generated_sources = [] + # If a source file gets copied, we still need to add the orginal source + # directory as header search path, for GCC searches headers in the + # directory that contains the source file by default. + origin_src_dirs = [] + for source in extra_sources: + local_file = source + if not '$(gyp_intermediate_dir)/' in local_file: + basename = os.path.basename(local_file) + local_file = '$(gyp_intermediate_dir)/' + basename + (root, ext) = os.path.splitext(local_file) + if IsCPPExtension(ext) and ext != local_cpp_extension: + local_file = root + local_cpp_extension + if local_file != source: + self.WriteLn('%s: %s' % (local_file, self.LocalPathify(source))) + self.WriteLn('\tmkdir -p $(@D); cp $< $@') + origin_src_dirs.append(os.path.dirname(source)) + final_generated_sources.append(local_file) + + # We add back in all of the non-compilable stuff to make sure that the + # make rules have dependencies on them. + final_generated_sources.extend(generated_not_sources) + self.WriteList(final_generated_sources, 'LOCAL_GENERATED_SOURCES') + + origin_src_dirs = gyp.common.uniquer(origin_src_dirs) + origin_src_dirs = map(Sourceify, map(self.LocalPathify, origin_src_dirs)) + self.WriteList(origin_src_dirs, 'GYP_COPIED_SOURCE_ORIGIN_DIRS') + + self.WriteList(local_files, 'LOCAL_SRC_FILES') + + # Write out the flags used to compile the source; this must be done last + # so that GYP_COPIED_SOURCE_ORIGIN_DIRS can be used as an include path. + self.WriteSourceFlags(spec, configs) + + + def ComputeAndroidModule(self, spec): + """Return the Android module name used for a gyp spec. + + We use the complete qualified target name to avoid collisions between + duplicate targets in different directories. We also add a suffix to + distinguish gyp-generated module names. + """ + + if int(spec.get('android_unmangled_name', 0)): + assert self.type != 'shared_library' or self.target.startswith('lib') + return self.target + + if self.type == 'shared_library': + # For reasons of convention, the Android build system requires that all + # shared library modules are named 'libfoo' when generating -l flags. + prefix = 'lib_' + else: + prefix = '' + + if spec['toolset'] == 'host': + suffix = '_$(TARGET_$(GYP_VAR_PREFIX)ARCH)_host_gyp' + else: + suffix = '_gyp' + + if self.path: + middle = make.StringToMakefileVariable('%s_%s' % (self.path, self.target)) + else: + middle = make.StringToMakefileVariable(self.target) + + return ''.join([prefix, middle, suffix]) + + + def ComputeOutputParts(self, spec): + """Return the 'output basename' of a gyp spec, split into filename + ext. + + Android libraries must be named the same thing as their module name, + otherwise the linker can't find them, so product_name and so on must be + ignored if we are building a library, and the "lib" prepending is + not done for Android. + """ + assert self.type != 'loadable_module' # TODO: not supported? + + target = spec['target_name'] + target_prefix = '' + target_ext = '' + if self.type == 'static_library': + target = self.ComputeAndroidModule(spec) + target_ext = '.a' + elif self.type == 'shared_library': + target = self.ComputeAndroidModule(spec) + target_ext = '.so' + elif self.type == 'none': + target_ext = '.stamp' + elif self.type != 'executable': + print ("ERROR: What output file should be generated?", + "type", self.type, "target", target) + + if self.type != 'static_library' and self.type != 'shared_library': + target_prefix = spec.get('product_prefix', target_prefix) + target = spec.get('product_name', target) + product_ext = spec.get('product_extension') + if product_ext: + target_ext = '.' + product_ext + + target_stem = target_prefix + target + return (target_stem, target_ext) + + + def ComputeOutputBasename(self, spec): + """Return the 'output basename' of a gyp spec. + + E.g., the loadable module 'foobar' in directory 'baz' will produce + 'libfoobar.so' + """ + return ''.join(self.ComputeOutputParts(spec)) + + + def ComputeOutput(self, spec): + """Return the 'output' (full output path) of a gyp spec. + + E.g., the loadable module 'foobar' in directory 'baz' will produce + '$(obj)/baz/libfoobar.so' + """ + if self.type == 'executable' and self.toolset == 'host': + # We install host executables into shared_intermediate_dir so they can be + # run by gyp rules that refer to PRODUCT_DIR. + path = '$(gyp_shared_intermediate_dir)' + elif self.type == 'shared_library': + if self.toolset == 'host': + path = '$(HOST_OUT_INTERMEDIATE_LIBRARIES)' + else: + path = '$($(GYP_VAR_PREFIX)TARGET_OUT_INTERMEDIATE_LIBRARIES)' + else: + # Other targets just get built into their intermediate dir. + if self.toolset == 'host': + path = '$(call intermediates-dir-for,%s,%s,true)' % (self.android_class, + self.android_module) + else: + path = ('$(call intermediates-dir-for,%s,%s,,,$(GYP_VAR_PREFIX))' + % (self.android_class, self.android_module)) + + assert spec.get('product_dir') is None # TODO: not supported? + return os.path.join(path, self.ComputeOutputBasename(spec)) + + def NormalizeIncludePaths(self, include_paths): + """ Normalize include_paths. + Convert absolute paths to relative to the Android top directory; + filter out include paths that are already brought in by the Android build + system. + + Args: + include_paths: A list of unprocessed include paths. + Returns: + A list of normalized include paths. + """ + normalized = [] + for path in include_paths: + if path[0] == '/': + path = gyp.common.RelativePath(path, self.android_top_dir) + + # Filter out the Android standard search path. + if path not in android_standard_include_paths: + normalized.append(path) + return normalized + + def ExtractIncludesFromCFlags(self, cflags): + """Extract includes "-I..." out from cflags + + Args: + cflags: A list of compiler flags, which may be mixed with "-I.." + Returns: + A tuple of lists: (clean_clfags, include_paths). "-I.." is trimmed. + """ + clean_cflags = [] + include_paths = [] + for flag in cflags: + if flag.startswith('-I'): + include_paths.append(flag[2:]) + else: + clean_cflags.append(flag) + + return (clean_cflags, include_paths) + + def ComputeAndroidLibraryModuleNames(self, libraries): + """Compute the Android module names from libraries, ie spec.get('libraries') + + Args: + libraries: the value of spec.get('libraries') + Returns: + A tuple (static_lib_modules, dynamic_lib_modules) + """ + static_lib_modules = [] + dynamic_lib_modules = [] + for libs in libraries: + # Libs can have multiple words. + for lib in libs.split(): + # Filter the system libraries, which are added by default by the Android + # build system. + if (lib == '-lc' or lib == '-lstdc++' or lib == '-lm' or + lib.endswith('libgcc.a')): + continue + match = re.search(r'([^/]+)\.a$', lib) + if match: + static_lib_modules.append(match.group(1)) + continue + match = re.search(r'([^/]+)\.so$', lib) + if match: + dynamic_lib_modules.append(match.group(1)) + continue + # "-lstlport" -> libstlport + if lib.startswith('-l'): + if lib.endswith('_static'): + static_lib_modules.append('lib' + lib[2:]) + else: + dynamic_lib_modules.append('lib' + lib[2:]) + return (static_lib_modules, dynamic_lib_modules) + + + def ComputeDeps(self, spec): + """Compute the dependencies of a gyp spec. + + Returns a tuple (deps, link_deps), where each is a list of + filenames that will need to be put in front of make for either + building (deps) or linking (link_deps). + """ + deps = [] + link_deps = [] + if 'dependencies' in spec: + deps.extend([target_outputs[dep] for dep in spec['dependencies'] + if target_outputs[dep]]) + for dep in spec['dependencies']: + if dep in target_link_deps: + link_deps.append(target_link_deps[dep]) + deps.extend(link_deps) + return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps)) + + + def WriteTargetFlags(self, spec, configs, link_deps): + """Write Makefile code to specify the link flags and library dependencies. + + spec, configs: input from gyp. + link_deps: link dependency list; see ComputeDeps() + """ + for configname, config in sorted(configs.iteritems()): + ldflags = list(config.get('ldflags', [])) + self.WriteLn('') + self.WriteList(ldflags, 'LOCAL_LDFLAGS_%s' % configname) + self.WriteLn('\nLOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))') + + # Libraries (i.e. -lfoo) + libraries = gyp.common.uniquer(spec.get('libraries', [])) + static_libs, dynamic_libs = self.ComputeAndroidLibraryModuleNames( + libraries) + + # Link dependencies (i.e. libfoo.a, libfoo.so) + static_link_deps = [x[1] for x in link_deps if x[0] == 'static'] + shared_link_deps = [x[1] for x in link_deps if x[0] == 'shared'] + self.WriteLn('') + self.WriteList(static_libs + static_link_deps, + 'LOCAL_STATIC_LIBRARIES') + self.WriteLn('# Enable grouping to fix circular references') + self.WriteLn('LOCAL_GROUP_STATIC_LIBRARIES := true') + self.WriteLn('') + self.WriteList(dynamic_libs + shared_link_deps, + 'LOCAL_SHARED_LIBRARIES') + + + def WriteTarget(self, spec, configs, deps, link_deps, part_of_all, + write_alias_target): + """Write Makefile code to produce the final target of the gyp spec. + + spec, configs: input from gyp. + deps, link_deps: dependency lists; see ComputeDeps() + part_of_all: flag indicating this target is part of 'all' + write_alias_target: flag indicating whether to create short aliases for this + target + """ + self.WriteLn('### Rules for final target.') + + if self.type != 'none': + self.WriteTargetFlags(spec, configs, link_deps) + + # Add to the set of targets which represent the gyp 'all' target. We use the + # name 'gyp_all_modules' as the Android build system doesn't allow the use + # of the Make target 'all' and because 'all_modules' is the equivalent of + # the Make target 'all' on Android. + if part_of_all and write_alias_target: + self.WriteLn('# Add target alias to "gyp_all_modules" target.') + self.WriteLn('.PHONY: gyp_all_modules') + self.WriteLn('gyp_all_modules: %s' % self.android_module) + self.WriteLn('') + + # Add an alias from the gyp target name to the Android module name. This + # simplifies manual builds of the target, and is required by the test + # framework. + if self.target != self.android_module and write_alias_target: + self.WriteLn('# Alias gyp target name.') + self.WriteLn('.PHONY: %s' % self.target) + self.WriteLn('%s: %s' % (self.target, self.android_module)) + self.WriteLn('') + + # Add the command to trigger build of the target type depending + # on the toolset. Ex: BUILD_STATIC_LIBRARY vs. BUILD_HOST_STATIC_LIBRARY + # NOTE: This has to come last! + modifier = '' + if self.toolset == 'host': + modifier = 'HOST_' + if self.type == 'static_library': + self.WriteLn('include $(BUILD_%sSTATIC_LIBRARY)' % modifier) + elif self.type == 'shared_library': + self.WriteLn('LOCAL_PRELINK_MODULE := false') + self.WriteLn('include $(BUILD_%sSHARED_LIBRARY)' % modifier) + elif self.type == 'executable': + if self.toolset == 'host': + self.WriteLn('LOCAL_MODULE_PATH := $(gyp_shared_intermediate_dir)') + else: + # Don't install target executables for now, as it results in them being + # included in ROM. This can be revisited if there's a reason to install + # them later. + self.WriteLn('LOCAL_UNINSTALLABLE_MODULE := true') + self.WriteLn('include $(BUILD_%sEXECUTABLE)' % modifier) + else: + self.WriteLn('LOCAL_MODULE_PATH := $(PRODUCT_OUT)/gyp_stamp') + self.WriteLn('LOCAL_UNINSTALLABLE_MODULE := true') + if self.toolset == 'target': + self.WriteLn('LOCAL_2ND_ARCH_VAR_PREFIX := $(GYP_VAR_PREFIX)') + self.WriteLn() + self.WriteLn('include $(BUILD_SYSTEM)/base_rules.mk') + self.WriteLn() + self.WriteLn('$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)') + self.WriteLn('\t$(hide) echo "Gyp timestamp: $@"') + self.WriteLn('\t$(hide) mkdir -p $(dir $@)') + self.WriteLn('\t$(hide) touch $@') + if self.toolset == 'target': + self.WriteLn() + self.WriteLn('LOCAL_2ND_ARCH_VAR_PREFIX :=') + + + def WriteList(self, value_list, variable=None, prefix='', + quoter=make.QuoteIfNecessary, local_pathify=False): + """Write a variable definition that is a list of values. + + E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out + foo = blaha blahb + but in a pretty-printed style. + """ + values = '' + if value_list: + value_list = [quoter(prefix + l) for l in value_list] + if local_pathify: + value_list = [self.LocalPathify(l) for l in value_list] + values = ' \\\n\t' + ' \\\n\t'.join(value_list) + self.fp.write('%s :=%s\n\n' % (variable, values)) + + + def WriteLn(self, text=''): + self.fp.write(text + '\n') + + + def LocalPathify(self, path): + """Convert a subdirectory-relative path into a normalized path which starts + with the make variable $(LOCAL_PATH) (i.e. the top of the project tree). + Absolute paths, or paths that contain variables, are just normalized.""" + if '$(' in path or os.path.isabs(path): + # path is not a file in the project tree in this case, but calling + # normpath is still important for trimming trailing slashes. + return os.path.normpath(path) + local_path = os.path.join('$(LOCAL_PATH)', self.path, path) + local_path = os.path.normpath(local_path) + # Check that normalizing the path didn't ../ itself out of $(LOCAL_PATH) + # - i.e. that the resulting path is still inside the project tree. The + # path may legitimately have ended up containing just $(LOCAL_PATH), though, + # so we don't look for a slash. + assert local_path.startswith('$(LOCAL_PATH)'), ( + 'Path %s attempts to escape from gyp path %s !)' % (path, self.path)) + return local_path + + + def ExpandInputRoot(self, template, expansion, dirname): + if '%(INPUT_ROOT)s' not in template and '%(INPUT_DIRNAME)s' not in template: + return template + path = template % { + 'INPUT_ROOT': expansion, + 'INPUT_DIRNAME': dirname, + } + return os.path.normpath(path) + + +def PerformBuild(data, configurations, params): + # The android backend only supports the default configuration. + options = params['options'] + makefile = os.path.abspath(os.path.join(options.toplevel_dir, + 'GypAndroid.mk')) + env = dict(os.environ) + env['ONE_SHOT_MAKEFILE'] = makefile + arguments = ['make', '-C', os.environ['ANDROID_BUILD_TOP'], 'gyp_all_modules'] + print 'Building: %s' % arguments + subprocess.check_call(arguments, env=env) + + +def GenerateOutput(target_list, target_dicts, data, params): + options = params['options'] + generator_flags = params.get('generator_flags', {}) + builddir_name = generator_flags.get('output_dir', 'out') + limit_to_target_all = generator_flags.get('limit_to_target_all', False) + write_alias_targets = generator_flags.get('write_alias_targets', True) + android_top_dir = os.environ.get('ANDROID_BUILD_TOP') + assert android_top_dir, '$ANDROID_BUILD_TOP not set; you need to run lunch.' + + def CalculateMakefilePath(build_file, base_name): + """Determine where to write a Makefile for a given gyp file.""" + # Paths in gyp files are relative to the .gyp file, but we want + # paths relative to the source root for the master makefile. Grab + # the path of the .gyp file as the base to relativize against. + # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp". + base_path = gyp.common.RelativePath(os.path.dirname(build_file), + options.depth) + # We write the file in the base_path directory. + output_file = os.path.join(options.depth, base_path, base_name) + assert not options.generator_output, ( + 'The Android backend does not support options.generator_output.') + base_path = gyp.common.RelativePath(os.path.dirname(build_file), + options.toplevel_dir) + return base_path, output_file + + # TODO: search for the first non-'Default' target. This can go + # away when we add verification that all targets have the + # necessary configurations. + default_configuration = None + toolsets = set([target_dicts[target]['toolset'] for target in target_list]) + for target in target_list: + spec = target_dicts[target] + if spec['default_configuration'] != 'Default': + default_configuration = spec['default_configuration'] + break + if not default_configuration: + default_configuration = 'Default' + + srcdir = '.' + makefile_name = 'GypAndroid' + options.suffix + '.mk' + makefile_path = os.path.join(options.toplevel_dir, makefile_name) + assert not options.generator_output, ( + 'The Android backend does not support options.generator_output.') + gyp.common.EnsureDirExists(makefile_path) + root_makefile = open(makefile_path, 'w') + + root_makefile.write(header) + + # We set LOCAL_PATH just once, here, to the top of the project tree. This + # allows all the other paths we use to be relative to the Android.mk file, + # as the Android build system expects. + root_makefile.write('\nLOCAL_PATH := $(call my-dir)\n') + + # Find the list of targets that derive from the gyp file(s) being built. + needed_targets = set() + for build_file in params['build_files']: + for target in gyp.common.AllTargets(target_list, target_dicts, build_file): + needed_targets.add(target) + + build_files = set() + include_list = set() + android_modules = {} + for qualified_target in target_list: + build_file, target, toolset = gyp.common.ParseQualifiedTarget( + qualified_target) + relative_build_file = gyp.common.RelativePath(build_file, + options.toplevel_dir) + build_files.add(relative_build_file) + included_files = data[build_file]['included_files'] + for included_file in included_files: + # The included_files entries are relative to the dir of the build file + # that included them, so we have to undo that and then make them relative + # to the root dir. + relative_include_file = gyp.common.RelativePath( + gyp.common.UnrelativePath(included_file, build_file), + options.toplevel_dir) + abs_include_file = os.path.abspath(relative_include_file) + # If the include file is from the ~/.gyp dir, we should use absolute path + # so that relocating the src dir doesn't break the path. + if (params['home_dot_gyp'] and + abs_include_file.startswith(params['home_dot_gyp'])): + build_files.add(abs_include_file) + else: + build_files.add(relative_include_file) + + base_path, output_file = CalculateMakefilePath(build_file, + target + '.' + toolset + options.suffix + '.mk') + + spec = target_dicts[qualified_target] + configs = spec['configurations'] + + part_of_all = (qualified_target in needed_targets and + not int(spec.get('suppress_wildcard', False))) + if limit_to_target_all and not part_of_all: + continue + + relative_target = gyp.common.QualifiedTarget(relative_build_file, target, + toolset) + writer = AndroidMkWriter(android_top_dir) + android_module = writer.Write(qualified_target, relative_target, base_path, + output_file, spec, configs, + part_of_all=part_of_all, + write_alias_target=write_alias_targets) + if android_module in android_modules: + print ('ERROR: Android module names must be unique. The following ' + 'targets both generate Android module name %s.\n %s\n %s' % + (android_module, android_modules[android_module], + qualified_target)) + return + android_modules[android_module] = qualified_target + + # Our root_makefile lives at the source root. Compute the relative path + # from there to the output_file for including. + mkfile_rel_path = gyp.common.RelativePath(output_file, + os.path.dirname(makefile_path)) + include_list.add(mkfile_rel_path) + + root_makefile.write('GYP_CONFIGURATION ?= %s\n' % default_configuration) + root_makefile.write('GYP_VAR_PREFIX ?=\n') + + # Write out the sorted list of includes. + root_makefile.write('\n') + for include_file in sorted(include_list): + root_makefile.write('include $(LOCAL_PATH)/' + include_file + '\n') + root_makefile.write('\n') + + if write_alias_targets: + root_makefile.write(ALL_MODULES_FOOTER) + + root_makefile.close() diff --git a/deps/gyp/pylib/gyp/generator/cmake.py b/deps/gyp/pylib/gyp/generator/cmake.py new file mode 100644 index 000000000..10d015ee8 --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/cmake.py @@ -0,0 +1,1143 @@ +# Copyright (c) 2013 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""cmake output module + +This module is under development and should be considered experimental. + +This module produces cmake (2.8.8+) input as its output. One CMakeLists.txt is +created for each configuration. + +This module's original purpose was to support editing in IDEs like KDevelop +which use CMake for project management. It is also possible to use CMake to +generate projects for other IDEs such as eclipse cdt and code::blocks. QtCreator +will convert the CMakeLists.txt to a code::blocks cbp for the editor to read, +but build using CMake. As a result QtCreator editor is unaware of compiler +defines. The generated CMakeLists.txt can also be used to build on Linux. There +is currently no support for building on platforms other than Linux. + +The generated CMakeLists.txt should properly compile all projects. However, +there is a mismatch between gyp and cmake with regard to linking. All attempts +are made to work around this, but CMake sometimes sees -Wl,--start-group as a +library and incorrectly repeats it. As a result the output of this generator +should not be relied on for building. + +When using with kdevelop, use version 4.4+. Previous versions of kdevelop will +not be able to find the header file directories described in the generated +CMakeLists.txt file. +""" + +import multiprocessing +import os +import signal +import string +import subprocess +import gyp.common + +generator_default_variables = { + 'EXECUTABLE_PREFIX': '', + 'EXECUTABLE_SUFFIX': '', + 'STATIC_LIB_PREFIX': 'lib', + 'STATIC_LIB_SUFFIX': '.a', + 'SHARED_LIB_PREFIX': 'lib', + 'SHARED_LIB_SUFFIX': '.so', + 'SHARED_LIB_DIR': '${builddir}/lib.${TOOLSET}', + 'LIB_DIR': '${obj}.${TOOLSET}', + 'INTERMEDIATE_DIR': '${obj}.${TOOLSET}/${TARGET}/geni', + 'SHARED_INTERMEDIATE_DIR': '${obj}/gen', + 'PRODUCT_DIR': '${builddir}', + 'RULE_INPUT_PATH': '${RULE_INPUT_PATH}', + 'RULE_INPUT_DIRNAME': '${RULE_INPUT_DIRNAME}', + 'RULE_INPUT_NAME': '${RULE_INPUT_NAME}', + 'RULE_INPUT_ROOT': '${RULE_INPUT_ROOT}', + 'RULE_INPUT_EXT': '${RULE_INPUT_EXT}', + 'CONFIGURATION_NAME': '${configuration}', +} + +FULL_PATH_VARS = ('${CMAKE_SOURCE_DIR}', '${builddir}', '${obj}') + +generator_supports_multiple_toolsets = True +generator_wants_static_library_dependencies_adjusted = True + +COMPILABLE_EXTENSIONS = { + '.c': 'cc', + '.cc': 'cxx', + '.cpp': 'cxx', + '.cxx': 'cxx', + '.s': 's', # cc + '.S': 's', # cc +} + + +def RemovePrefix(a, prefix): + """Returns 'a' without 'prefix' if it starts with 'prefix'.""" + return a[len(prefix):] if a.startswith(prefix) else a + + +def CalculateVariables(default_variables, params): + """Calculate additional variables for use in the build (called by gyp).""" + default_variables.setdefault('OS', gyp.common.GetFlavor(params)) + + +def Compilable(filename): + """Return true if the file is compilable (should be in OBJS).""" + return any(filename.endswith(e) for e in COMPILABLE_EXTENSIONS) + + +def Linkable(filename): + """Return true if the file is linkable (should be on the link line).""" + return filename.endswith('.o') + + +def NormjoinPathForceCMakeSource(base_path, rel_path): + """Resolves rel_path against base_path and returns the result. + + If rel_path is an absolute path it is returned unchanged. + Otherwise it is resolved against base_path and normalized. + If the result is a relative path, it is forced to be relative to the + CMakeLists.txt. + """ + if os.path.isabs(rel_path): + return rel_path + if any([rel_path.startswith(var) for var in FULL_PATH_VARS]): + return rel_path + # TODO: do we need to check base_path for absolute variables as well? + return os.path.join('${CMAKE_SOURCE_DIR}', + os.path.normpath(os.path.join(base_path, rel_path))) + + +def NormjoinPath(base_path, rel_path): + """Resolves rel_path against base_path and returns the result. + TODO: what is this really used for? + If rel_path begins with '$' it is returned unchanged. + Otherwise it is resolved against base_path if relative, then normalized. + """ + if rel_path.startswith('$') and not rel_path.startswith('${configuration}'): + return rel_path + return os.path.normpath(os.path.join(base_path, rel_path)) + + +def CMakeStringEscape(a): + """Escapes the string 'a' for use inside a CMake string. + + This means escaping + '\' otherwise it may be seen as modifying the next character + '"' otherwise it will end the string + ';' otherwise the string becomes a list + + The following do not need to be escaped + '#' when the lexer is in string state, this does not start a comment + + The following are yet unknown + '$' generator variables (like ${obj}) must not be escaped, + but text $ should be escaped + what is wanted is to know which $ come from generator variables + """ + return a.replace('\\', '\\\\').replace(';', '\\;').replace('"', '\\"') + + +def SetFileProperty(output, source_name, property_name, values, sep): + """Given a set of source file, sets the given property on them.""" + output.write('set_source_files_properties(') + output.write(source_name) + output.write(' PROPERTIES ') + output.write(property_name) + output.write(' "') + for value in values: + output.write(CMakeStringEscape(value)) + output.write(sep) + output.write('")\n') + + +def SetFilesProperty(output, source_names, property_name, values, sep): + """Given a set of source files, sets the given property on them.""" + output.write('set_source_files_properties(\n') + for source_name in source_names: + output.write(' ') + output.write(source_name) + output.write('\n') + output.write(' PROPERTIES\n ') + output.write(property_name) + output.write(' "') + for value in values: + output.write(CMakeStringEscape(value)) + output.write(sep) + output.write('"\n)\n') + + +def SetTargetProperty(output, target_name, property_name, values, sep=''): + """Given a target, sets the given property.""" + output.write('set_target_properties(') + output.write(target_name) + output.write(' PROPERTIES ') + output.write(property_name) + output.write(' "') + for value in values: + output.write(CMakeStringEscape(value)) + output.write(sep) + output.write('")\n') + + +def SetVariable(output, variable_name, value): + """Sets a CMake variable.""" + output.write('set(') + output.write(variable_name) + output.write(' "') + output.write(CMakeStringEscape(value)) + output.write('")\n') + + +def SetVariableList(output, variable_name, values): + """Sets a CMake variable to a list.""" + if not values: + return SetVariable(output, variable_name, "") + if len(values) == 1: + return SetVariable(output, variable_name, values[0]) + output.write('list(APPEND ') + output.write(variable_name) + output.write('\n "') + output.write('"\n "'.join([CMakeStringEscape(value) for value in values])) + output.write('")\n') + + +def UnsetVariable(output, variable_name): + """Unsets a CMake variable.""" + output.write('unset(') + output.write(variable_name) + output.write(')\n') + + +def WriteVariable(output, variable_name, prepend=None): + if prepend: + output.write(prepend) + output.write('${') + output.write(variable_name) + output.write('}') + + +class CMakeTargetType: + def __init__(self, command, modifier, property_modifier): + self.command = command + self.modifier = modifier + self.property_modifier = property_modifier + + +cmake_target_type_from_gyp_target_type = { + 'executable': CMakeTargetType('add_executable', None, 'RUNTIME'), + 'static_library': CMakeTargetType('add_library', 'STATIC', 'ARCHIVE'), + 'shared_library': CMakeTargetType('add_library', 'SHARED', 'LIBRARY'), + 'loadable_module': CMakeTargetType('add_library', 'MODULE', 'LIBRARY'), + 'none': CMakeTargetType('add_custom_target', 'SOURCES', None), +} + + +def StringToCMakeTargetName(a): + """Converts the given string 'a' to a valid CMake target name. + + All invalid characters are replaced by '_'. + Invalid for cmake: ' ', '/', '(', ')' + Invalid for make: ':' + Invalid for unknown reasons but cause failures: '.' + """ + return a.translate(string.maketrans(' /():.', '______')) + + +def WriteActions(target_name, actions, extra_sources, extra_deps, + path_to_gyp, output): + """Write CMake for the 'actions' in the target. + + Args: + target_name: the name of the CMake target being generated. + actions: the Gyp 'actions' dict for this target. + extra_sources: [(, )] to append with generated source files. + extra_deps: [] to append with generated targets. + path_to_gyp: relative path from CMakeLists.txt being generated to + the Gyp file in which the target being generated is defined. + """ + for action in actions: + action_name = StringToCMakeTargetName(action['action_name']) + action_target_name = '%s__%s' % (target_name, action_name) + + inputs = action['inputs'] + inputs_name = action_target_name + '__input' + SetVariableList(output, inputs_name, + [NormjoinPathForceCMakeSource(path_to_gyp, dep) for dep in inputs]) + + outputs = action['outputs'] + cmake_outputs = [NormjoinPathForceCMakeSource(path_to_gyp, out) + for out in outputs] + outputs_name = action_target_name + '__output' + SetVariableList(output, outputs_name, cmake_outputs) + + # Build up a list of outputs. + # Collect the output dirs we'll need. + dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir) + + if int(action.get('process_outputs_as_sources', False)): + extra_sources.extend(zip(cmake_outputs, outputs)) + + # add_custom_command + output.write('add_custom_command(OUTPUT ') + WriteVariable(output, outputs_name) + output.write('\n') + + if len(dirs) > 0: + for directory in dirs: + output.write(' COMMAND ${CMAKE_COMMAND} -E make_directory ') + output.write(directory) + output.write('\n') + + output.write(' COMMAND ') + output.write(gyp.common.EncodePOSIXShellList(action['action'])) + output.write('\n') + + output.write(' DEPENDS ') + WriteVariable(output, inputs_name) + output.write('\n') + + output.write(' WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/') + output.write(path_to_gyp) + output.write('\n') + + output.write(' COMMENT ') + if 'message' in action: + output.write(action['message']) + else: + output.write(action_target_name) + output.write('\n') + + output.write(' VERBATIM\n') + output.write(')\n') + + # add_custom_target + output.write('add_custom_target(') + output.write(action_target_name) + output.write('\n DEPENDS ') + WriteVariable(output, outputs_name) + output.write('\n SOURCES ') + WriteVariable(output, inputs_name) + output.write('\n)\n') + + extra_deps.append(action_target_name) + + +def NormjoinRulePathForceCMakeSource(base_path, rel_path, rule_source): + if rel_path.startswith(("${RULE_INPUT_PATH}","${RULE_INPUT_DIRNAME}")): + if any([rule_source.startswith(var) for var in FULL_PATH_VARS]): + return rel_path + return NormjoinPathForceCMakeSource(base_path, rel_path) + + +def WriteRules(target_name, rules, extra_sources, extra_deps, + path_to_gyp, output): + """Write CMake for the 'rules' in the target. + + Args: + target_name: the name of the CMake target being generated. + actions: the Gyp 'actions' dict for this target. + extra_sources: [(, )] to append with generated source files. + extra_deps: [] to append with generated targets. + path_to_gyp: relative path from CMakeLists.txt being generated to + the Gyp file in which the target being generated is defined. + """ + for rule in rules: + rule_name = StringToCMakeTargetName(target_name + '__' + rule['rule_name']) + + inputs = rule.get('inputs', []) + inputs_name = rule_name + '__input' + SetVariableList(output, inputs_name, + [NormjoinPathForceCMakeSource(path_to_gyp, dep) for dep in inputs]) + outputs = rule['outputs'] + var_outputs = [] + + for count, rule_source in enumerate(rule.get('rule_sources', [])): + action_name = rule_name + '_' + str(count) + + rule_source_dirname, rule_source_basename = os.path.split(rule_source) + rule_source_root, rule_source_ext = os.path.splitext(rule_source_basename) + + SetVariable(output, 'RULE_INPUT_PATH', rule_source) + SetVariable(output, 'RULE_INPUT_DIRNAME', rule_source_dirname) + SetVariable(output, 'RULE_INPUT_NAME', rule_source_basename) + SetVariable(output, 'RULE_INPUT_ROOT', rule_source_root) + SetVariable(output, 'RULE_INPUT_EXT', rule_source_ext) + + # Build up a list of outputs. + # Collect the output dirs we'll need. + dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir) + + # Create variables for the output, as 'local' variable will be unset. + these_outputs = [] + for output_index, out in enumerate(outputs): + output_name = action_name + '_' + str(output_index) + SetVariable(output, output_name, + NormjoinRulePathForceCMakeSource(path_to_gyp, out, + rule_source)) + if int(rule.get('process_outputs_as_sources', False)): + extra_sources.append(('${' + output_name + '}', out)) + these_outputs.append('${' + output_name + '}') + var_outputs.append('${' + output_name + '}') + + # add_custom_command + output.write('add_custom_command(OUTPUT\n') + for out in these_outputs: + output.write(' ') + output.write(out) + output.write('\n') + + for directory in dirs: + output.write(' COMMAND ${CMAKE_COMMAND} -E make_directory ') + output.write(directory) + output.write('\n') + + output.write(' COMMAND ') + output.write(gyp.common.EncodePOSIXShellList(rule['action'])) + output.write('\n') + + output.write(' DEPENDS ') + WriteVariable(output, inputs_name) + output.write(' ') + output.write(NormjoinPath(path_to_gyp, rule_source)) + output.write('\n') + + # CMAKE_SOURCE_DIR is where the CMakeLists.txt lives. + # The cwd is the current build directory. + output.write(' WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/') + output.write(path_to_gyp) + output.write('\n') + + output.write(' COMMENT ') + if 'message' in rule: + output.write(rule['message']) + else: + output.write(action_name) + output.write('\n') + + output.write(' VERBATIM\n') + output.write(')\n') + + UnsetVariable(output, 'RULE_INPUT_PATH') + UnsetVariable(output, 'RULE_INPUT_DIRNAME') + UnsetVariable(output, 'RULE_INPUT_NAME') + UnsetVariable(output, 'RULE_INPUT_ROOT') + UnsetVariable(output, 'RULE_INPUT_EXT') + + # add_custom_target + output.write('add_custom_target(') + output.write(rule_name) + output.write(' DEPENDS\n') + for out in var_outputs: + output.write(' ') + output.write(out) + output.write('\n') + output.write('SOURCES ') + WriteVariable(output, inputs_name) + output.write('\n') + for rule_source in rule.get('rule_sources', []): + output.write(' ') + output.write(NormjoinPath(path_to_gyp, rule_source)) + output.write('\n') + output.write(')\n') + + extra_deps.append(rule_name) + + +def WriteCopies(target_name, copies, extra_deps, path_to_gyp, output): + """Write CMake for the 'copies' in the target. + + Args: + target_name: the name of the CMake target being generated. + actions: the Gyp 'actions' dict for this target. + extra_deps: [] to append with generated targets. + path_to_gyp: relative path from CMakeLists.txt being generated to + the Gyp file in which the target being generated is defined. + """ + copy_name = target_name + '__copies' + + # CMake gets upset with custom targets with OUTPUT which specify no output. + have_copies = any(copy['files'] for copy in copies) + if not have_copies: + output.write('add_custom_target(') + output.write(copy_name) + output.write(')\n') + extra_deps.append(copy_name) + return + + class Copy: + def __init__(self, ext, command): + self.cmake_inputs = [] + self.cmake_outputs = [] + self.gyp_inputs = [] + self.gyp_outputs = [] + self.ext = ext + self.inputs_name = None + self.outputs_name = None + self.command = command + + file_copy = Copy('', 'copy') + dir_copy = Copy('_dirs', 'copy_directory') + + for copy in copies: + files = copy['files'] + destination = copy['destination'] + for src in files: + path = os.path.normpath(src) + basename = os.path.split(path)[1] + dst = os.path.join(destination, basename) + + copy = file_copy if os.path.basename(src) else dir_copy + + copy.cmake_inputs.append(NormjoinPath(path_to_gyp, src)) + copy.cmake_outputs.append(NormjoinPathForceCMakeSource(path_to_gyp, dst)) + copy.gyp_inputs.append(src) + copy.gyp_outputs.append(dst) + + for copy in (file_copy, dir_copy): + if copy.cmake_inputs: + copy.inputs_name = copy_name + '__input' + copy.ext + SetVariableList(output, copy.inputs_name, copy.cmake_inputs) + + copy.outputs_name = copy_name + '__output' + copy.ext + SetVariableList(output, copy.outputs_name, copy.cmake_outputs) + + # add_custom_command + output.write('add_custom_command(\n') + + output.write('OUTPUT') + for copy in (file_copy, dir_copy): + if copy.outputs_name: + WriteVariable(output, copy.outputs_name, ' ') + output.write('\n') + + for copy in (file_copy, dir_copy): + for src, dst in zip(copy.gyp_inputs, copy.gyp_outputs): + # 'cmake -E copy src dst' will create the 'dst' directory if needed. + output.write('COMMAND ${CMAKE_COMMAND} -E %s ' % copy.command) + output.write(src) + output.write(' ') + output.write(dst) + output.write("\n") + + output.write('DEPENDS') + for copy in (file_copy, dir_copy): + if copy.inputs_name: + WriteVariable(output, copy.inputs_name, ' ') + output.write('\n') + + output.write('WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/') + output.write(path_to_gyp) + output.write('\n') + + output.write('COMMENT Copying for ') + output.write(target_name) + output.write('\n') + + output.write('VERBATIM\n') + output.write(')\n') + + # add_custom_target + output.write('add_custom_target(') + output.write(copy_name) + output.write('\n DEPENDS') + for copy in (file_copy, dir_copy): + if copy.outputs_name: + WriteVariable(output, copy.outputs_name, ' ') + output.write('\n SOURCES') + if file_copy.inputs_name: + WriteVariable(output, file_copy.inputs_name, ' ') + output.write('\n)\n') + + extra_deps.append(copy_name) + + +def CreateCMakeTargetBaseName(qualified_target): + """This is the name we would like the target to have.""" + _, gyp_target_name, gyp_target_toolset = ( + gyp.common.ParseQualifiedTarget(qualified_target)) + cmake_target_base_name = gyp_target_name + if gyp_target_toolset and gyp_target_toolset != 'target': + cmake_target_base_name += '_' + gyp_target_toolset + return StringToCMakeTargetName(cmake_target_base_name) + + +def CreateCMakeTargetFullName(qualified_target): + """An unambiguous name for the target.""" + gyp_file, gyp_target_name, gyp_target_toolset = ( + gyp.common.ParseQualifiedTarget(qualified_target)) + cmake_target_full_name = gyp_file + ':' + gyp_target_name + if gyp_target_toolset and gyp_target_toolset != 'target': + cmake_target_full_name += '_' + gyp_target_toolset + return StringToCMakeTargetName(cmake_target_full_name) + + +class CMakeNamer(object): + """Converts Gyp target names into CMake target names. + + CMake requires that target names be globally unique. One way to ensure + this is to fully qualify the names of the targets. Unfortunatly, this + ends up with all targets looking like "chrome_chrome_gyp_chrome" instead + of just "chrome". If this generator were only interested in building, it + would be possible to fully qualify all target names, then create + unqualified target names which depend on all qualified targets which + should have had that name. This is more or less what the 'make' generator + does with aliases. However, one goal of this generator is to create CMake + files for use with IDEs, and fully qualified names are not as user + friendly. + + Since target name collision is rare, we do the above only when required. + + Toolset variants are always qualified from the base, as this is required for + building. However, it also makes sense for an IDE, as it is possible for + defines to be different. + """ + def __init__(self, target_list): + self.cmake_target_base_names_conficting = set() + + cmake_target_base_names_seen = set() + for qualified_target in target_list: + cmake_target_base_name = CreateCMakeTargetBaseName(qualified_target) + + if cmake_target_base_name not in cmake_target_base_names_seen: + cmake_target_base_names_seen.add(cmake_target_base_name) + else: + self.cmake_target_base_names_conficting.add(cmake_target_base_name) + + def CreateCMakeTargetName(self, qualified_target): + base_name = CreateCMakeTargetBaseName(qualified_target) + if base_name in self.cmake_target_base_names_conficting: + return CreateCMakeTargetFullName(qualified_target) + return base_name + + +def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, + options, generator_flags, all_qualified_targets, output): + + # The make generator does this always. + # TODO: It would be nice to be able to tell CMake all dependencies. + circular_libs = generator_flags.get('circular', True) + + if not generator_flags.get('standalone', False): + output.write('\n#') + output.write(qualified_target) + output.write('\n') + + gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target) + rel_gyp_file = gyp.common.RelativePath(gyp_file, options.toplevel_dir) + rel_gyp_dir = os.path.dirname(rel_gyp_file) + + # Relative path from build dir to top dir. + build_to_top = gyp.common.InvertRelativePath(build_dir, options.toplevel_dir) + # Relative path from build dir to gyp dir. + build_to_gyp = os.path.join(build_to_top, rel_gyp_dir) + + path_from_cmakelists_to_gyp = build_to_gyp + + spec = target_dicts.get(qualified_target, {}) + config = spec.get('configurations', {}).get(config_to_use, {}) + + target_name = spec.get('target_name', '') + target_type = spec.get('type', '') + target_toolset = spec.get('toolset') + + SetVariable(output, 'TARGET', target_name) + SetVariable(output, 'TOOLSET', target_toolset) + + cmake_target_name = namer.CreateCMakeTargetName(qualified_target) + + extra_sources = [] + extra_deps = [] + + # Actions must come first, since they can generate more OBJs for use below. + if 'actions' in spec: + WriteActions(cmake_target_name, spec['actions'], extra_sources, extra_deps, + path_from_cmakelists_to_gyp, output) + + # Rules must be early like actions. + if 'rules' in spec: + WriteRules(cmake_target_name, spec['rules'], extra_sources, extra_deps, + path_from_cmakelists_to_gyp, output) + + # Copies + if 'copies' in spec: + WriteCopies(cmake_target_name, spec['copies'], extra_deps, + path_from_cmakelists_to_gyp, output) + + # Target and sources + srcs = spec.get('sources', []) + + # Gyp separates the sheep from the goats based on file extensions. + def partition(l, p): + return reduce(lambda x, e: x[not p(e)].append(e) or x, l, ([], [])) + compilable_srcs, other_srcs = partition(srcs, Compilable) + + # CMake gets upset when executable targets provide no sources. + if target_type == 'executable' and not compilable_srcs and not extra_sources: + print ('Executable %s has no complilable sources, treating as "none".' % + target_name ) + target_type = 'none' + + cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type) + if cmake_target_type is None: + print ('Target %s has unknown target type %s, skipping.' % + ( target_name, target_type ) ) + return + + other_srcs_name = None + if other_srcs: + other_srcs_name = cmake_target_name + '__other_srcs' + SetVariableList(output, other_srcs_name, + [NormjoinPath(path_from_cmakelists_to_gyp, src) for src in other_srcs]) + + # CMake is opposed to setting linker directories and considers the practice + # of setting linker directories dangerous. Instead, it favors the use of + # find_library and passing absolute paths to target_link_libraries. + # However, CMake does provide the command link_directories, which adds + # link directories to targets defined after it is called. + # As a result, link_directories must come before the target definition. + # CMake unfortunately has no means of removing entries from LINK_DIRECTORIES. + library_dirs = config.get('library_dirs') + if library_dirs is not None: + output.write('link_directories(') + for library_dir in library_dirs: + output.write(' ') + output.write(NormjoinPath(path_from_cmakelists_to_gyp, library_dir)) + output.write('\n') + output.write(')\n') + + output.write(cmake_target_type.command) + output.write('(') + output.write(cmake_target_name) + + if cmake_target_type.modifier is not None: + output.write(' ') + output.write(cmake_target_type.modifier) + + if other_srcs_name: + WriteVariable(output, other_srcs_name, ' ') + + output.write('\n') + + for src in compilable_srcs: + output.write(' ') + output.write(NormjoinPath(path_from_cmakelists_to_gyp, src)) + output.write('\n') + for extra_source in extra_sources: + output.write(' ') + src, _ = extra_source + output.write(NormjoinPath(path_from_cmakelists_to_gyp, src)) + output.write('\n') + + output.write(')\n') + + # Output name and location. + if target_type != 'none': + # Mark uncompiled sources as uncompiled. + if other_srcs_name: + output.write('set_source_files_properties(') + WriteVariable(output, other_srcs_name, '') + output.write(' PROPERTIES HEADER_FILE_ONLY "TRUE")\n') + + # Output directory + target_output_directory = spec.get('product_dir') + if target_output_directory is None: + if target_type in ('executable', 'loadable_module'): + target_output_directory = generator_default_variables['PRODUCT_DIR'] + elif target_type in ('shared_library'): + target_output_directory = '${builddir}/lib.${TOOLSET}' + elif spec.get('standalone_static_library', False): + target_output_directory = generator_default_variables['PRODUCT_DIR'] + else: + base_path = gyp.common.RelativePath(os.path.dirname(gyp_file), + options.toplevel_dir) + target_output_directory = '${obj}.${TOOLSET}' + target_output_directory = ( + os.path.join(target_output_directory, base_path)) + + cmake_target_output_directory = NormjoinPathForceCMakeSource( + path_from_cmakelists_to_gyp, + target_output_directory) + SetTargetProperty(output, + cmake_target_name, + cmake_target_type.property_modifier + '_OUTPUT_DIRECTORY', + cmake_target_output_directory) + + # Output name + default_product_prefix = '' + default_product_name = target_name + default_product_ext = '' + if target_type == 'static_library': + static_library_prefix = generator_default_variables['STATIC_LIB_PREFIX'] + default_product_name = RemovePrefix(default_product_name, + static_library_prefix) + default_product_prefix = static_library_prefix + default_product_ext = generator_default_variables['STATIC_LIB_SUFFIX'] + + elif target_type in ('loadable_module', 'shared_library'): + shared_library_prefix = generator_default_variables['SHARED_LIB_PREFIX'] + default_product_name = RemovePrefix(default_product_name, + shared_library_prefix) + default_product_prefix = shared_library_prefix + default_product_ext = generator_default_variables['SHARED_LIB_SUFFIX'] + + elif target_type != 'executable': + print ('ERROR: What output file should be generated?', + 'type', target_type, 'target', target_name) + + product_prefix = spec.get('product_prefix', default_product_prefix) + product_name = spec.get('product_name', default_product_name) + product_ext = spec.get('product_extension') + if product_ext: + product_ext = '.' + product_ext + else: + product_ext = default_product_ext + + SetTargetProperty(output, cmake_target_name, 'PREFIX', product_prefix) + SetTargetProperty(output, cmake_target_name, + cmake_target_type.property_modifier + '_OUTPUT_NAME', + product_name) + SetTargetProperty(output, cmake_target_name, 'SUFFIX', product_ext) + + # Make the output of this target referenceable as a source. + cmake_target_output_basename = product_prefix + product_name + product_ext + cmake_target_output = os.path.join(cmake_target_output_directory, + cmake_target_output_basename) + SetFileProperty(output, cmake_target_output, 'GENERATED', ['TRUE'], '') + + # Let CMake know if the 'all' target should depend on this target. + exclude_from_all = ('TRUE' if qualified_target not in all_qualified_targets + else 'FALSE') + SetTargetProperty(output, cmake_target_name, + 'EXCLUDE_FROM_ALL', exclude_from_all) + for extra_target_name in extra_deps: + SetTargetProperty(output, extra_target_name, + 'EXCLUDE_FROM_ALL', exclude_from_all) + + # Includes + includes = config.get('include_dirs') + if includes: + # This (target include directories) is what requires CMake 2.8.8 + includes_name = cmake_target_name + '__include_dirs' + SetVariableList(output, includes_name, + [NormjoinPathForceCMakeSource(path_from_cmakelists_to_gyp, include) + for include in includes]) + output.write('set_property(TARGET ') + output.write(cmake_target_name) + output.write(' APPEND PROPERTY INCLUDE_DIRECTORIES ') + WriteVariable(output, includes_name, '') + output.write(')\n') + + # Defines + defines = config.get('defines') + if defines is not None: + SetTargetProperty(output, + cmake_target_name, + 'COMPILE_DEFINITIONS', + defines, + ';') + + # Compile Flags - http://www.cmake.org/Bug/view.php?id=6493 + # CMake currently does not have target C and CXX flags. + # So, instead of doing... + + # cflags_c = config.get('cflags_c') + # if cflags_c is not None: + # SetTargetProperty(output, cmake_target_name, + # 'C_COMPILE_FLAGS', cflags_c, ' ') + + # cflags_cc = config.get('cflags_cc') + # if cflags_cc is not None: + # SetTargetProperty(output, cmake_target_name, + # 'CXX_COMPILE_FLAGS', cflags_cc, ' ') + + # Instead we must... + s_sources = [] + c_sources = [] + cxx_sources = [] + for src in srcs: + _, ext = os.path.splitext(src) + src_type = COMPILABLE_EXTENSIONS.get(ext, None) + + if src_type == 's': + s_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) + + if src_type == 'cc': + c_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) + + if src_type == 'cxx': + cxx_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) + + for extra_source in extra_sources: + src, real_source = extra_source + _, ext = os.path.splitext(real_source) + src_type = COMPILABLE_EXTENSIONS.get(ext, None) + + if src_type == 's': + s_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) + + if src_type == 'cc': + c_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) + + if src_type == 'cxx': + cxx_sources.append(NormjoinPath(path_from_cmakelists_to_gyp, src)) + + cflags = config.get('cflags', []) + cflags_c = config.get('cflags_c', []) + cflags_cxx = config.get('cflags_cc', []) + if c_sources and not (s_sources or cxx_sources): + flags = [] + flags.extend(cflags) + flags.extend(cflags_c) + SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ') + + elif cxx_sources and not (s_sources or c_sources): + flags = [] + flags.extend(cflags) + flags.extend(cflags_cxx) + SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ') + + else: + if s_sources and cflags: + SetFilesProperty(output, s_sources, 'COMPILE_FLAGS', cflags, ' ') + + if c_sources and (cflags or cflags_c): + flags = [] + flags.extend(cflags) + flags.extend(cflags_c) + SetFilesProperty(output, c_sources, 'COMPILE_FLAGS', flags, ' ') + + if cxx_sources and (cflags or cflags_cxx): + flags = [] + flags.extend(cflags) + flags.extend(cflags_cxx) + SetFilesProperty(output, cxx_sources, 'COMPILE_FLAGS', flags, ' ') + + # Have assembly link as c if there are no other files + if not c_sources and not cxx_sources and s_sources: + SetTargetProperty(output, cmake_target_name, 'LINKER_LANGUAGE', ['C']) + + # Linker flags + ldflags = config.get('ldflags') + if ldflags is not None: + SetTargetProperty(output, cmake_target_name, 'LINK_FLAGS', ldflags, ' ') + + # Note on Dependencies and Libraries: + # CMake wants to handle link order, resolving the link line up front. + # Gyp does not retain or enforce specifying enough information to do so. + # So do as other gyp generators and use --start-group and --end-group. + # Give CMake as little information as possible so that it doesn't mess it up. + + # Dependencies + rawDeps = spec.get('dependencies', []) + + static_deps = [] + shared_deps = [] + other_deps = [] + for rawDep in rawDeps: + dep_cmake_name = namer.CreateCMakeTargetName(rawDep) + dep_spec = target_dicts.get(rawDep, {}) + dep_target_type = dep_spec.get('type', None) + + if dep_target_type == 'static_library': + static_deps.append(dep_cmake_name) + elif dep_target_type == 'shared_library': + shared_deps.append(dep_cmake_name) + else: + other_deps.append(dep_cmake_name) + + # ensure all external dependencies are complete before internal dependencies + # extra_deps currently only depend on their own deps, so otherwise run early + if static_deps or shared_deps or other_deps: + for extra_dep in extra_deps: + output.write('add_dependencies(') + output.write(extra_dep) + output.write('\n') + for deps in (static_deps, shared_deps, other_deps): + for dep in gyp.common.uniquer(deps): + output.write(' ') + output.write(dep) + output.write('\n') + output.write(')\n') + + linkable = target_type in ('executable', 'loadable_module', 'shared_library') + other_deps.extend(extra_deps) + if other_deps or (not linkable and (static_deps or shared_deps)): + output.write('add_dependencies(') + output.write(cmake_target_name) + output.write('\n') + for dep in gyp.common.uniquer(other_deps): + output.write(' ') + output.write(dep) + output.write('\n') + if not linkable: + for deps in (static_deps, shared_deps): + for lib_dep in gyp.common.uniquer(deps): + output.write(' ') + output.write(lib_dep) + output.write('\n') + output.write(')\n') + + # Libraries + if linkable: + external_libs = [lib for lib in spec.get('libraries', []) if len(lib) > 0] + if external_libs or static_deps or shared_deps: + output.write('target_link_libraries(') + output.write(cmake_target_name) + output.write('\n') + if static_deps: + write_group = circular_libs and len(static_deps) > 1 + if write_group: + output.write('-Wl,--start-group\n') + for dep in gyp.common.uniquer(static_deps): + output.write(' ') + output.write(dep) + output.write('\n') + if write_group: + output.write('-Wl,--end-group\n') + if shared_deps: + for dep in gyp.common.uniquer(shared_deps): + output.write(' ') + output.write(dep) + output.write('\n') + if external_libs: + for lib in gyp.common.uniquer(external_libs): + output.write(' ') + output.write(lib) + output.write('\n') + + output.write(')\n') + + UnsetVariable(output, 'TOOLSET') + UnsetVariable(output, 'TARGET') + + +def GenerateOutputForConfig(target_list, target_dicts, data, + params, config_to_use): + options = params['options'] + generator_flags = params['generator_flags'] + + # generator_dir: relative path from pwd to where make puts build files. + # Makes migrating from make to cmake easier, cmake doesn't put anything here. + # Each Gyp configuration creates a different CMakeLists.txt file + # to avoid incompatibilities between Gyp and CMake configurations. + generator_dir = os.path.relpath(options.generator_output or '.') + + # output_dir: relative path from generator_dir to the build directory. + output_dir = generator_flags.get('output_dir', 'out') + + # build_dir: relative path from source root to our output files. + # e.g. "out/Debug" + build_dir = os.path.normpath(os.path.join(generator_dir, + output_dir, + config_to_use)) + + toplevel_build = os.path.join(options.toplevel_dir, build_dir) + + output_file = os.path.join(toplevel_build, 'CMakeLists.txt') + gyp.common.EnsureDirExists(output_file) + + output = open(output_file, 'w') + output.write('cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)\n') + output.write('cmake_policy(VERSION 2.8.8)\n') + + _, project_target, _ = gyp.common.ParseQualifiedTarget(target_list[-1]) + output.write('project(') + output.write(project_target) + output.write(')\n') + + SetVariable(output, 'configuration', config_to_use) + + # The following appears to be as-yet undocumented. + # http://public.kitware.com/Bug/view.php?id=8392 + output.write('enable_language(ASM)\n') + # ASM-ATT does not support .S files. + # output.write('enable_language(ASM-ATT)\n') + + SetVariable(output, 'builddir', '${CMAKE_BINARY_DIR}') + SetVariable(output, 'obj', '${builddir}/obj') + output.write('\n') + + # TODO: Undocumented/unsupported (the CMake Java generator depends on it). + # CMake by default names the object resulting from foo.c to be foo.c.o. + # Gyp traditionally names the object resulting from foo.c foo.o. + # This should be irrelevant, but some targets extract .o files from .a + # and depend on the name of the extracted .o files. + output.write('set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)\n') + output.write('set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)\n') + output.write('\n') + + namer = CMakeNamer(target_list) + + # The list of targets upon which the 'all' target should depend. + # CMake has it's own implicit 'all' target, one is not created explicitly. + all_qualified_targets = set() + for build_file in params['build_files']: + for qualified_target in gyp.common.AllTargets(target_list, + target_dicts, + os.path.normpath(build_file)): + all_qualified_targets.add(qualified_target) + + for qualified_target in target_list: + WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, + options, generator_flags, all_qualified_targets, output) + + output.close() + + +def PerformBuild(data, configurations, params): + options = params['options'] + generator_flags = params['generator_flags'] + + # generator_dir: relative path from pwd to where make puts build files. + # Makes migrating from make to cmake easier, cmake doesn't put anything here. + generator_dir = os.path.relpath(options.generator_output or '.') + + # output_dir: relative path from generator_dir to the build directory. + output_dir = generator_flags.get('output_dir', 'out') + + for config_name in configurations: + # build_dir: relative path from source root to our output files. + # e.g. "out/Debug" + build_dir = os.path.normpath(os.path.join(generator_dir, + output_dir, + config_name)) + arguments = ['cmake', '-G', 'Ninja'] + print 'Generating [%s]: %s' % (config_name, arguments) + subprocess.check_call(arguments, cwd=build_dir) + + arguments = ['ninja', '-C', build_dir] + print 'Building [%s]: %s' % (config_name, arguments) + subprocess.check_call(arguments) + + +def CallGenerateOutputForConfig(arglist): + # Ignore the interrupt signal so that the parent process catches it and + # kills all multiprocessing children. + signal.signal(signal.SIGINT, signal.SIG_IGN) + + target_list, target_dicts, data, params, config_name = arglist + GenerateOutputForConfig(target_list, target_dicts, data, params, config_name) + + +def GenerateOutput(target_list, target_dicts, data, params): + user_config = params.get('generator_flags', {}).get('config', None) + if user_config: + GenerateOutputForConfig(target_list, target_dicts, data, + params, user_config) + else: + config_names = target_dicts[target_list[0]]['configurations'].keys() + if params['parallel']: + try: + pool = multiprocessing.Pool(len(config_names)) + arglists = [] + for config_name in config_names: + arglists.append((target_list, target_dicts, data, + params, config_name)) + pool.map(CallGenerateOutputForConfig, arglists) + except KeyboardInterrupt, e: + pool.terminate() + raise e + else: + for config_name in config_names: + GenerateOutputForConfig(target_list, target_dicts, data, + params, config_name) diff --git a/deps/gyp/pylib/gyp/generator/dump_dependency_json.py b/deps/gyp/pylib/gyp/generator/dump_dependency_json.py new file mode 100644 index 000000000..927ba6eba --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/dump_dependency_json.py @@ -0,0 +1,81 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import collections +import os +import gyp +import gyp.common +import gyp.msvs_emulation +import json +import sys + +generator_supports_multiple_toolsets = True + +generator_wants_static_library_dependencies_adjusted = False + +generator_default_variables = { +} +for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR', + 'LIB_DIR', 'SHARED_LIB_DIR']: + # Some gyp steps fail if these are empty(!). + generator_default_variables[dirname] = 'dir' +for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME', + 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT', + 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX', + 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX', + 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX', + 'CONFIGURATION_NAME']: + generator_default_variables[unused] = '' + + +def CalculateVariables(default_variables, params): + generator_flags = params.get('generator_flags', {}) + for key, val in generator_flags.items(): + default_variables.setdefault(key, val) + default_variables.setdefault('OS', gyp.common.GetFlavor(params)) + + flavor = gyp.common.GetFlavor(params) + if flavor =='win': + # Copy additional generator configuration data from VS, which is shared + # by the Windows Ninja generator. + import gyp.generator.msvs as msvs_generator + generator_additional_non_configuration_keys = getattr(msvs_generator, + 'generator_additional_non_configuration_keys', []) + generator_additional_path_sections = getattr(msvs_generator, + 'generator_additional_path_sections', []) + + gyp.msvs_emulation.CalculateCommonVariables(default_variables, params) + + +def CalculateGeneratorInputInfo(params): + """Calculate the generator specific info that gets fed to input (called by + gyp).""" + generator_flags = params.get('generator_flags', {}) + if generator_flags.get('adjust_static_libraries', False): + global generator_wants_static_library_dependencies_adjusted + generator_wants_static_library_dependencies_adjusted = True + + +def GenerateOutput(target_list, target_dicts, data, params): + # Map of target -> list of targets it depends on. + edges = {} + + # Queue of targets to visit. + targets_to_visit = target_list[:] + + while len(targets_to_visit) > 0: + target = targets_to_visit.pop() + if target in edges: + continue + edges[target] = [] + + for dep in target_dicts[target].get('dependencies', []): + edges[target].append(dep) + targets_to_visit.append(dep) + + filename = 'dump.json' + f = open(filename, 'w') + json.dump(edges, f) + f.close() + print 'Wrote json to %s.' % filename diff --git a/deps/gyp/pylib/gyp/generator/eclipse.py b/deps/gyp/pylib/gyp/generator/eclipse.py new file mode 100644 index 000000000..718eb5d3d --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/eclipse.py @@ -0,0 +1,334 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""GYP backend that generates Eclipse CDT settings files. + +This backend DOES NOT generate Eclipse CDT projects. Instead, it generates XML +files that can be imported into an Eclipse CDT project. The XML file contains a +list of include paths and symbols (i.e. defines). + +Because a full .cproject definition is not created by this generator, it's not +possible to properly define the include dirs and symbols for each file +individually. Instead, one set of includes/symbols is generated for the entire +project. This works fairly well (and is a vast improvement in general), but may +still result in a few indexer issues here and there. + +This generator has no automated tests, so expect it to be broken. +""" + +from xml.sax.saxutils import escape +import os.path +import subprocess +import gyp +import gyp.common +import gyp.msvs_emulation +import shlex + +generator_wants_static_library_dependencies_adjusted = False + +generator_default_variables = { +} + +for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']: + # Some gyp steps fail if these are empty(!). + generator_default_variables[dirname] = 'dir' + +for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME', + 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT', + 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX', + 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX', + 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX', + 'CONFIGURATION_NAME']: + generator_default_variables[unused] = '' + +# Include dirs will occasionally use the SHARED_INTERMEDIATE_DIR variable as +# part of the path when dealing with generated headers. This value will be +# replaced dynamically for each configuration. +generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \ + '$SHARED_INTERMEDIATE_DIR' + + +def CalculateVariables(default_variables, params): + generator_flags = params.get('generator_flags', {}) + for key, val in generator_flags.items(): + default_variables.setdefault(key, val) + flavor = gyp.common.GetFlavor(params) + default_variables.setdefault('OS', flavor) + if flavor == 'win': + # Copy additional generator configuration data from VS, which is shared + # by the Eclipse generator. + import gyp.generator.msvs as msvs_generator + generator_additional_non_configuration_keys = getattr(msvs_generator, + 'generator_additional_non_configuration_keys', []) + generator_additional_path_sections = getattr(msvs_generator, + 'generator_additional_path_sections', []) + + gyp.msvs_emulation.CalculateCommonVariables(default_variables, params) + + +def CalculateGeneratorInputInfo(params): + """Calculate the generator specific info that gets fed to input (called by + gyp).""" + generator_flags = params.get('generator_flags', {}) + if generator_flags.get('adjust_static_libraries', False): + global generator_wants_static_library_dependencies_adjusted + generator_wants_static_library_dependencies_adjusted = True + + +def GetAllIncludeDirectories(target_list, target_dicts, + shared_intermediate_dirs, config_name, params, + compiler_path): + """Calculate the set of include directories to be used. + + Returns: + A list including all the include_dir's specified for every target followed + by any include directories that were added as cflag compiler options. + """ + + gyp_includes_set = set() + compiler_includes_list = [] + + # Find compiler's default include dirs. + if compiler_path: + command = shlex.split(compiler_path) + command.extend(['-E', '-xc++', '-v', '-']) + proc = subprocess.Popen(args=command, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output = proc.communicate()[1] + # Extract the list of include dirs from the output, which has this format: + # ... + # #include "..." search starts here: + # #include <...> search starts here: + # /usr/include/c++/4.6 + # /usr/local/include + # End of search list. + # ... + in_include_list = False + for line in output.splitlines(): + if line.startswith('#include'): + in_include_list = True + continue + if line.startswith('End of search list.'): + break + if in_include_list: + include_dir = line.strip() + if include_dir not in compiler_includes_list: + compiler_includes_list.append(include_dir) + + flavor = gyp.common.GetFlavor(params) + if flavor == 'win': + generator_flags = params.get('generator_flags', {}) + for target_name in target_list: + target = target_dicts[target_name] + if config_name in target['configurations']: + config = target['configurations'][config_name] + + # Look for any include dirs that were explicitly added via cflags. This + # may be done in gyp files to force certain includes to come at the end. + # TODO(jgreenwald): Change the gyp files to not abuse cflags for this, and + # remove this. + if flavor == 'win': + msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags) + cflags = msvs_settings.GetCflags(config_name) + else: + cflags = config['cflags'] + for cflag in cflags: + if cflag.startswith('-I'): + include_dir = cflag[2:] + if include_dir not in compiler_includes_list: + compiler_includes_list.append(include_dir) + + # Find standard gyp include dirs. + if config.has_key('include_dirs'): + include_dirs = config['include_dirs'] + for shared_intermediate_dir in shared_intermediate_dirs: + for include_dir in include_dirs: + include_dir = include_dir.replace('$SHARED_INTERMEDIATE_DIR', + shared_intermediate_dir) + if not os.path.isabs(include_dir): + base_dir = os.path.dirname(target_name) + + include_dir = base_dir + '/' + include_dir + include_dir = os.path.abspath(include_dir) + + gyp_includes_set.add(include_dir) + + # Generate a list that has all the include dirs. + all_includes_list = list(gyp_includes_set) + all_includes_list.sort() + for compiler_include in compiler_includes_list: + if not compiler_include in gyp_includes_set: + all_includes_list.append(compiler_include) + + # All done. + return all_includes_list + + +def GetCompilerPath(target_list, data, options): + """Determine a command that can be used to invoke the compiler. + + Returns: + If this is a gyp project that has explicit make settings, try to determine + the compiler from that. Otherwise, see if a compiler was specified via the + CC_target environment variable. + """ + # First, see if the compiler is configured in make's settings. + build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) + make_global_settings_dict = data[build_file].get('make_global_settings', {}) + for key, value in make_global_settings_dict: + if key in ['CC', 'CXX']: + return os.path.join(options.toplevel_dir, value) + + # Check to see if the compiler was specified as an environment variable. + for key in ['CC_target', 'CC', 'CXX']: + compiler = os.environ.get(key) + if compiler: + return compiler + + return 'gcc' + + +def GetAllDefines(target_list, target_dicts, data, config_name, params, + compiler_path): + """Calculate the defines for a project. + + Returns: + A dict that includes explict defines declared in gyp files along with all of + the default defines that the compiler uses. + """ + + # Get defines declared in the gyp files. + all_defines = {} + flavor = gyp.common.GetFlavor(params) + if flavor == 'win': + generator_flags = params.get('generator_flags', {}) + for target_name in target_list: + target = target_dicts[target_name] + + if flavor == 'win': + msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags) + extra_defines = msvs_settings.GetComputedDefines(config_name) + else: + extra_defines = [] + if config_name in target['configurations']: + config = target['configurations'][config_name] + target_defines = config['defines'] + else: + target_defines = [] + for define in target_defines + extra_defines: + split_define = define.split('=', 1) + if len(split_define) == 1: + split_define.append('1') + if split_define[0].strip() in all_defines: + # Already defined + continue + all_defines[split_define[0].strip()] = split_define[1].strip() + # Get default compiler defines (if possible). + if flavor == 'win': + return all_defines # Default defines already processed in the loop above. + if compiler_path: + command = shlex.split(compiler_path) + command.extend(['-E', '-dM', '-']) + cpp_proc = subprocess.Popen(args=command, cwd='.', + stdin=subprocess.PIPE, stdout=subprocess.PIPE) + cpp_output = cpp_proc.communicate()[0] + cpp_lines = cpp_output.split('\n') + for cpp_line in cpp_lines: + if not cpp_line.strip(): + continue + cpp_line_parts = cpp_line.split(' ', 2) + key = cpp_line_parts[1] + if len(cpp_line_parts) >= 3: + val = cpp_line_parts[2] + else: + val = '1' + all_defines[key] = val + + return all_defines + + +def WriteIncludePaths(out, eclipse_langs, include_dirs): + """Write the includes section of a CDT settings export file.""" + + out.write('
\n') + out.write(' \n') + for lang in eclipse_langs: + out.write(' \n' % lang) + for include_dir in include_dirs: + out.write(' %s\n' % + include_dir) + out.write(' \n') + out.write('
\n') + + +def WriteMacros(out, eclipse_langs, defines): + """Write the macros section of a CDT settings export file.""" + + out.write('
\n') + out.write(' \n') + for lang in eclipse_langs: + out.write(' \n' % lang) + for key in sorted(defines.iterkeys()): + out.write(' %s%s\n' % + (escape(key), escape(defines[key]))) + out.write(' \n') + out.write('
\n') + + +def GenerateOutputForConfig(target_list, target_dicts, data, params, + config_name): + options = params['options'] + generator_flags = params.get('generator_flags', {}) + + # build_dir: relative path from source root to our output files. + # e.g. "out/Debug" + build_dir = os.path.join(generator_flags.get('output_dir', 'out'), + config_name) + + toplevel_build = os.path.join(options.toplevel_dir, build_dir) + # Ninja uses out/Debug/gen while make uses out/Debug/obj/gen as the + # SHARED_INTERMEDIATE_DIR. Include both possible locations. + shared_intermediate_dirs = [os.path.join(toplevel_build, 'obj', 'gen'), + os.path.join(toplevel_build, 'gen')] + + out_name = os.path.join(toplevel_build, 'eclipse-cdt-settings.xml') + gyp.common.EnsureDirExists(out_name) + out = open(out_name, 'w') + + out.write('\n') + out.write('\n') + + eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File', + 'GNU C++', 'GNU C', 'Assembly'] + compiler_path = GetCompilerPath(target_list, data, options) + include_dirs = GetAllIncludeDirectories(target_list, target_dicts, + shared_intermediate_dirs, config_name, + params, compiler_path) + WriteIncludePaths(out, eclipse_langs, include_dirs) + defines = GetAllDefines(target_list, target_dicts, data, config_name, params, + compiler_path) + WriteMacros(out, eclipse_langs, defines) + + out.write('\n') + out.close() + + +def GenerateOutput(target_list, target_dicts, data, params): + """Generate an XML settings file that can be imported into a CDT project.""" + + if params['options'].generator_output: + raise NotImplementedError, "--generator_output not implemented for eclipse" + + user_config = params.get('generator_flags', {}).get('config', None) + if user_config: + GenerateOutputForConfig(target_list, target_dicts, data, params, + user_config) + else: + config_names = target_dicts[target_list[0]]['configurations'].keys() + for config_name in config_names: + GenerateOutputForConfig(target_list, target_dicts, data, params, + config_name) + diff --git a/deps/gyp/pylib/gyp/generator/gypd.py b/deps/gyp/pylib/gyp/generator/gypd.py new file mode 100644 index 000000000..22ef57f84 --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/gypd.py @@ -0,0 +1,87 @@ +# Copyright (c) 2011 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""gypd output module + +This module produces gyp input as its output. Output files are given the +.gypd extension to avoid overwriting the .gyp files that they are generated +from. Internal references to .gyp files (such as those found in +"dependencies" sections) are not adjusted to point to .gypd files instead; +unlike other paths, which are relative to the .gyp or .gypd file, such paths +are relative to the directory from which gyp was run to create the .gypd file. + +This generator module is intended to be a sample and a debugging aid, hence +the "d" for "debug" in .gypd. It is useful to inspect the results of the +various merges, expansions, and conditional evaluations performed by gyp +and to see a representation of what would be fed to a generator module. + +It's not advisable to rename .gypd files produced by this module to .gyp, +because they will have all merges, expansions, and evaluations already +performed and the relevant constructs not present in the output; paths to +dependencies may be wrong; and various sections that do not belong in .gyp +files such as such as "included_files" and "*_excluded" will be present. +Output will also be stripped of comments. This is not intended to be a +general-purpose gyp pretty-printer; for that, you probably just want to +run "pprint.pprint(eval(open('source.gyp').read()))", which will still strip +comments but won't do all of the other things done to this module's output. + +The specific formatting of the output generated by this module is subject +to change. +""" + + +import gyp.common +import errno +import os +import pprint + + +# These variables should just be spit back out as variable references. +_generator_identity_variables = [ + 'EXECUTABLE_PREFIX', + 'EXECUTABLE_SUFFIX', + 'INTERMEDIATE_DIR', + 'PRODUCT_DIR', + 'RULE_INPUT_ROOT', + 'RULE_INPUT_DIRNAME', + 'RULE_INPUT_EXT', + 'RULE_INPUT_NAME', + 'RULE_INPUT_PATH', + 'SHARED_INTERMEDIATE_DIR', +] + +# gypd doesn't define a default value for OS like many other generator +# modules. Specify "-D OS=whatever" on the command line to provide a value. +generator_default_variables = { +} + +# gypd supports multiple toolsets +generator_supports_multiple_toolsets = True + +# TODO(mark): This always uses <, which isn't right. The input module should +# notify the generator to tell it which phase it is operating in, and this +# module should use < for the early phase and then switch to > for the late +# phase. Bonus points for carrying @ back into the output too. +for v in _generator_identity_variables: + generator_default_variables[v] = '<(%s)' % v + + +def GenerateOutput(target_list, target_dicts, data, params): + output_files = {} + for qualified_target in target_list: + [input_file, target] = \ + gyp.common.ParseQualifiedTarget(qualified_target)[0:2] + + if input_file[-4:] != '.gyp': + continue + input_file_stem = input_file[:-4] + output_file = input_file_stem + params['options'].suffix + '.gypd' + + if not output_file in output_files: + output_files[output_file] = input_file + + for output_file, input_file in output_files.iteritems(): + output = open(output_file, 'w') + pprint.pprint(data[input_file], output) + output.close() diff --git a/deps/gyp/pylib/gyp/generator/gypsh.py b/deps/gyp/pylib/gyp/generator/gypsh.py new file mode 100644 index 000000000..bd405f43a --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/gypsh.py @@ -0,0 +1,56 @@ +# Copyright (c) 2011 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""gypsh output module + +gypsh is a GYP shell. It's not really a generator per se. All it does is +fire up an interactive Python session with a few local variables set to the +variables passed to the generator. Like gypd, it's intended as a debugging +aid, to facilitate the exploration of .gyp structures after being processed +by the input module. + +The expected usage is "gyp -f gypsh -D OS=desired_os". +""" + + +import code +import sys + + +# All of this stuff about generator variables was lovingly ripped from gypd.py. +# That module has a much better description of what's going on and why. +_generator_identity_variables = [ + 'EXECUTABLE_PREFIX', + 'EXECUTABLE_SUFFIX', + 'INTERMEDIATE_DIR', + 'PRODUCT_DIR', + 'RULE_INPUT_ROOT', + 'RULE_INPUT_DIRNAME', + 'RULE_INPUT_EXT', + 'RULE_INPUT_NAME', + 'RULE_INPUT_PATH', + 'SHARED_INTERMEDIATE_DIR', +] + +generator_default_variables = { +} + +for v in _generator_identity_variables: + generator_default_variables[v] = '<(%s)' % v + + +def GenerateOutput(target_list, target_dicts, data, params): + locals = { + 'target_list': target_list, + 'target_dicts': target_dicts, + 'data': data, + } + + # Use a banner that looks like the stock Python one and like what + # code.interact uses by default, but tack on something to indicate what + # locals are available, and identify gypsh. + banner='Python %s on %s\nlocals.keys() = %s\ngypsh' % \ + (sys.version, sys.platform, repr(sorted(locals.keys()))) + + code.interact(banner, local=locals) diff --git a/deps/gyp/pylib/gyp/generator/make.py b/deps/gyp/pylib/gyp/generator/make.py new file mode 100644 index 000000000..7a8adb585 --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/make.py @@ -0,0 +1,2182 @@ +# Copyright (c) 2013 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Notes: +# +# This is all roughly based on the Makefile system used by the Linux +# kernel, but is a non-recursive make -- we put the entire dependency +# graph in front of make and let it figure it out. +# +# The code below generates a separate .mk file for each target, but +# all are sourced by the top-level Makefile. This means that all +# variables in .mk-files clobber one another. Be careful to use := +# where appropriate for immediate evaluation, and similarly to watch +# that you're not relying on a variable value to last beween different +# .mk files. +# +# TODOs: +# +# Global settings and utility functions are currently stuffed in the +# toplevel Makefile. It may make sense to generate some .mk files on +# the side to keep the the files readable. + +import os +import re +import sys +import subprocess +import gyp +import gyp.common +import gyp.xcode_emulation +from gyp.common import GetEnvironFallback + +generator_default_variables = { + 'EXECUTABLE_PREFIX': '', + 'EXECUTABLE_SUFFIX': '', + 'STATIC_LIB_PREFIX': 'lib', + 'SHARED_LIB_PREFIX': 'lib', + 'STATIC_LIB_SUFFIX': '.a', + 'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/$(TARGET)/geni', + 'SHARED_INTERMEDIATE_DIR': '$(obj)/gen', + 'PRODUCT_DIR': '$(builddir)', + 'RULE_INPUT_ROOT': '%(INPUT_ROOT)s', # This gets expanded by Python. + 'RULE_INPUT_DIRNAME': '%(INPUT_DIRNAME)s', # This gets expanded by Python. + 'RULE_INPUT_PATH': '$(abspath $<)', + 'RULE_INPUT_EXT': '$(suffix $<)', + 'RULE_INPUT_NAME': '$(notdir $<)', + 'CONFIGURATION_NAME': '$(BUILDTYPE)', +} + +# Make supports multiple toolsets +generator_supports_multiple_toolsets = True + +# Request sorted dependencies in the order from dependents to dependencies. +generator_wants_sorted_dependencies = False + +# Placates pylint. +generator_additional_non_configuration_keys = [] +generator_additional_path_sections = [] +generator_extra_sources_for_rules = [] +generator_filelist_paths = None + + +def CalculateVariables(default_variables, params): + """Calculate additional variables for use in the build (called by gyp).""" + flavor = gyp.common.GetFlavor(params) + if flavor == 'mac': + default_variables.setdefault('OS', 'mac') + default_variables.setdefault('SHARED_LIB_SUFFIX', '.dylib') + default_variables.setdefault('SHARED_LIB_DIR', + generator_default_variables['PRODUCT_DIR']) + default_variables.setdefault('LIB_DIR', + generator_default_variables['PRODUCT_DIR']) + + # Copy additional generator configuration data from Xcode, which is shared + # by the Mac Make generator. + import gyp.generator.xcode as xcode_generator + global generator_additional_non_configuration_keys + generator_additional_non_configuration_keys = getattr(xcode_generator, + 'generator_additional_non_configuration_keys', []) + global generator_additional_path_sections + generator_additional_path_sections = getattr(xcode_generator, + 'generator_additional_path_sections', []) + global generator_extra_sources_for_rules + generator_extra_sources_for_rules = getattr(xcode_generator, + 'generator_extra_sources_for_rules', []) + COMPILABLE_EXTENSIONS.update({'.m': 'objc', '.mm' : 'objcxx'}) + else: + operating_system = flavor + if flavor == 'android': + operating_system = 'linux' # Keep this legacy behavior for now. + default_variables.setdefault('OS', operating_system) + default_variables.setdefault('SHARED_LIB_SUFFIX', '.so') + default_variables.setdefault('SHARED_LIB_DIR','$(builddir)/lib.$(TOOLSET)') + default_variables.setdefault('LIB_DIR', '$(obj).$(TOOLSET)') + + +def CalculateGeneratorInputInfo(params): + """Calculate the generator specific info that gets fed to input (called by + gyp).""" + generator_flags = params.get('generator_flags', {}) + android_ndk_version = generator_flags.get('android_ndk_version', None) + # Android NDK requires a strict link order. + if android_ndk_version: + global generator_wants_sorted_dependencies + generator_wants_sorted_dependencies = True + + output_dir = params['options'].generator_output or \ + params['options'].toplevel_dir + builddir_name = generator_flags.get('output_dir', 'out') + qualified_out_dir = os.path.normpath(os.path.join( + output_dir, builddir_name, 'gypfiles')) + + global generator_filelist_paths + generator_filelist_paths = { + 'toplevel': params['options'].toplevel_dir, + 'qualified_out_dir': qualified_out_dir, + } + + +# The .d checking code below uses these functions: +# wildcard, sort, foreach, shell, wordlist +# wildcard can handle spaces, the rest can't. +# Since I could find no way to make foreach work with spaces in filenames +# correctly, the .d files have spaces replaced with another character. The .d +# file for +# Chromium\ Framework.framework/foo +# is for example +# out/Release/.deps/out/Release/Chromium?Framework.framework/foo +# This is the replacement character. +SPACE_REPLACEMENT = '?' + + +LINK_COMMANDS_LINUX = """\ +quiet_cmd_alink = AR($(TOOLSET)) $@ +cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) + +quiet_cmd_alink_thin = AR($(TOOLSET)) $@ +cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^) + +# Due to circular dependencies between libraries :(, we wrap the +# special "figure out circular dependencies" flags around the entire +# input list during linking. +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) -Wl,--start-group $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) -Wl,--end-group $(LIBS) + +# We support two kinds of shared objects (.so): +# 1) shared_library, which is just bundling together many dependent libraries +# into a link line. +# 2) loadable_module, which is generating a module intended for dlopen(). +# +# They differ only slightly: +# In the former case, we want to package all dependent code into the .so. +# In the latter case, we want to package just the API exposed by the +# outermost module. +# This means shared_library uses --whole-archive, while loadable_module doesn't. +# (Note that --whole-archive is incompatible with the --start-group used in +# normal linking.) + +# Other shared-object link notes: +# - Set SONAME to the library filename so our binaries don't reference +# the local, absolute paths used on the link command-line. +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) +""" + +LINK_COMMANDS_MAC = """\ +quiet_cmd_alink = LIBTOOL-STATIC $@ +cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) + +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) +""" + +LINK_COMMANDS_ANDROID = """\ +quiet_cmd_alink = AR($(TOOLSET)) $@ +cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) + +quiet_cmd_alink_thin = AR($(TOOLSET)) $@ +cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^) + +# Due to circular dependencies between libraries :(, we wrap the +# special "figure out circular dependencies" flags around the entire +# input list during linking. +quiet_cmd_link = LINK($(TOOLSET)) $@ +quiet_cmd_link_host = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS) +cmd_link_host = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) + +# Other shared-object link notes: +# - Set SONAME to the library filename so our binaries don't reference +# the local, absolute paths used on the link command-line. +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) +quiet_cmd_solink_module_host = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module_host = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) +""" + + +LINK_COMMANDS_AIX = """\ +quiet_cmd_alink = AR($(TOOLSET)) $@ +cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) + +quiet_cmd_alink_thin = AR($(TOOLSET)) $@ +cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) + +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) +""" + + +# Header of toplevel Makefile. +# This should go into the build tree, but it's easier to keep it here for now. +SHARED_HEADER = ("""\ +# We borrow heavily from the kernel build setup, though we are simpler since +# we don't have Kconfig tweaking settings on us. + +# The implicit make rules have it looking for RCS files, among other things. +# We instead explicitly write all the rules we care about. +# It's even quicker (saves ~200ms) to pass -r on the command line. +MAKEFLAGS=-r + +# The source directory tree. +srcdir := %(srcdir)s +abs_srcdir := $(abspath $(srcdir)) + +# The name of the builddir. +builddir_name ?= %(builddir)s + +# The V=1 flag on command line makes us verbosely print command lines. +ifdef V + quiet= +else + quiet=quiet_ +endif + +# Specify BUILDTYPE=Release on the command line for a release build. +BUILDTYPE ?= %(default_configuration)s + +# Directory all our build output goes into. +# Note that this must be two directories beneath src/ for unit tests to pass, +# as they reach into the src/ directory for data with relative paths. +builddir ?= $(builddir_name)/$(BUILDTYPE) +abs_builddir := $(abspath $(builddir)) +depsdir := $(builddir)/.deps + +# Object output directory. +obj := $(builddir)/obj +abs_obj := $(abspath $(obj)) + +# We build up a list of every single one of the targets so we can slurp in the +# generated dependency rule Makefiles in one pass. +all_deps := + +%(make_global_settings)s + +CC.target ?= %(CC.target)s +CFLAGS.target ?= $(CFLAGS) +CXX.target ?= %(CXX.target)s +CXXFLAGS.target ?= $(CXXFLAGS) +LINK.target ?= %(LINK.target)s +LDFLAGS.target ?= $(LDFLAGS) +AR.target ?= $(AR) + +# C++ apps need to be linked with g++. +# +# Note: flock is used to seralize linking. Linking is a memory-intensive +# process so running parallel links can often lead to thrashing. To disable +# the serialization, override LINK via an envrionment variable as follows: +# +# export LINK=g++ +# +# This will allow make to invoke N linker processes as specified in -jN. +LINK ?= %(flock)s $(builddir)/linker.lock $(CXX.target) + +# TODO(evan): move all cross-compilation logic to gyp-time so we don't need +# to replicate this environment fallback in make as well. +CC.host ?= %(CC.host)s +CFLAGS.host ?= +CXX.host ?= %(CXX.host)s +CXXFLAGS.host ?= +LINK.host ?= %(LINK.host)s +LDFLAGS.host ?= +AR.host ?= %(AR.host)s + +# Define a dir function that can handle spaces. +# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions +# "leading spaces cannot appear in the text of the first argument as written. +# These characters can be put into the argument value by variable substitution." +empty := +space := $(empty) $(empty) + +# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces +replace_spaces = $(subst $(space),""" + SPACE_REPLACEMENT + """,$1) +unreplace_spaces = $(subst """ + SPACE_REPLACEMENT + """,$(space),$1) +dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1))) + +# Flags to make gcc output dependency info. Note that you need to be +# careful here to use the flags that ccache and distcc can understand. +# We write to a dep file on the side first and then rename at the end +# so we can't end up with a broken dep file. +depfile = $(depsdir)/$(call replace_spaces,$@).d +DEPFLAGS = -MMD -MF $(depfile).raw + +# We have to fixup the deps output in a few ways. +# (1) the file output should mention the proper .o file. +# ccache or distcc lose the path to the target, so we convert a rule of +# the form: +# foobar.o: DEP1 DEP2 +# into +# path/to/foobar.o: DEP1 DEP2 +# (2) we want missing files not to cause us to fail to build. +# We want to rewrite +# foobar.o: DEP1 DEP2 \\ +# DEP3 +# to +# DEP1: +# DEP2: +# DEP3: +# so if the files are missing, they're just considered phony rules. +# We have to do some pretty insane escaping to get those backslashes +# and dollar signs past make, the shell, and sed at the same time. +# Doesn't work with spaces, but that's fine: .d files have spaces in +# their names replaced with other characters.""" +r""" +define fixup_dep +# The depfile may not exist if the input file didn't have any #includes. +touch $(depfile).raw +# Fixup path as in (1). +sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef +""" +""" +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +%(extra_commands)s +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@") + +%(link_commands)s +""" + +r""" +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%%s\n' '$(call escape_quotes,$(1))' +""" +""" +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \\ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain """ + SPACE_REPLACEMENT + \ + """ instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\\ + for p in $(POSTBUILDS); do\\ + eval $$p;\\ + E=$$?;\\ + if [ $$E -ne 0 ]; then\\ + break;\\ + fi;\\ + done;\\ + if [ $$E -ne 0 ]; then\\ + rm -rf "$@";\\ + exit $$E;\\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains """ + \ + SPACE_REPLACEMENT + """ for +# spaces already and dirx strips the """ + SPACE_REPLACEMENT + \ + """ characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word %(flock_index)d,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "%(default_target)s" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: %(default_target)s +%(default_target)s: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +""") + +SHARED_HEADER_MAC_COMMANDS = """ +quiet_cmd_objc = CXX($(TOOLSET)) $@ +cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< + +quiet_cmd_objcxx = CXX($(TOOLSET)) $@ +cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# Commands for precompiled header files. +quiet_cmd_pch_c = CXX($(TOOLSET)) $@ +cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ +cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_m = CXX($(TOOLSET)) $@ +cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< +quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ +cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# gyp-mac-tool is written next to the root Makefile by gyp. +# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd +# already. +quiet_cmd_mac_tool = MACTOOL $(4) $< +cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@" + +quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ +cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) + +quiet_cmd_infoplist = INFOPLIST $@ +cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" +""" + + +def WriteRootHeaderSuffixRules(writer): + extensions = sorted(COMPILABLE_EXTENSIONS.keys(), key=str.lower) + + writer.write('# Suffix rules, putting all outputs into $(obj).\n') + for ext in extensions: + writer.write('$(obj).$(TOOLSET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD\n' % ext) + writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext]) + + writer.write('\n# Try building from generated source, too.\n') + for ext in extensions: + writer.write( + '$(obj).$(TOOLSET)/%%.o: $(obj).$(TOOLSET)/%%%s FORCE_DO_CMD\n' % ext) + writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext]) + writer.write('\n') + for ext in extensions: + writer.write('$(obj).$(TOOLSET)/%%.o: $(obj)/%%%s FORCE_DO_CMD\n' % ext) + writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext]) + writer.write('\n') + + +SHARED_HEADER_SUFFIX_RULES_COMMENT1 = ("""\ +# Suffix rules, putting all outputs into $(obj). +""") + + +SHARED_HEADER_SUFFIX_RULES_COMMENT2 = ("""\ +# Try building from generated source, too. +""") + + +SHARED_FOOTER = """\ +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif +""" + +header = """\ +# This file is generated by gyp; do not edit. + +""" + +# Maps every compilable file extension to the do_cmd that compiles it. +COMPILABLE_EXTENSIONS = { + '.c': 'cc', + '.cc': 'cxx', + '.cpp': 'cxx', + '.cxx': 'cxx', + '.s': 'cc', + '.S': 'cc', +} + +def Compilable(filename): + """Return true if the file is compilable (should be in OBJS).""" + for res in (filename.endswith(e) for e in COMPILABLE_EXTENSIONS): + if res: + return True + return False + + +def Linkable(filename): + """Return true if the file is linkable (should be on the link line).""" + return filename.endswith('.o') + + +def Target(filename): + """Translate a compilable filename to its .o target.""" + return os.path.splitext(filename)[0] + '.o' + + +def EscapeShellArgument(s): + """Quotes an argument so that it will be interpreted literally by a POSIX + shell. Taken from + http://stackoverflow.com/questions/35817/whats-the-best-way-to-escape-ossystem-calls-in-python + """ + return "'" + s.replace("'", "'\\''") + "'" + + +def EscapeMakeVariableExpansion(s): + """Make has its own variable expansion syntax using $. We must escape it for + string to be interpreted literally.""" + return s.replace('$', '$$') + + +def EscapeCppDefine(s): + """Escapes a CPP define so that it will reach the compiler unaltered.""" + s = EscapeShellArgument(s) + s = EscapeMakeVariableExpansion(s) + # '#' characters must be escaped even embedded in a string, else Make will + # treat it as the start of a comment. + return s.replace('#', r'\#') + + +def QuoteIfNecessary(string): + """TODO: Should this ideally be replaced with one or more of the above + functions?""" + if '"' in string: + string = '"' + string.replace('"', '\\"') + '"' + return string + + +def StringToMakefileVariable(string): + """Convert a string to a value that is acceptable as a make variable name.""" + return re.sub('[^a-zA-Z0-9_]', '_', string) + + +srcdir_prefix = '' +def Sourceify(path): + """Convert a path to its source directory form.""" + if '$(' in path: + return path + if os.path.isabs(path): + return path + return srcdir_prefix + path + + +def QuoteSpaces(s, quote=r'\ '): + return s.replace(' ', quote) + + +# Map from qualified target to path to output. +target_outputs = {} +# Map from qualified target to any linkable output. A subset +# of target_outputs. E.g. when mybinary depends on liba, we want to +# include liba in the linker line; when otherbinary depends on +# mybinary, we just want to build mybinary first. +target_link_deps = {} + + +class MakefileWriter: + """MakefileWriter packages up the writing of one target-specific foobar.mk. + + Its only real entry point is Write(), and is mostly used for namespacing. + """ + + def __init__(self, generator_flags, flavor): + self.generator_flags = generator_flags + self.flavor = flavor + + self.suffix_rules_srcdir = {} + self.suffix_rules_objdir1 = {} + self.suffix_rules_objdir2 = {} + + # Generate suffix rules for all compilable extensions. + for ext in COMPILABLE_EXTENSIONS.keys(): + # Suffix rules for source folder. + self.suffix_rules_srcdir.update({ext: ("""\ +$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD + @$(call do_cmd,%s,1) +""" % (ext, COMPILABLE_EXTENSIONS[ext]))}) + + # Suffix rules for generated source files. + self.suffix_rules_objdir1.update({ext: ("""\ +$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj).$(TOOLSET)/%%%s FORCE_DO_CMD + @$(call do_cmd,%s,1) +""" % (ext, COMPILABLE_EXTENSIONS[ext]))}) + self.suffix_rules_objdir2.update({ext: ("""\ +$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD + @$(call do_cmd,%s,1) +""" % (ext, COMPILABLE_EXTENSIONS[ext]))}) + + + def Write(self, qualified_target, base_path, output_filename, spec, configs, + part_of_all): + """The main entry point: writes a .mk file for a single target. + + Arguments: + qualified_target: target we're generating + base_path: path relative to source root we're building in, used to resolve + target-relative paths + output_filename: output .mk file name to write + spec, configs: gyp info + part_of_all: flag indicating this target is part of 'all' + """ + gyp.common.EnsureDirExists(output_filename) + + self.fp = open(output_filename, 'w') + + self.fp.write(header) + + self.qualified_target = qualified_target + self.path = base_path + self.target = spec['target_name'] + self.type = spec['type'] + self.toolset = spec['toolset'] + + self.is_mac_bundle = gyp.xcode_emulation.IsMacBundle(self.flavor, spec) + if self.flavor == 'mac': + self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec) + else: + self.xcode_settings = None + + deps, link_deps = self.ComputeDeps(spec) + + # Some of the generation below can add extra output, sources, or + # link dependencies. All of the out params of the functions that + # follow use names like extra_foo. + extra_outputs = [] + extra_sources = [] + extra_link_deps = [] + extra_mac_bundle_resources = [] + mac_bundle_deps = [] + + if self.is_mac_bundle: + self.output = self.ComputeMacBundleOutput(spec) + self.output_binary = self.ComputeMacBundleBinaryOutput(spec) + else: + self.output = self.output_binary = self.ComputeOutput(spec) + + self.is_standalone_static_library = bool( + spec.get('standalone_static_library', 0)) + self._INSTALLABLE_TARGETS = ('executable', 'loadable_module', + 'shared_library') + if (self.is_standalone_static_library or + self.type in self._INSTALLABLE_TARGETS): + self.alias = os.path.basename(self.output) + install_path = self._InstallableTargetInstallPath() + else: + self.alias = self.output + install_path = self.output + + self.WriteLn("TOOLSET := " + self.toolset) + self.WriteLn("TARGET := " + self.target) + + # Actions must come first, since they can generate more OBJs for use below. + if 'actions' in spec: + self.WriteActions(spec['actions'], extra_sources, extra_outputs, + extra_mac_bundle_resources, part_of_all) + + # Rules must be early like actions. + if 'rules' in spec: + self.WriteRules(spec['rules'], extra_sources, extra_outputs, + extra_mac_bundle_resources, part_of_all) + + if 'copies' in spec: + self.WriteCopies(spec['copies'], extra_outputs, part_of_all) + + # Bundle resources. + if self.is_mac_bundle: + all_mac_bundle_resources = ( + spec.get('mac_bundle_resources', []) + extra_mac_bundle_resources) + self.WriteMacBundleResources(all_mac_bundle_resources, mac_bundle_deps) + self.WriteMacInfoPlist(mac_bundle_deps) + + # Sources. + all_sources = spec.get('sources', []) + extra_sources + if all_sources: + self.WriteSources( + configs, deps, all_sources, extra_outputs, + extra_link_deps, part_of_all, + gyp.xcode_emulation.MacPrefixHeader( + self.xcode_settings, lambda p: Sourceify(self.Absolutify(p)), + self.Pchify)) + sources = filter(Compilable, all_sources) + if sources: + self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT1) + extensions = set([os.path.splitext(s)[1] for s in sources]) + for ext in extensions: + if ext in self.suffix_rules_srcdir: + self.WriteLn(self.suffix_rules_srcdir[ext]) + self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT2) + for ext in extensions: + if ext in self.suffix_rules_objdir1: + self.WriteLn(self.suffix_rules_objdir1[ext]) + for ext in extensions: + if ext in self.suffix_rules_objdir2: + self.WriteLn(self.suffix_rules_objdir2[ext]) + self.WriteLn('# End of this set of suffix rules') + + # Add dependency from bundle to bundle binary. + if self.is_mac_bundle: + mac_bundle_deps.append(self.output_binary) + + self.WriteTarget(spec, configs, deps, extra_link_deps + link_deps, + mac_bundle_deps, extra_outputs, part_of_all) + + # Update global list of target outputs, used in dependency tracking. + target_outputs[qualified_target] = install_path + + # Update global list of link dependencies. + if self.type in ('static_library', 'shared_library'): + target_link_deps[qualified_target] = self.output_binary + + # Currently any versions have the same effect, but in future the behavior + # could be different. + if self.generator_flags.get('android_ndk_version', None): + self.WriteAndroidNdkModuleRule(self.target, all_sources, link_deps) + + self.fp.close() + + + def WriteSubMake(self, output_filename, makefile_path, targets, build_dir): + """Write a "sub-project" Makefile. + + This is a small, wrapper Makefile that calls the top-level Makefile to build + the targets from a single gyp file (i.e. a sub-project). + + Arguments: + output_filename: sub-project Makefile name to write + makefile_path: path to the top-level Makefile + targets: list of "all" targets for this sub-project + build_dir: build output directory, relative to the sub-project + """ + gyp.common.EnsureDirExists(output_filename) + self.fp = open(output_filename, 'w') + self.fp.write(header) + # For consistency with other builders, put sub-project build output in the + # sub-project dir (see test/subdirectory/gyptest-subdir-all.py). + self.WriteLn('export builddir_name ?= %s' % + os.path.join(os.path.dirname(output_filename), build_dir)) + self.WriteLn('.PHONY: all') + self.WriteLn('all:') + if makefile_path: + makefile_path = ' -C ' + makefile_path + self.WriteLn('\t$(MAKE)%s %s' % (makefile_path, ' '.join(targets))) + self.fp.close() + + + def WriteActions(self, actions, extra_sources, extra_outputs, + extra_mac_bundle_resources, part_of_all): + """Write Makefile code for any 'actions' from the gyp input. + + extra_sources: a list that will be filled in with newly generated source + files, if any + extra_outputs: a list that will be filled in with any outputs of these + actions (used to make other pieces dependent on these + actions) + part_of_all: flag indicating this target is part of 'all' + """ + env = self.GetSortedXcodeEnv() + for action in actions: + name = StringToMakefileVariable('%s_%s' % (self.qualified_target, + action['action_name'])) + self.WriteLn('### Rules for action "%s":' % action['action_name']) + inputs = action['inputs'] + outputs = action['outputs'] + + # Build up a list of outputs. + # Collect the output dirs we'll need. + dirs = set() + for out in outputs: + dir = os.path.split(out)[0] + if dir: + dirs.add(dir) + if int(action.get('process_outputs_as_sources', False)): + extra_sources += outputs + if int(action.get('process_outputs_as_mac_bundle_resources', False)): + extra_mac_bundle_resources += outputs + + # Write the actual command. + action_commands = action['action'] + if self.flavor == 'mac': + action_commands = [gyp.xcode_emulation.ExpandEnvVars(command, env) + for command in action_commands] + command = gyp.common.EncodePOSIXShellList(action_commands) + if 'message' in action: + self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, action['message'])) + else: + self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, name)) + if len(dirs) > 0: + command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command + + cd_action = 'cd %s; ' % Sourceify(self.path or '.') + + # command and cd_action get written to a toplevel variable called + # cmd_foo. Toplevel variables can't handle things that change per + # makefile like $(TARGET), so hardcode the target. + command = command.replace('$(TARGET)', self.target) + cd_action = cd_action.replace('$(TARGET)', self.target) + + # Set LD_LIBRARY_PATH in case the action runs an executable from this + # build which links to shared libs from this build. + # actions run on the host, so they should in theory only use host + # libraries, but until everything is made cross-compile safe, also use + # target libraries. + # TODO(piman): when everything is cross-compile safe, remove lib.target + self.WriteLn('cmd_%s = LD_LIBRARY_PATH=$(builddir)/lib.host:' + '$(builddir)/lib.target:$$LD_LIBRARY_PATH; ' + 'export LD_LIBRARY_PATH; ' + '%s%s' + % (name, cd_action, command)) + self.WriteLn() + outputs = map(self.Absolutify, outputs) + # The makefile rules are all relative to the top dir, but the gyp actions + # are defined relative to their containing dir. This replaces the obj + # variable for the action rule with an absolute version so that the output + # goes in the right place. + # Only write the 'obj' and 'builddir' rules for the "primary" output (:1); + # it's superfluous for the "extra outputs", and this avoids accidentally + # writing duplicate dummy rules for those outputs. + # Same for environment. + self.WriteLn("%s: obj := $(abs_obj)" % QuoteSpaces(outputs[0])) + self.WriteLn("%s: builddir := $(abs_builddir)" % QuoteSpaces(outputs[0])) + self.WriteSortedXcodeEnv(outputs[0], self.GetSortedXcodeEnv()) + + for input in inputs: + assert ' ' not in input, ( + "Spaces in action input filenames not supported (%s)" % input) + for output in outputs: + assert ' ' not in output, ( + "Spaces in action output filenames not supported (%s)" % output) + + # See the comment in WriteCopies about expanding env vars. + outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs] + inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs] + + self.WriteDoCmd(outputs, map(Sourceify, map(self.Absolutify, inputs)), + part_of_all=part_of_all, command=name) + + # Stuff the outputs in a variable so we can refer to them later. + outputs_variable = 'action_%s_outputs' % name + self.WriteLn('%s := %s' % (outputs_variable, ' '.join(outputs))) + extra_outputs.append('$(%s)' % outputs_variable) + self.WriteLn() + + self.WriteLn() + + + def WriteRules(self, rules, extra_sources, extra_outputs, + extra_mac_bundle_resources, part_of_all): + """Write Makefile code for any 'rules' from the gyp input. + + extra_sources: a list that will be filled in with newly generated source + files, if any + extra_outputs: a list that will be filled in with any outputs of these + rules (used to make other pieces dependent on these rules) + part_of_all: flag indicating this target is part of 'all' + """ + env = self.GetSortedXcodeEnv() + for rule in rules: + name = StringToMakefileVariable('%s_%s' % (self.qualified_target, + rule['rule_name'])) + count = 0 + self.WriteLn('### Generated for rule %s:' % name) + + all_outputs = [] + + for rule_source in rule.get('rule_sources', []): + dirs = set() + (rule_source_dirname, rule_source_basename) = os.path.split(rule_source) + (rule_source_root, rule_source_ext) = \ + os.path.splitext(rule_source_basename) + + outputs = [self.ExpandInputRoot(out, rule_source_root, + rule_source_dirname) + for out in rule['outputs']] + + for out in outputs: + dir = os.path.dirname(out) + if dir: + dirs.add(dir) + if int(rule.get('process_outputs_as_sources', False)): + extra_sources += outputs + if int(rule.get('process_outputs_as_mac_bundle_resources', False)): + extra_mac_bundle_resources += outputs + inputs = map(Sourceify, map(self.Absolutify, [rule_source] + + rule.get('inputs', []))) + actions = ['$(call do_cmd,%s_%d)' % (name, count)] + + if name == 'resources_grit': + # HACK: This is ugly. Grit intentionally doesn't touch the + # timestamp of its output file when the file doesn't change, + # which is fine in hash-based dependency systems like scons + # and forge, but not kosher in the make world. After some + # discussion, hacking around it here seems like the least + # amount of pain. + actions += ['@touch --no-create $@'] + + # See the comment in WriteCopies about expanding env vars. + outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs] + inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs] + + outputs = map(self.Absolutify, outputs) + all_outputs += outputs + # Only write the 'obj' and 'builddir' rules for the "primary" output + # (:1); it's superfluous for the "extra outputs", and this avoids + # accidentally writing duplicate dummy rules for those outputs. + self.WriteLn('%s: obj := $(abs_obj)' % outputs[0]) + self.WriteLn('%s: builddir := $(abs_builddir)' % outputs[0]) + self.WriteMakeRule(outputs, inputs + ['FORCE_DO_CMD'], actions) + # Spaces in rule filenames are not supported, but rule variables have + # spaces in them (e.g. RULE_INPUT_PATH expands to '$(abspath $<)'). + # The spaces within the variables are valid, so remove the variables + # before checking. + variables_with_spaces = re.compile(r'\$\([^ ]* \$<\)') + for output in outputs: + output = re.sub(variables_with_spaces, '', output) + assert ' ' not in output, ( + "Spaces in rule filenames not yet supported (%s)" % output) + self.WriteLn('all_deps += %s' % ' '.join(outputs)) + + action = [self.ExpandInputRoot(ac, rule_source_root, + rule_source_dirname) + for ac in rule['action']] + mkdirs = '' + if len(dirs) > 0: + mkdirs = 'mkdir -p %s; ' % ' '.join(dirs) + cd_action = 'cd %s; ' % Sourceify(self.path or '.') + + # action, cd_action, and mkdirs get written to a toplevel variable + # called cmd_foo. Toplevel variables can't handle things that change + # per makefile like $(TARGET), so hardcode the target. + if self.flavor == 'mac': + action = [gyp.xcode_emulation.ExpandEnvVars(command, env) + for command in action] + action = gyp.common.EncodePOSIXShellList(action) + action = action.replace('$(TARGET)', self.target) + cd_action = cd_action.replace('$(TARGET)', self.target) + mkdirs = mkdirs.replace('$(TARGET)', self.target) + + # Set LD_LIBRARY_PATH in case the rule runs an executable from this + # build which links to shared libs from this build. + # rules run on the host, so they should in theory only use host + # libraries, but until everything is made cross-compile safe, also use + # target libraries. + # TODO(piman): when everything is cross-compile safe, remove lib.target + self.WriteLn( + "cmd_%(name)s_%(count)d = LD_LIBRARY_PATH=" + "$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; " + "export LD_LIBRARY_PATH; " + "%(cd_action)s%(mkdirs)s%(action)s" % { + 'action': action, + 'cd_action': cd_action, + 'count': count, + 'mkdirs': mkdirs, + 'name': name, + }) + self.WriteLn( + 'quiet_cmd_%(name)s_%(count)d = RULE %(name)s_%(count)d $@' % { + 'count': count, + 'name': name, + }) + self.WriteLn() + count += 1 + + outputs_variable = 'rule_%s_outputs' % name + self.WriteList(all_outputs, outputs_variable) + extra_outputs.append('$(%s)' % outputs_variable) + + self.WriteLn('### Finished generating for rule: %s' % name) + self.WriteLn() + self.WriteLn('### Finished generating for all rules') + self.WriteLn('') + + + def WriteCopies(self, copies, extra_outputs, part_of_all): + """Write Makefile code for any 'copies' from the gyp input. + + extra_outputs: a list that will be filled in with any outputs of this action + (used to make other pieces dependent on this action) + part_of_all: flag indicating this target is part of 'all' + """ + self.WriteLn('### Generated for copy rule.') + + variable = StringToMakefileVariable(self.qualified_target + '_copies') + outputs = [] + for copy in copies: + for path in copy['files']: + # Absolutify() may call normpath, and will strip trailing slashes. + path = Sourceify(self.Absolutify(path)) + filename = os.path.split(path)[1] + output = Sourceify(self.Absolutify(os.path.join(copy['destination'], + filename))) + + # If the output path has variables in it, which happens in practice for + # 'copies', writing the environment as target-local doesn't work, + # because the variables are already needed for the target name. + # Copying the environment variables into global make variables doesn't + # work either, because then the .d files will potentially contain spaces + # after variable expansion, and .d file handling cannot handle spaces. + # As a workaround, manually expand variables at gyp time. Since 'copies' + # can't run scripts, there's no need to write the env then. + # WriteDoCmd() will escape spaces for .d files. + env = self.GetSortedXcodeEnv() + output = gyp.xcode_emulation.ExpandEnvVars(output, env) + path = gyp.xcode_emulation.ExpandEnvVars(path, env) + self.WriteDoCmd([output], [path], 'copy', part_of_all) + outputs.append(output) + self.WriteLn('%s = %s' % (variable, ' '.join(map(QuoteSpaces, outputs)))) + extra_outputs.append('$(%s)' % variable) + self.WriteLn() + + + def WriteMacBundleResources(self, resources, bundle_deps): + """Writes Makefile code for 'mac_bundle_resources'.""" + self.WriteLn('### Generated for mac_bundle_resources') + + for output, res in gyp.xcode_emulation.GetMacBundleResources( + generator_default_variables['PRODUCT_DIR'], self.xcode_settings, + map(Sourceify, map(self.Absolutify, resources))): + self.WriteDoCmd([output], [res], 'mac_tool,,,copy-bundle-resource', + part_of_all=True) + bundle_deps.append(output) + + + def WriteMacInfoPlist(self, bundle_deps): + """Write Makefile code for bundle Info.plist files.""" + info_plist, out, defines, extra_env = gyp.xcode_emulation.GetMacInfoPlist( + generator_default_variables['PRODUCT_DIR'], self.xcode_settings, + lambda p: Sourceify(self.Absolutify(p))) + if not info_plist: + return + if defines: + # Create an intermediate file to store preprocessed results. + intermediate_plist = ('$(obj).$(TOOLSET)/$(TARGET)/' + + os.path.basename(info_plist)) + self.WriteList(defines, intermediate_plist + ': INFOPLIST_DEFINES', '-D', + quoter=EscapeCppDefine) + self.WriteMakeRule([intermediate_plist], [info_plist], + ['$(call do_cmd,infoplist)', + # "Convert" the plist so that any weird whitespace changes from the + # preprocessor do not affect the XML parser in mac_tool. + '@plutil -convert xml1 $@ $@']) + info_plist = intermediate_plist + # plists can contain envvars and substitute them into the file. + self.WriteSortedXcodeEnv( + out, self.GetSortedXcodeEnv(additional_settings=extra_env)) + self.WriteDoCmd([out], [info_plist], 'mac_tool,,,copy-info-plist', + part_of_all=True) + bundle_deps.append(out) + + + def WriteSources(self, configs, deps, sources, + extra_outputs, extra_link_deps, + part_of_all, precompiled_header): + """Write Makefile code for any 'sources' from the gyp input. + These are source files necessary to build the current target. + + configs, deps, sources: input from gyp. + extra_outputs: a list of extra outputs this action should be dependent on; + used to serialize action/rules before compilation + extra_link_deps: a list that will be filled in with any outputs of + compilation (to be used in link lines) + part_of_all: flag indicating this target is part of 'all' + """ + + # Write configuration-specific variables for CFLAGS, etc. + for configname in sorted(configs.keys()): + config = configs[configname] + self.WriteList(config.get('defines'), 'DEFS_%s' % configname, prefix='-D', + quoter=EscapeCppDefine) + + if self.flavor == 'mac': + cflags = self.xcode_settings.GetCflags(configname) + cflags_c = self.xcode_settings.GetCflagsC(configname) + cflags_cc = self.xcode_settings.GetCflagsCC(configname) + cflags_objc = self.xcode_settings.GetCflagsObjC(configname) + cflags_objcc = self.xcode_settings.GetCflagsObjCC(configname) + else: + cflags = config.get('cflags') + cflags_c = config.get('cflags_c') + cflags_cc = config.get('cflags_cc') + + self.WriteLn("# Flags passed to all source files."); + self.WriteList(cflags, 'CFLAGS_%s' % configname) + self.WriteLn("# Flags passed to only C files."); + self.WriteList(cflags_c, 'CFLAGS_C_%s' % configname) + self.WriteLn("# Flags passed to only C++ files."); + self.WriteList(cflags_cc, 'CFLAGS_CC_%s' % configname) + if self.flavor == 'mac': + self.WriteLn("# Flags passed to only ObjC files."); + self.WriteList(cflags_objc, 'CFLAGS_OBJC_%s' % configname) + self.WriteLn("# Flags passed to only ObjC++ files."); + self.WriteList(cflags_objcc, 'CFLAGS_OBJCC_%s' % configname) + includes = config.get('include_dirs') + if includes: + includes = map(Sourceify, map(self.Absolutify, includes)) + self.WriteList(includes, 'INCS_%s' % configname, prefix='-I') + + compilable = filter(Compilable, sources) + objs = map(self.Objectify, map(self.Absolutify, map(Target, compilable))) + self.WriteList(objs, 'OBJS') + + for obj in objs: + assert ' ' not in obj, ( + "Spaces in object filenames not supported (%s)" % obj) + self.WriteLn('# Add to the list of files we specially track ' + 'dependencies for.') + self.WriteLn('all_deps += $(OBJS)') + self.WriteLn() + + # Make sure our dependencies are built first. + if deps: + self.WriteMakeRule(['$(OBJS)'], deps, + comment = 'Make sure our dependencies are built ' + 'before any of us.', + order_only = True) + + # Make sure the actions and rules run first. + # If they generate any extra headers etc., the per-.o file dep tracking + # will catch the proper rebuilds, so order only is still ok here. + if extra_outputs: + self.WriteMakeRule(['$(OBJS)'], extra_outputs, + comment = 'Make sure our actions/rules run ' + 'before any of us.', + order_only = True) + + pchdeps = precompiled_header.GetObjDependencies(compilable, objs ) + if pchdeps: + self.WriteLn('# Dependencies from obj files to their precompiled headers') + for source, obj, gch in pchdeps: + self.WriteLn('%s: %s' % (obj, gch)) + self.WriteLn('# End precompiled header dependencies') + + if objs: + extra_link_deps.append('$(OBJS)') + self.WriteLn("""\ +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual.""") + self.WriteLn("$(OBJS): TOOLSET := $(TOOLSET)") + self.WriteLn("$(OBJS): GYP_CFLAGS := " + "$(DEFS_$(BUILDTYPE)) " + "$(INCS_$(BUILDTYPE)) " + "%s " % precompiled_header.GetInclude('c') + + "$(CFLAGS_$(BUILDTYPE)) " + "$(CFLAGS_C_$(BUILDTYPE))") + self.WriteLn("$(OBJS): GYP_CXXFLAGS := " + "$(DEFS_$(BUILDTYPE)) " + "$(INCS_$(BUILDTYPE)) " + "%s " % precompiled_header.GetInclude('cc') + + "$(CFLAGS_$(BUILDTYPE)) " + "$(CFLAGS_CC_$(BUILDTYPE))") + if self.flavor == 'mac': + self.WriteLn("$(OBJS): GYP_OBJCFLAGS := " + "$(DEFS_$(BUILDTYPE)) " + "$(INCS_$(BUILDTYPE)) " + "%s " % precompiled_header.GetInclude('m') + + "$(CFLAGS_$(BUILDTYPE)) " + "$(CFLAGS_C_$(BUILDTYPE)) " + "$(CFLAGS_OBJC_$(BUILDTYPE))") + self.WriteLn("$(OBJS): GYP_OBJCXXFLAGS := " + "$(DEFS_$(BUILDTYPE)) " + "$(INCS_$(BUILDTYPE)) " + "%s " % precompiled_header.GetInclude('mm') + + "$(CFLAGS_$(BUILDTYPE)) " + "$(CFLAGS_CC_$(BUILDTYPE)) " + "$(CFLAGS_OBJCC_$(BUILDTYPE))") + + self.WritePchTargets(precompiled_header.GetPchBuildCommands()) + + # If there are any object files in our input file list, link them into our + # output. + extra_link_deps += filter(Linkable, sources) + + self.WriteLn() + + def WritePchTargets(self, pch_commands): + """Writes make rules to compile prefix headers.""" + if not pch_commands: + return + + for gch, lang_flag, lang, input in pch_commands: + extra_flags = { + 'c': '$(CFLAGS_C_$(BUILDTYPE))', + 'cc': '$(CFLAGS_CC_$(BUILDTYPE))', + 'm': '$(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))', + 'mm': '$(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))', + }[lang] + var_name = { + 'c': 'GYP_PCH_CFLAGS', + 'cc': 'GYP_PCH_CXXFLAGS', + 'm': 'GYP_PCH_OBJCFLAGS', + 'mm': 'GYP_PCH_OBJCXXFLAGS', + }[lang] + self.WriteLn("%s: %s := %s " % (gch, var_name, lang_flag) + + "$(DEFS_$(BUILDTYPE)) " + "$(INCS_$(BUILDTYPE)) " + "$(CFLAGS_$(BUILDTYPE)) " + + extra_flags) + + self.WriteLn('%s: %s FORCE_DO_CMD' % (gch, input)) + self.WriteLn('\t@$(call do_cmd,pch_%s,1)' % lang) + self.WriteLn('') + assert ' ' not in gch, ( + "Spaces in gch filenames not supported (%s)" % gch) + self.WriteLn('all_deps += %s' % gch) + self.WriteLn('') + + + def ComputeOutputBasename(self, spec): + """Return the 'output basename' of a gyp spec. + + E.g., the loadable module 'foobar' in directory 'baz' will produce + 'libfoobar.so' + """ + assert not self.is_mac_bundle + + if self.flavor == 'mac' and self.type in ( + 'static_library', 'executable', 'shared_library', 'loadable_module'): + return self.xcode_settings.GetExecutablePath() + + target = spec['target_name'] + target_prefix = '' + target_ext = '' + if self.type == 'static_library': + if target[:3] == 'lib': + target = target[3:] + target_prefix = 'lib' + target_ext = '.a' + elif self.type in ('loadable_module', 'shared_library'): + if target[:3] == 'lib': + target = target[3:] + target_prefix = 'lib' + target_ext = '.so' + elif self.type == 'none': + target = '%s.stamp' % target + elif self.type != 'executable': + print ("ERROR: What output file should be generated?", + "type", self.type, "target", target) + + target_prefix = spec.get('product_prefix', target_prefix) + target = spec.get('product_name', target) + product_ext = spec.get('product_extension') + if product_ext: + target_ext = '.' + product_ext + + return target_prefix + target + target_ext + + + def _InstallImmediately(self): + return self.toolset == 'target' and self.flavor == 'mac' and self.type in ( + 'static_library', 'executable', 'shared_library', 'loadable_module') + + + def ComputeOutput(self, spec): + """Return the 'output' (full output path) of a gyp spec. + + E.g., the loadable module 'foobar' in directory 'baz' will produce + '$(obj)/baz/libfoobar.so' + """ + assert not self.is_mac_bundle + + path = os.path.join('$(obj).' + self.toolset, self.path) + if self.type == 'executable' or self._InstallImmediately(): + path = '$(builddir)' + path = spec.get('product_dir', path) + return os.path.join(path, self.ComputeOutputBasename(spec)) + + + def ComputeMacBundleOutput(self, spec): + """Return the 'output' (full output path) to a bundle output directory.""" + assert self.is_mac_bundle + path = generator_default_variables['PRODUCT_DIR'] + return os.path.join(path, self.xcode_settings.GetWrapperName()) + + + def ComputeMacBundleBinaryOutput(self, spec): + """Return the 'output' (full output path) to the binary in a bundle.""" + path = generator_default_variables['PRODUCT_DIR'] + return os.path.join(path, self.xcode_settings.GetExecutablePath()) + + + def ComputeDeps(self, spec): + """Compute the dependencies of a gyp spec. + + Returns a tuple (deps, link_deps), where each is a list of + filenames that will need to be put in front of make for either + building (deps) or linking (link_deps). + """ + deps = [] + link_deps = [] + if 'dependencies' in spec: + deps.extend([target_outputs[dep] for dep in spec['dependencies'] + if target_outputs[dep]]) + for dep in spec['dependencies']: + if dep in target_link_deps: + link_deps.append(target_link_deps[dep]) + deps.extend(link_deps) + # TODO: It seems we need to transitively link in libraries (e.g. -lfoo)? + # This hack makes it work: + # link_deps.extend(spec.get('libraries', [])) + return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps)) + + + def WriteDependencyOnExtraOutputs(self, target, extra_outputs): + self.WriteMakeRule([self.output_binary], extra_outputs, + comment = 'Build our special outputs first.', + order_only = True) + + + def WriteTarget(self, spec, configs, deps, link_deps, bundle_deps, + extra_outputs, part_of_all): + """Write Makefile code to produce the final target of the gyp spec. + + spec, configs: input from gyp. + deps, link_deps: dependency lists; see ComputeDeps() + extra_outputs: any extra outputs that our target should depend on + part_of_all: flag indicating this target is part of 'all' + """ + + self.WriteLn('### Rules for final target.') + + if extra_outputs: + self.WriteDependencyOnExtraOutputs(self.output_binary, extra_outputs) + self.WriteMakeRule(extra_outputs, deps, + comment=('Preserve order dependency of ' + 'special output on deps.'), + order_only = True) + + target_postbuilds = {} + if self.type != 'none': + for configname in sorted(configs.keys()): + config = configs[configname] + if self.flavor == 'mac': + ldflags = self.xcode_settings.GetLdflags(configname, + generator_default_variables['PRODUCT_DIR'], + lambda p: Sourceify(self.Absolutify(p))) + + # TARGET_POSTBUILDS_$(BUILDTYPE) is added to postbuilds later on. + gyp_to_build = gyp.common.InvertRelativePath(self.path) + target_postbuild = self.xcode_settings.AddImplicitPostbuilds( + configname, + QuoteSpaces(os.path.normpath(os.path.join(gyp_to_build, + self.output))), + QuoteSpaces(os.path.normpath(os.path.join(gyp_to_build, + self.output_binary)))) + if target_postbuild: + target_postbuilds[configname] = target_postbuild + else: + ldflags = config.get('ldflags', []) + # Compute an rpath for this output if needed. + if any(dep.endswith('.so') or '.so.' in dep for dep in deps): + # We want to get the literal string "$ORIGIN" into the link command, + # so we need lots of escaping. + ldflags.append(r'-Wl,-rpath=\$$ORIGIN/lib.%s/' % self.toolset) + ldflags.append(r'-Wl,-rpath-link=\$(builddir)/lib.%s/' % + self.toolset) + library_dirs = config.get('library_dirs', []) + ldflags += [('-L%s' % library_dir) for library_dir in library_dirs] + self.WriteList(ldflags, 'LDFLAGS_%s' % configname) + if self.flavor == 'mac': + self.WriteList(self.xcode_settings.GetLibtoolflags(configname), + 'LIBTOOLFLAGS_%s' % configname) + libraries = spec.get('libraries') + if libraries: + # Remove duplicate entries + # Commented out due to https://code.google.com/p/gyp/issues/detail?id=419 + # libraries = gyp.common.uniquer(libraries) + if self.flavor == 'mac': + libraries = self.xcode_settings.AdjustLibraries(libraries) + self.WriteList(libraries, 'LIBS') + self.WriteLn('%s: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))' % + QuoteSpaces(self.output_binary)) + self.WriteLn('%s: LIBS := $(LIBS)' % QuoteSpaces(self.output_binary)) + + if self.flavor == 'mac': + self.WriteLn('%s: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE))' % + QuoteSpaces(self.output_binary)) + + # Postbuild actions. Like actions, but implicitly depend on the target's + # output. + postbuilds = [] + if self.flavor == 'mac': + if target_postbuilds: + postbuilds.append('$(TARGET_POSTBUILDS_$(BUILDTYPE))') + postbuilds.extend( + gyp.xcode_emulation.GetSpecPostbuildCommands(spec)) + + if postbuilds: + # Envvars may be referenced by TARGET_POSTBUILDS_$(BUILDTYPE), + # so we must output its definition first, since we declare variables + # using ":=". + self.WriteSortedXcodeEnv(self.output, self.GetSortedXcodePostbuildEnv()) + + for configname in target_postbuilds: + self.WriteLn('%s: TARGET_POSTBUILDS_%s := %s' % + (QuoteSpaces(self.output), + configname, + gyp.common.EncodePOSIXShellList(target_postbuilds[configname]))) + + # Postbuilds expect to be run in the gyp file's directory, so insert an + # implicit postbuild to cd to there. + postbuilds.insert(0, gyp.common.EncodePOSIXShellList(['cd', self.path])) + for i in xrange(len(postbuilds)): + if not postbuilds[i].startswith('$'): + postbuilds[i] = EscapeShellArgument(postbuilds[i]) + self.WriteLn('%s: builddir := $(abs_builddir)' % QuoteSpaces(self.output)) + self.WriteLn('%s: POSTBUILDS := %s' % ( + QuoteSpaces(self.output), ' '.join(postbuilds))) + + # A bundle directory depends on its dependencies such as bundle resources + # and bundle binary. When all dependencies have been built, the bundle + # needs to be packaged. + if self.is_mac_bundle: + # If the framework doesn't contain a binary, then nothing depends + # on the actions -- make the framework depend on them directly too. + self.WriteDependencyOnExtraOutputs(self.output, extra_outputs) + + # Bundle dependencies. Note that the code below adds actions to this + # target, so if you move these two lines, move the lines below as well. + self.WriteList(map(QuoteSpaces, bundle_deps), 'BUNDLE_DEPS') + self.WriteLn('%s: $(BUNDLE_DEPS)' % QuoteSpaces(self.output)) + + # After the framework is built, package it. Needs to happen before + # postbuilds, since postbuilds depend on this. + if self.type in ('shared_library', 'loadable_module'): + self.WriteLn('\t@$(call do_cmd,mac_package_framework,,,%s)' % + self.xcode_settings.GetFrameworkVersion()) + + # Bundle postbuilds can depend on the whole bundle, so run them after + # the bundle is packaged, not already after the bundle binary is done. + if postbuilds: + self.WriteLn('\t@$(call do_postbuilds)') + postbuilds = [] # Don't write postbuilds for target's output. + + # Needed by test/mac/gyptest-rebuild.py. + self.WriteLn('\t@true # No-op, used by tests') + + # Since this target depends on binary and resources which are in + # nested subfolders, the framework directory will be older than + # its dependencies usually. To prevent this rule from executing + # on every build (expensive, especially with postbuilds), expliclity + # update the time on the framework directory. + self.WriteLn('\t@touch -c %s' % QuoteSpaces(self.output)) + + if postbuilds: + assert not self.is_mac_bundle, ('Postbuilds for bundles should be done ' + 'on the bundle, not the binary (target \'%s\')' % self.target) + assert 'product_dir' not in spec, ('Postbuilds do not work with ' + 'custom product_dir') + + if self.type == 'executable': + self.WriteLn('%s: LD_INPUTS := %s' % ( + QuoteSpaces(self.output_binary), + ' '.join(map(QuoteSpaces, link_deps)))) + if self.toolset == 'host' and self.flavor == 'android': + self.WriteDoCmd([self.output_binary], link_deps, 'link_host', + part_of_all, postbuilds=postbuilds) + else: + self.WriteDoCmd([self.output_binary], link_deps, 'link', part_of_all, + postbuilds=postbuilds) + + elif self.type == 'static_library': + for link_dep in link_deps: + assert ' ' not in link_dep, ( + "Spaces in alink input filenames not supported (%s)" % link_dep) + if (self.flavor not in ('mac', 'openbsd', 'win') and not + self.is_standalone_static_library): + self.WriteDoCmd([self.output_binary], link_deps, 'alink_thin', + part_of_all, postbuilds=postbuilds) + else: + self.WriteDoCmd([self.output_binary], link_deps, 'alink', part_of_all, + postbuilds=postbuilds) + elif self.type == 'shared_library': + self.WriteLn('%s: LD_INPUTS := %s' % ( + QuoteSpaces(self.output_binary), + ' '.join(map(QuoteSpaces, link_deps)))) + self.WriteDoCmd([self.output_binary], link_deps, 'solink', part_of_all, + postbuilds=postbuilds) + elif self.type == 'loadable_module': + for link_dep in link_deps: + assert ' ' not in link_dep, ( + "Spaces in module input filenames not supported (%s)" % link_dep) + if self.toolset == 'host' and self.flavor == 'android': + self.WriteDoCmd([self.output_binary], link_deps, 'solink_module_host', + part_of_all, postbuilds=postbuilds) + else: + self.WriteDoCmd( + [self.output_binary], link_deps, 'solink_module', part_of_all, + postbuilds=postbuilds) + elif self.type == 'none': + # Write a stamp line. + self.WriteDoCmd([self.output_binary], deps, 'touch', part_of_all, + postbuilds=postbuilds) + else: + print "WARNING: no output for", self.type, target + + # Add an alias for each target (if there are any outputs). + # Installable target aliases are created below. + if ((self.output and self.output != self.target) and + (self.type not in self._INSTALLABLE_TARGETS)): + self.WriteMakeRule([self.target], [self.output], + comment='Add target alias', phony = True) + if part_of_all: + self.WriteMakeRule(['all'], [self.target], + comment = 'Add target alias to "all" target.', + phony = True) + + # Add special-case rules for our installable targets. + # 1) They need to install to the build dir or "product" dir. + # 2) They get shortcuts for building (e.g. "make chrome"). + # 3) They are part of "make all". + if (self.type in self._INSTALLABLE_TARGETS or + self.is_standalone_static_library): + if self.type == 'shared_library': + file_desc = 'shared library' + elif self.type == 'static_library': + file_desc = 'static library' + else: + file_desc = 'executable' + install_path = self._InstallableTargetInstallPath() + installable_deps = [self.output] + if (self.flavor == 'mac' and not 'product_dir' in spec and + self.toolset == 'target'): + # On mac, products are created in install_path immediately. + assert install_path == self.output, '%s != %s' % ( + install_path, self.output) + + # Point the target alias to the final binary output. + self.WriteMakeRule([self.target], [install_path], + comment='Add target alias', phony = True) + if install_path != self.output: + assert not self.is_mac_bundle # See comment a few lines above. + self.WriteDoCmd([install_path], [self.output], 'copy', + comment = 'Copy this to the %s output path.' % + file_desc, part_of_all=part_of_all) + installable_deps.append(install_path) + if self.output != self.alias and self.alias != self.target: + self.WriteMakeRule([self.alias], installable_deps, + comment = 'Short alias for building this %s.' % + file_desc, phony = True) + if part_of_all: + self.WriteMakeRule(['all'], [install_path], + comment = 'Add %s to "all" target.' % file_desc, + phony = True) + + + def WriteList(self, value_list, variable=None, prefix='', + quoter=QuoteIfNecessary): + """Write a variable definition that is a list of values. + + E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out + foo = blaha blahb + but in a pretty-printed style. + """ + values = '' + if value_list: + value_list = [quoter(prefix + l) for l in value_list] + values = ' \\\n\t' + ' \\\n\t'.join(value_list) + self.fp.write('%s :=%s\n\n' % (variable, values)) + + + def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None, + postbuilds=False): + """Write a Makefile rule that uses do_cmd. + + This makes the outputs dependent on the command line that was run, + as well as support the V= make command line flag. + """ + suffix = '' + if postbuilds: + assert ',' not in command + suffix = ',,1' # Tell do_cmd to honor $POSTBUILDS + self.WriteMakeRule(outputs, inputs, + actions = ['$(call do_cmd,%s%s)' % (command, suffix)], + comment = comment, + force = True) + # Add our outputs to the list of targets we read depfiles from. + # all_deps is only used for deps file reading, and for deps files we replace + # spaces with ? because escaping doesn't work with make's $(sort) and + # other functions. + outputs = [QuoteSpaces(o, SPACE_REPLACEMENT) for o in outputs] + self.WriteLn('all_deps += %s' % ' '.join(outputs)) + + + def WriteMakeRule(self, outputs, inputs, actions=None, comment=None, + order_only=False, force=False, phony=False): + """Write a Makefile rule, with some extra tricks. + + outputs: a list of outputs for the rule (note: this is not directly + supported by make; see comments below) + inputs: a list of inputs for the rule + actions: a list of shell commands to run for the rule + comment: a comment to put in the Makefile above the rule (also useful + for making this Python script's code self-documenting) + order_only: if true, makes the dependency order-only + force: if true, include FORCE_DO_CMD as an order-only dep + phony: if true, the rule does not actually generate the named output, the + output is just a name to run the rule + """ + outputs = map(QuoteSpaces, outputs) + inputs = map(QuoteSpaces, inputs) + + if comment: + self.WriteLn('# ' + comment) + if phony: + self.WriteLn('.PHONY: ' + ' '.join(outputs)) + # TODO(evanm): just make order_only a list of deps instead of these hacks. + if order_only: + order_insert = '| ' + pick_output = ' '.join(outputs) + else: + order_insert = '' + pick_output = outputs[0] + if force: + force_append = ' FORCE_DO_CMD' + else: + force_append = '' + if actions: + self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0]) + self.WriteLn('%s: %s%s%s' % (pick_output, order_insert, ' '.join(inputs), + force_append)) + if actions: + for action in actions: + self.WriteLn('\t%s' % action) + if not order_only and len(outputs) > 1: + # If we have more than one output, a rule like + # foo bar: baz + # that for *each* output we must run the action, potentially + # in parallel. That is not what we're trying to write -- what + # we want is that we run the action once and it generates all + # the files. + # http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html + # discusses this problem and has this solution: + # 1) Write the naive rule that would produce parallel runs of + # the action. + # 2) Make the outputs seralized on each other, so we won't start + # a parallel run until the first run finishes, at which point + # we'll have generated all the outputs and we're done. + self.WriteLn('%s: %s' % (' '.join(outputs[1:]), outputs[0])) + # Add a dummy command to the "extra outputs" rule, otherwise make seems to + # think these outputs haven't (couldn't have?) changed, and thus doesn't + # flag them as changed (i.e. include in '$?') when evaluating dependent + # rules, which in turn causes do_cmd() to skip running dependent commands. + self.WriteLn('%s: ;' % (' '.join(outputs[1:]))) + self.WriteLn() + + + def WriteAndroidNdkModuleRule(self, module_name, all_sources, link_deps): + """Write a set of LOCAL_XXX definitions for Android NDK. + + These variable definitions will be used by Android NDK but do nothing for + non-Android applications. + + Arguments: + module_name: Android NDK module name, which must be unique among all + module names. + all_sources: A list of source files (will be filtered by Compilable). + link_deps: A list of link dependencies, which must be sorted in + the order from dependencies to dependents. + """ + if self.type not in ('executable', 'shared_library', 'static_library'): + return + + self.WriteLn('# Variable definitions for Android applications') + self.WriteLn('include $(CLEAR_VARS)') + self.WriteLn('LOCAL_MODULE := ' + module_name) + self.WriteLn('LOCAL_CFLAGS := $(CFLAGS_$(BUILDTYPE)) ' + '$(DEFS_$(BUILDTYPE)) ' + # LOCAL_CFLAGS is applied to both of C and C++. There is + # no way to specify $(CFLAGS_C_$(BUILDTYPE)) only for C + # sources. + '$(CFLAGS_C_$(BUILDTYPE)) ' + # $(INCS_$(BUILDTYPE)) includes the prefix '-I' while + # LOCAL_C_INCLUDES does not expect it. So put it in + # LOCAL_CFLAGS. + '$(INCS_$(BUILDTYPE))') + # LOCAL_CXXFLAGS is obsolete and LOCAL_CPPFLAGS is preferred. + self.WriteLn('LOCAL_CPPFLAGS := $(CFLAGS_CC_$(BUILDTYPE))') + self.WriteLn('LOCAL_C_INCLUDES :=') + self.WriteLn('LOCAL_LDLIBS := $(LDFLAGS_$(BUILDTYPE)) $(LIBS)') + + # Detect the C++ extension. + cpp_ext = {'.cc': 0, '.cpp': 0, '.cxx': 0} + default_cpp_ext = '.cpp' + for filename in all_sources: + ext = os.path.splitext(filename)[1] + if ext in cpp_ext: + cpp_ext[ext] += 1 + if cpp_ext[ext] > cpp_ext[default_cpp_ext]: + default_cpp_ext = ext + self.WriteLn('LOCAL_CPP_EXTENSION := ' + default_cpp_ext) + + self.WriteList(map(self.Absolutify, filter(Compilable, all_sources)), + 'LOCAL_SRC_FILES') + + # Filter out those which do not match prefix and suffix and produce + # the resulting list without prefix and suffix. + def DepsToModules(deps, prefix, suffix): + modules = [] + for filepath in deps: + filename = os.path.basename(filepath) + if filename.startswith(prefix) and filename.endswith(suffix): + modules.append(filename[len(prefix):-len(suffix)]) + return modules + + # Retrieve the default value of 'SHARED_LIB_SUFFIX' + params = {'flavor': 'linux'} + default_variables = {} + CalculateVariables(default_variables, params) + + self.WriteList( + DepsToModules(link_deps, + generator_default_variables['SHARED_LIB_PREFIX'], + default_variables['SHARED_LIB_SUFFIX']), + 'LOCAL_SHARED_LIBRARIES') + self.WriteList( + DepsToModules(link_deps, + generator_default_variables['STATIC_LIB_PREFIX'], + generator_default_variables['STATIC_LIB_SUFFIX']), + 'LOCAL_STATIC_LIBRARIES') + + if self.type == 'executable': + self.WriteLn('include $(BUILD_EXECUTABLE)') + elif self.type == 'shared_library': + self.WriteLn('include $(BUILD_SHARED_LIBRARY)') + elif self.type == 'static_library': + self.WriteLn('include $(BUILD_STATIC_LIBRARY)') + self.WriteLn() + + + def WriteLn(self, text=''): + self.fp.write(text + '\n') + + + def GetSortedXcodeEnv(self, additional_settings=None): + return gyp.xcode_emulation.GetSortedXcodeEnv( + self.xcode_settings, "$(abs_builddir)", + os.path.join("$(abs_srcdir)", self.path), "$(BUILDTYPE)", + additional_settings) + + + def GetSortedXcodePostbuildEnv(self): + # CHROMIUM_STRIP_SAVE_FILE is a chromium-specific hack. + # TODO(thakis): It would be nice to have some general mechanism instead. + strip_save_file = self.xcode_settings.GetPerTargetSetting( + 'CHROMIUM_STRIP_SAVE_FILE', '') + # Even if strip_save_file is empty, explicitly write it. Else a postbuild + # might pick up an export from an earlier target. + return self.GetSortedXcodeEnv( + additional_settings={'CHROMIUM_STRIP_SAVE_FILE': strip_save_file}) + + + def WriteSortedXcodeEnv(self, target, env): + for k, v in env: + # For + # foo := a\ b + # the escaped space does the right thing. For + # export foo := a\ b + # it does not -- the backslash is written to the env as literal character. + # So don't escape spaces in |env[k]|. + self.WriteLn('%s: export %s := %s' % (QuoteSpaces(target), k, v)) + + + def Objectify(self, path): + """Convert a path to its output directory form.""" + if '$(' in path: + path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/' % self.toolset) + if not '$(obj)' in path: + path = '$(obj).%s/$(TARGET)/%s' % (self.toolset, path) + return path + + + def Pchify(self, path, lang): + """Convert a prefix header path to its output directory form.""" + path = self.Absolutify(path) + if '$(' in path: + path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/pch-%s' % + (self.toolset, lang)) + return path + return '$(obj).%s/$(TARGET)/pch-%s/%s' % (self.toolset, lang, path) + + + def Absolutify(self, path): + """Convert a subdirectory-relative path into a base-relative path. + Skips over paths that contain variables.""" + if '$(' in path: + # Don't call normpath in this case, as it might collapse the + # path too aggressively if it features '..'. However it's still + # important to strip trailing slashes. + return path.rstrip('/') + return os.path.normpath(os.path.join(self.path, path)) + + + def ExpandInputRoot(self, template, expansion, dirname): + if '%(INPUT_ROOT)s' not in template and '%(INPUT_DIRNAME)s' not in template: + return template + path = template % { + 'INPUT_ROOT': expansion, + 'INPUT_DIRNAME': dirname, + } + return path + + + def _InstallableTargetInstallPath(self): + """Returns the location of the final output for an installable target.""" + # Xcode puts shared_library results into PRODUCT_DIR, and some gyp files + # rely on this. Emulate this behavior for mac. + if (self.type == 'shared_library' and + (self.flavor != 'mac' or self.toolset != 'target')): + # Install all shared libs into a common directory (per toolset) for + # convenient access with LD_LIBRARY_PATH. + return '$(builddir)/lib.%s/%s' % (self.toolset, self.alias) + return '$(builddir)/' + self.alias + + +def WriteAutoRegenerationRule(params, root_makefile, makefile_name, + build_files): + """Write the target to regenerate the Makefile.""" + options = params['options'] + build_files_args = [gyp.common.RelativePath(filename, options.toplevel_dir) + for filename in params['build_files_arg']] + + gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'], + options.toplevel_dir) + if not gyp_binary.startswith(os.sep): + gyp_binary = os.path.join('.', gyp_binary) + + root_makefile.write( + "quiet_cmd_regen_makefile = ACTION Regenerating $@\n" + "cmd_regen_makefile = cd $(srcdir); %(cmd)s\n" + "%(makefile_name)s: %(deps)s\n" + "\t$(call do_cmd,regen_makefile)\n\n" % { + 'makefile_name': makefile_name, + 'deps': ' '.join(map(Sourceify, build_files)), + 'cmd': gyp.common.EncodePOSIXShellList( + [gyp_binary, '-fmake'] + + gyp.RegenerateFlags(options) + + build_files_args)}) + + +def PerformBuild(data, configurations, params): + options = params['options'] + for config in configurations: + arguments = ['make'] + if options.toplevel_dir and options.toplevel_dir != '.': + arguments += '-C', options.toplevel_dir + arguments.append('BUILDTYPE=' + config) + print 'Building [%s]: %s' % (config, arguments) + subprocess.check_call(arguments) + + +def GenerateOutput(target_list, target_dicts, data, params): + options = params['options'] + flavor = gyp.common.GetFlavor(params) + generator_flags = params.get('generator_flags', {}) + builddir_name = generator_flags.get('output_dir', 'out') + android_ndk_version = generator_flags.get('android_ndk_version', None) + default_target = generator_flags.get('default_target', 'all') + + def CalculateMakefilePath(build_file, base_name): + """Determine where to write a Makefile for a given gyp file.""" + # Paths in gyp files are relative to the .gyp file, but we want + # paths relative to the source root for the master makefile. Grab + # the path of the .gyp file as the base to relativize against. + # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp". + base_path = gyp.common.RelativePath(os.path.dirname(build_file), + options.depth) + # We write the file in the base_path directory. + output_file = os.path.join(options.depth, base_path, base_name) + if options.generator_output: + output_file = os.path.join( + options.depth, options.generator_output, base_path, base_name) + base_path = gyp.common.RelativePath(os.path.dirname(build_file), + options.toplevel_dir) + return base_path, output_file + + # TODO: search for the first non-'Default' target. This can go + # away when we add verification that all targets have the + # necessary configurations. + default_configuration = None + toolsets = set([target_dicts[target]['toolset'] for target in target_list]) + for target in target_list: + spec = target_dicts[target] + if spec['default_configuration'] != 'Default': + default_configuration = spec['default_configuration'] + break + if not default_configuration: + default_configuration = 'Default' + + srcdir = '.' + makefile_name = 'Makefile' + options.suffix + makefile_path = os.path.join(options.toplevel_dir, makefile_name) + if options.generator_output: + global srcdir_prefix + makefile_path = os.path.join( + options.toplevel_dir, options.generator_output, makefile_name) + srcdir = gyp.common.RelativePath(srcdir, options.generator_output) + srcdir_prefix = '$(srcdir)/' + + flock_command= 'flock' + header_params = { + 'default_target': default_target, + 'builddir': builddir_name, + 'default_configuration': default_configuration, + 'flock': flock_command, + 'flock_index': 1, + 'link_commands': LINK_COMMANDS_LINUX, + 'extra_commands': '', + 'srcdir': srcdir, + } + if flavor == 'mac': + flock_command = './gyp-mac-tool flock' + header_params.update({ + 'flock': flock_command, + 'flock_index': 2, + 'link_commands': LINK_COMMANDS_MAC, + 'extra_commands': SHARED_HEADER_MAC_COMMANDS, + }) + elif flavor == 'android': + header_params.update({ + 'link_commands': LINK_COMMANDS_ANDROID, + }) + elif flavor == 'solaris': + header_params.update({ + 'flock': './gyp-flock-tool flock', + 'flock_index': 2, + }) + elif flavor == 'freebsd': + # Note: OpenBSD has sysutils/flock. lockf seems to be FreeBSD specific. + header_params.update({ + 'flock': 'lockf', + }) + elif flavor == 'aix': + header_params.update({ + 'link_commands': LINK_COMMANDS_AIX, + 'flock': './gyp-flock-tool flock', + 'flock_index': 2, + }) + + header_params.update({ + 'CC.target': GetEnvironFallback(('CC_target', 'CC'), '$(CC)'), + 'AR.target': GetEnvironFallback(('AR_target', 'AR'), '$(AR)'), + 'CXX.target': GetEnvironFallback(('CXX_target', 'CXX'), '$(CXX)'), + 'LINK.target': GetEnvironFallback(('LINK_target', 'LINK'), '$(LINK)'), + 'CC.host': GetEnvironFallback(('CC_host',), 'gcc'), + 'AR.host': GetEnvironFallback(('AR_host',), 'ar'), + 'CXX.host': GetEnvironFallback(('CXX_host',), 'g++'), + 'LINK.host': GetEnvironFallback(('LINK_host',), '$(CXX.host)'), + }) + + build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) + make_global_settings_array = data[build_file].get('make_global_settings', []) + wrappers = {} + wrappers['LINK'] = '%s $(builddir)/linker.lock' % flock_command + for key, value in make_global_settings_array: + if key.endswith('_wrapper'): + wrappers[key[:-len('_wrapper')]] = '$(abspath %s)' % value + make_global_settings = '' + for key, value in make_global_settings_array: + if re.match('.*_wrapper', key): + continue + if value[0] != '$': + value = '$(abspath %s)' % value + wrapper = wrappers.get(key) + if wrapper: + value = '%s %s' % (wrapper, value) + del wrappers[key] + if key in ('CC', 'CC.host', 'CXX', 'CXX.host'): + make_global_settings += ( + 'ifneq (,$(filter $(origin %s), undefined default))\n' % key) + # Let gyp-time envvars win over global settings. + env_key = key.replace('.', '_') # CC.host -> CC_host + if env_key in os.environ: + value = os.environ[env_key] + make_global_settings += ' %s = %s\n' % (key, value) + make_global_settings += 'endif\n' + else: + make_global_settings += '%s ?= %s\n' % (key, value) + # TODO(ukai): define cmd when only wrapper is specified in + # make_global_settings. + + header_params['make_global_settings'] = make_global_settings + + gyp.common.EnsureDirExists(makefile_path) + root_makefile = open(makefile_path, 'w') + root_makefile.write(SHARED_HEADER % header_params) + # Currently any versions have the same effect, but in future the behavior + # could be different. + if android_ndk_version: + root_makefile.write( + '# Define LOCAL_PATH for build of Android applications.\n' + 'LOCAL_PATH := $(call my-dir)\n' + '\n') + for toolset in toolsets: + root_makefile.write('TOOLSET := %s\n' % toolset) + WriteRootHeaderSuffixRules(root_makefile) + + # Put build-time support tools next to the root Makefile. + dest_path = os.path.dirname(makefile_path) + gyp.common.CopyTool(flavor, dest_path) + + # Find the list of targets that derive from the gyp file(s) being built. + needed_targets = set() + for build_file in params['build_files']: + for target in gyp.common.AllTargets(target_list, target_dicts, build_file): + needed_targets.add(target) + + build_files = set() + include_list = set() + for qualified_target in target_list: + build_file, target, toolset = gyp.common.ParseQualifiedTarget( + qualified_target) + + this_make_global_settings = data[build_file].get('make_global_settings', []) + assert make_global_settings_array == this_make_global_settings, ( + "make_global_settings needs to be the same for all targets. %s vs. %s" % + (this_make_global_settings, make_global_settings)) + + build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir)) + included_files = data[build_file]['included_files'] + for included_file in included_files: + # The included_files entries are relative to the dir of the build file + # that included them, so we have to undo that and then make them relative + # to the root dir. + relative_include_file = gyp.common.RelativePath( + gyp.common.UnrelativePath(included_file, build_file), + options.toplevel_dir) + abs_include_file = os.path.abspath(relative_include_file) + # If the include file is from the ~/.gyp dir, we should use absolute path + # so that relocating the src dir doesn't break the path. + if (params['home_dot_gyp'] and + abs_include_file.startswith(params['home_dot_gyp'])): + build_files.add(abs_include_file) + else: + build_files.add(relative_include_file) + + base_path, output_file = CalculateMakefilePath(build_file, + target + '.' + toolset + options.suffix + '.mk') + + spec = target_dicts[qualified_target] + configs = spec['configurations'] + + if flavor == 'mac': + gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec) + + writer = MakefileWriter(generator_flags, flavor) + writer.Write(qualified_target, base_path, output_file, spec, configs, + part_of_all=qualified_target in needed_targets) + + # Our root_makefile lives at the source root. Compute the relative path + # from there to the output_file for including. + mkfile_rel_path = gyp.common.RelativePath(output_file, + os.path.dirname(makefile_path)) + include_list.add(mkfile_rel_path) + + # Write out per-gyp (sub-project) Makefiles. + depth_rel_path = gyp.common.RelativePath(options.depth, os.getcwd()) + for build_file in build_files: + # The paths in build_files were relativized above, so undo that before + # testing against the non-relativized items in target_list and before + # calculating the Makefile path. + build_file = os.path.join(depth_rel_path, build_file) + gyp_targets = [target_dicts[target]['target_name'] for target in target_list + if target.startswith(build_file) and + target in needed_targets] + # Only generate Makefiles for gyp files with targets. + if not gyp_targets: + continue + base_path, output_file = CalculateMakefilePath(build_file, + os.path.splitext(os.path.basename(build_file))[0] + '.Makefile') + makefile_rel_path = gyp.common.RelativePath(os.path.dirname(makefile_path), + os.path.dirname(output_file)) + writer.WriteSubMake(output_file, makefile_rel_path, gyp_targets, + builddir_name) + + + # Write out the sorted list of includes. + root_makefile.write('\n') + for include_file in sorted(include_list): + # We wrap each .mk include in an if statement so users can tell make to + # not load a file by setting NO_LOAD. The below make code says, only + # load the .mk file if the .mk filename doesn't start with a token in + # NO_LOAD. + root_makefile.write( + "ifeq ($(strip $(foreach prefix,$(NO_LOAD),\\\n" + " $(findstring $(join ^,$(prefix)),\\\n" + " $(join ^," + include_file + ")))),)\n") + root_makefile.write(" include " + include_file + "\n") + root_makefile.write("endif\n") + root_makefile.write('\n') + + if (not generator_flags.get('standalone') + and generator_flags.get('auto_regeneration', True)): + WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files) + + root_makefile.write(SHARED_FOOTER) + + root_makefile.close() diff --git a/deps/gyp/pylib/gyp/generator/msvs.py b/deps/gyp/pylib/gyp/generator/msvs.py new file mode 100644 index 000000000..64991d424 --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/msvs.py @@ -0,0 +1,3319 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import copy +import ntpath +import os +import posixpath +import re +import subprocess +import sys + +import gyp.common +import gyp.easy_xml as easy_xml +import gyp.MSVSNew as MSVSNew +import gyp.MSVSProject as MSVSProject +import gyp.MSVSSettings as MSVSSettings +import gyp.MSVSToolFile as MSVSToolFile +import gyp.MSVSUserFile as MSVSUserFile +import gyp.MSVSUtil as MSVSUtil +import gyp.MSVSVersion as MSVSVersion +from gyp.common import GypError +from gyp.common import OrderedSet + +# TODO: Remove once bots are on 2.7, http://crbug.com/241769 +def _import_OrderedDict(): + import collections + try: + return collections.OrderedDict + except AttributeError: + import gyp.ordered_dict + return gyp.ordered_dict.OrderedDict +OrderedDict = _import_OrderedDict() + + +# Regular expression for validating Visual Studio GUIDs. If the GUID +# contains lowercase hex letters, MSVS will be fine. However, +# IncrediBuild BuildConsole will parse the solution file, but then +# silently skip building the target causing hard to track down errors. +# Note that this only happens with the BuildConsole, and does not occur +# if IncrediBuild is executed from inside Visual Studio. This regex +# validates that the string looks like a GUID with all uppercase hex +# letters. +VALID_MSVS_GUID_CHARS = re.compile('^[A-F0-9\-]+$') + + +generator_default_variables = { + 'EXECUTABLE_PREFIX': '', + 'EXECUTABLE_SUFFIX': '.exe', + 'STATIC_LIB_PREFIX': '', + 'SHARED_LIB_PREFIX': '', + 'STATIC_LIB_SUFFIX': '.lib', + 'SHARED_LIB_SUFFIX': '.dll', + 'INTERMEDIATE_DIR': '$(IntDir)', + 'SHARED_INTERMEDIATE_DIR': '$(OutDir)obj/global_intermediate', + 'OS': 'win', + 'PRODUCT_DIR': '$(OutDir)', + 'LIB_DIR': '$(OutDir)lib', + 'RULE_INPUT_ROOT': '$(InputName)', + 'RULE_INPUT_DIRNAME': '$(InputDir)', + 'RULE_INPUT_EXT': '$(InputExt)', + 'RULE_INPUT_NAME': '$(InputFileName)', + 'RULE_INPUT_PATH': '$(InputPath)', + 'CONFIGURATION_NAME': '$(ConfigurationName)', +} + + +# The msvs specific sections that hold paths +generator_additional_path_sections = [ + 'msvs_cygwin_dirs', + 'msvs_props', +] + + +generator_additional_non_configuration_keys = [ + 'msvs_cygwin_dirs', + 'msvs_cygwin_shell', + 'msvs_large_pdb', + 'msvs_shard', + 'msvs_external_builder', + 'msvs_external_builder_out_dir', + 'msvs_external_builder_build_cmd', + 'msvs_external_builder_clean_cmd', + 'msvs_external_builder_clcompile_cmd', +] + + +# List of precompiled header related keys. +precomp_keys = [ + 'msvs_precompiled_header', + 'msvs_precompiled_source', +] + + +cached_username = None + + +cached_domain = None + + +# TODO(gspencer): Switch the os.environ calls to be +# win32api.GetDomainName() and win32api.GetUserName() once the +# python version in depot_tools has been updated to work on Vista +# 64-bit. +def _GetDomainAndUserName(): + if sys.platform not in ('win32', 'cygwin'): + return ('DOMAIN', 'USERNAME') + global cached_username + global cached_domain + if not cached_domain or not cached_username: + domain = os.environ.get('USERDOMAIN') + username = os.environ.get('USERNAME') + if not domain or not username: + call = subprocess.Popen(['net', 'config', 'Workstation'], + stdout=subprocess.PIPE) + config = call.communicate()[0] + username_re = re.compile('^User name\s+(\S+)', re.MULTILINE) + username_match = username_re.search(config) + if username_match: + username = username_match.group(1) + domain_re = re.compile('^Logon domain\s+(\S+)', re.MULTILINE) + domain_match = domain_re.search(config) + if domain_match: + domain = domain_match.group(1) + cached_domain = domain + cached_username = username + return (cached_domain, cached_username) + +fixpath_prefix = None + + +def _NormalizedSource(source): + """Normalize the path. + + But not if that gets rid of a variable, as this may expand to something + larger than one directory. + + Arguments: + source: The path to be normalize.d + + Returns: + The normalized path. + """ + normalized = os.path.normpath(source) + if source.count('$') == normalized.count('$'): + source = normalized + return source + + +def _FixPath(path): + """Convert paths to a form that will make sense in a vcproj file. + + Arguments: + path: The path to convert, may contain / etc. + Returns: + The path with all slashes made into backslashes. + """ + if fixpath_prefix and path and not os.path.isabs(path) and not path[0] == '$': + path = os.path.join(fixpath_prefix, path) + path = path.replace('/', '\\') + path = _NormalizedSource(path) + if path and path[-1] == '\\': + path = path[:-1] + return path + + +def _FixPaths(paths): + """Fix each of the paths of the list.""" + return [_FixPath(i) for i in paths] + + +def _ConvertSourcesToFilterHierarchy(sources, prefix=None, excluded=None, + list_excluded=True, msvs_version=None): + """Converts a list split source file paths into a vcproj folder hierarchy. + + Arguments: + sources: A list of source file paths split. + prefix: A list of source file path layers meant to apply to each of sources. + excluded: A set of excluded files. + msvs_version: A MSVSVersion object. + + Returns: + A hierarchy of filenames and MSVSProject.Filter objects that matches the + layout of the source tree. + For example: + _ConvertSourcesToFilterHierarchy([['a', 'bob1.c'], ['b', 'bob2.c']], + prefix=['joe']) + --> + [MSVSProject.Filter('a', contents=['joe\\a\\bob1.c']), + MSVSProject.Filter('b', contents=['joe\\b\\bob2.c'])] + """ + if not prefix: prefix = [] + result = [] + excluded_result = [] + folders = OrderedDict() + # Gather files into the final result, excluded, or folders. + for s in sources: + if len(s) == 1: + filename = _NormalizedSource('\\'.join(prefix + s)) + if filename in excluded: + excluded_result.append(filename) + else: + result.append(filename) + elif msvs_version and not msvs_version.UsesVcxproj(): + # For MSVS 2008 and earlier, we need to process all files before walking + # the sub folders. + if not folders.get(s[0]): + folders[s[0]] = [] + folders[s[0]].append(s[1:]) + else: + contents = _ConvertSourcesToFilterHierarchy([s[1:]], prefix + [s[0]], + excluded=excluded, + list_excluded=list_excluded, + msvs_version=msvs_version) + contents = MSVSProject.Filter(s[0], contents=contents) + result.append(contents) + # Add a folder for excluded files. + if excluded_result and list_excluded: + excluded_folder = MSVSProject.Filter('_excluded_files', + contents=excluded_result) + result.append(excluded_folder) + + if msvs_version and msvs_version.UsesVcxproj(): + return result + + # Populate all the folders. + for f in folders: + contents = _ConvertSourcesToFilterHierarchy(folders[f], prefix=prefix + [f], + excluded=excluded, + list_excluded=list_excluded, + msvs_version=msvs_version) + contents = MSVSProject.Filter(f, contents=contents) + result.append(contents) + return result + + +def _ToolAppend(tools, tool_name, setting, value, only_if_unset=False): + if not value: return + _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset) + + +def _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset=False): + # TODO(bradnelson): ugly hack, fix this more generally!!! + if 'Directories' in setting or 'Dependencies' in setting: + if type(value) == str: + value = value.replace('/', '\\') + else: + value = [i.replace('/', '\\') for i in value] + if not tools.get(tool_name): + tools[tool_name] = dict() + tool = tools[tool_name] + if tool.get(setting): + if only_if_unset: return + if type(tool[setting]) == list and type(value) == list: + tool[setting] += value + else: + raise TypeError( + 'Appending "%s" to a non-list setting "%s" for tool "%s" is ' + 'not allowed, previous value: %s' % ( + value, setting, tool_name, str(tool[setting]))) + else: + tool[setting] = value + + +def _ConfigPlatform(config_data): + return config_data.get('msvs_configuration_platform', 'Win32') + + +def _ConfigBaseName(config_name, platform_name): + if config_name.endswith('_' + platform_name): + return config_name[0:-len(platform_name) - 1] + else: + return config_name + + +def _ConfigFullName(config_name, config_data): + platform_name = _ConfigPlatform(config_data) + return '%s|%s' % (_ConfigBaseName(config_name, platform_name), platform_name) + + +def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path, + quote_cmd, do_setup_env): + + if [x for x in cmd if '$(InputDir)' in x]: + input_dir_preamble = ( + 'set INPUTDIR=$(InputDir)\n' + 'set INPUTDIR=%INPUTDIR:$(ProjectDir)=%\n' + 'set INPUTDIR=%INPUTDIR:~0,-1%\n' + ) + else: + input_dir_preamble = '' + + if cygwin_shell: + # Find path to cygwin. + cygwin_dir = _FixPath(spec.get('msvs_cygwin_dirs', ['.'])[0]) + # Prepare command. + direct_cmd = cmd + direct_cmd = [i.replace('$(IntDir)', + '`cygpath -m "${INTDIR}"`') for i in direct_cmd] + direct_cmd = [i.replace('$(OutDir)', + '`cygpath -m "${OUTDIR}"`') for i in direct_cmd] + direct_cmd = [i.replace('$(InputDir)', + '`cygpath -m "${INPUTDIR}"`') for i in direct_cmd] + if has_input_path: + direct_cmd = [i.replace('$(InputPath)', + '`cygpath -m "${INPUTPATH}"`') + for i in direct_cmd] + direct_cmd = ['\\"%s\\"' % i.replace('"', '\\\\\\"') for i in direct_cmd] + # direct_cmd = gyp.common.EncodePOSIXShellList(direct_cmd) + direct_cmd = ' '.join(direct_cmd) + # TODO(quote): regularize quoting path names throughout the module + cmd = '' + if do_setup_env: + cmd += 'call "$(ProjectDir)%(cygwin_dir)s\\setup_env.bat" && ' + cmd += 'set CYGWIN=nontsec&& ' + if direct_cmd.find('NUMBER_OF_PROCESSORS') >= 0: + cmd += 'set /a NUMBER_OF_PROCESSORS_PLUS_1=%%NUMBER_OF_PROCESSORS%%+1&& ' + if direct_cmd.find('INTDIR') >= 0: + cmd += 'set INTDIR=$(IntDir)&& ' + if direct_cmd.find('OUTDIR') >= 0: + cmd += 'set OUTDIR=$(OutDir)&& ' + if has_input_path and direct_cmd.find('INPUTPATH') >= 0: + cmd += 'set INPUTPATH=$(InputPath) && ' + cmd += 'bash -c "%(cmd)s"' + cmd = cmd % {'cygwin_dir': cygwin_dir, + 'cmd': direct_cmd} + return input_dir_preamble + cmd + else: + # Convert cat --> type to mimic unix. + if cmd[0] == 'cat': + command = ['type'] + else: + command = [cmd[0].replace('/', '\\')] + # Add call before command to ensure that commands can be tied together one + # after the other without aborting in Incredibuild, since IB makes a bat + # file out of the raw command string, and some commands (like python) are + # actually batch files themselves. + command.insert(0, 'call') + # Fix the paths + # TODO(quote): This is a really ugly heuristic, and will miss path fixing + # for arguments like "--arg=path" or "/opt:path". + # If the argument starts with a slash or dash, it's probably a command line + # switch + arguments = [i if (i[:1] in "/-") else _FixPath(i) for i in cmd[1:]] + arguments = [i.replace('$(InputDir)', '%INPUTDIR%') for i in arguments] + arguments = [MSVSSettings.FixVCMacroSlashes(i) for i in arguments] + if quote_cmd: + # Support a mode for using cmd directly. + # Convert any paths to native form (first element is used directly). + # TODO(quote): regularize quoting path names throughout the module + arguments = ['"%s"' % i for i in arguments] + # Collapse into a single command. + return input_dir_preamble + ' '.join(command + arguments) + + +def _BuildCommandLineForRule(spec, rule, has_input_path, do_setup_env): + # Currently this weird argument munging is used to duplicate the way a + # python script would need to be run as part of the chrome tree. + # Eventually we should add some sort of rule_default option to set this + # per project. For now the behavior chrome needs is the default. + mcs = rule.get('msvs_cygwin_shell') + if mcs is None: + mcs = int(spec.get('msvs_cygwin_shell', 1)) + elif isinstance(mcs, str): + mcs = int(mcs) + quote_cmd = int(rule.get('msvs_quote_cmd', 1)) + return _BuildCommandLineForRuleRaw(spec, rule['action'], mcs, has_input_path, + quote_cmd, do_setup_env=do_setup_env) + + +def _AddActionStep(actions_dict, inputs, outputs, description, command): + """Merge action into an existing list of actions. + + Care must be taken so that actions which have overlapping inputs either don't + get assigned to the same input, or get collapsed into one. + + Arguments: + actions_dict: dictionary keyed on input name, which maps to a list of + dicts describing the actions attached to that input file. + inputs: list of inputs + outputs: list of outputs + description: description of the action + command: command line to execute + """ + # Require there to be at least one input (call sites will ensure this). + assert inputs + + action = { + 'inputs': inputs, + 'outputs': outputs, + 'description': description, + 'command': command, + } + + # Pick where to stick this action. + # While less than optimal in terms of build time, attach them to the first + # input for now. + chosen_input = inputs[0] + + # Add it there. + if chosen_input not in actions_dict: + actions_dict[chosen_input] = [] + actions_dict[chosen_input].append(action) + + +def _AddCustomBuildToolForMSVS(p, spec, primary_input, + inputs, outputs, description, cmd): + """Add a custom build tool to execute something. + + Arguments: + p: the target project + spec: the target project dict + primary_input: input file to attach the build tool to + inputs: list of inputs + outputs: list of outputs + description: description of the action + cmd: command line to execute + """ + inputs = _FixPaths(inputs) + outputs = _FixPaths(outputs) + tool = MSVSProject.Tool( + 'VCCustomBuildTool', + {'Description': description, + 'AdditionalDependencies': ';'.join(inputs), + 'Outputs': ';'.join(outputs), + 'CommandLine': cmd, + }) + # Add to the properties of primary input for each config. + for config_name, c_data in spec['configurations'].iteritems(): + p.AddFileConfig(_FixPath(primary_input), + _ConfigFullName(config_name, c_data), tools=[tool]) + + +def _AddAccumulatedActionsToMSVS(p, spec, actions_dict): + """Add actions accumulated into an actions_dict, merging as needed. + + Arguments: + p: the target project + spec: the target project dict + actions_dict: dictionary keyed on input name, which maps to a list of + dicts describing the actions attached to that input file. + """ + for primary_input in actions_dict: + inputs = OrderedSet() + outputs = OrderedSet() + descriptions = [] + commands = [] + for action in actions_dict[primary_input]: + inputs.update(OrderedSet(action['inputs'])) + outputs.update(OrderedSet(action['outputs'])) + descriptions.append(action['description']) + commands.append(action['command']) + # Add the custom build step for one input file. + description = ', and also '.join(descriptions) + command = '\r\n'.join(commands) + _AddCustomBuildToolForMSVS(p, spec, + primary_input=primary_input, + inputs=inputs, + outputs=outputs, + description=description, + cmd=command) + + +def _RuleExpandPath(path, input_file): + """Given the input file to which a rule applied, string substitute a path. + + Arguments: + path: a path to string expand + input_file: the file to which the rule applied. + Returns: + The string substituted path. + """ + path = path.replace('$(InputName)', + os.path.splitext(os.path.split(input_file)[1])[0]) + path = path.replace('$(InputDir)', os.path.dirname(input_file)) + path = path.replace('$(InputExt)', + os.path.splitext(os.path.split(input_file)[1])[1]) + path = path.replace('$(InputFileName)', os.path.split(input_file)[1]) + path = path.replace('$(InputPath)', input_file) + return path + + +def _FindRuleTriggerFiles(rule, sources): + """Find the list of files which a particular rule applies to. + + Arguments: + rule: the rule in question + sources: the set of all known source files for this project + Returns: + The list of sources that trigger a particular rule. + """ + return rule.get('rule_sources', []) + + +def _RuleInputsAndOutputs(rule, trigger_file): + """Find the inputs and outputs generated by a rule. + + Arguments: + rule: the rule in question. + trigger_file: the main trigger for this rule. + Returns: + The pair of (inputs, outputs) involved in this rule. + """ + raw_inputs = _FixPaths(rule.get('inputs', [])) + raw_outputs = _FixPaths(rule.get('outputs', [])) + inputs = OrderedSet() + outputs = OrderedSet() + inputs.add(trigger_file) + for i in raw_inputs: + inputs.add(_RuleExpandPath(i, trigger_file)) + for o in raw_outputs: + outputs.add(_RuleExpandPath(o, trigger_file)) + return (inputs, outputs) + + +def _GenerateNativeRulesForMSVS(p, rules, output_dir, spec, options): + """Generate a native rules file. + + Arguments: + p: the target project + rules: the set of rules to include + output_dir: the directory in which the project/gyp resides + spec: the project dict + options: global generator options + """ + rules_filename = '%s%s.rules' % (spec['target_name'], + options.suffix) + rules_file = MSVSToolFile.Writer(os.path.join(output_dir, rules_filename), + spec['target_name']) + # Add each rule. + for r in rules: + rule_name = r['rule_name'] + rule_ext = r['extension'] + inputs = _FixPaths(r.get('inputs', [])) + outputs = _FixPaths(r.get('outputs', [])) + # Skip a rule with no action and no inputs. + if 'action' not in r and not r.get('rule_sources', []): + continue + cmd = _BuildCommandLineForRule(spec, r, has_input_path=True, + do_setup_env=True) + rules_file.AddCustomBuildRule(name=rule_name, + description=r.get('message', rule_name), + extensions=[rule_ext], + additional_dependencies=inputs, + outputs=outputs, + cmd=cmd) + # Write out rules file. + rules_file.WriteIfChanged() + + # Add rules file to project. + p.AddToolFile(rules_filename) + + +def _Cygwinify(path): + path = path.replace('$(OutDir)', '$(OutDirCygwin)') + path = path.replace('$(IntDir)', '$(IntDirCygwin)') + return path + + +def _GenerateExternalRules(rules, output_dir, spec, + sources, options, actions_to_add): + """Generate an external makefile to do a set of rules. + + Arguments: + rules: the list of rules to include + output_dir: path containing project and gyp files + spec: project specification data + sources: set of sources known + options: global generator options + actions_to_add: The list of actions we will add to. + """ + filename = '%s_rules%s.mk' % (spec['target_name'], options.suffix) + mk_file = gyp.common.WriteOnDiff(os.path.join(output_dir, filename)) + # Find cygwin style versions of some paths. + mk_file.write('OutDirCygwin:=$(shell cygpath -u "$(OutDir)")\n') + mk_file.write('IntDirCygwin:=$(shell cygpath -u "$(IntDir)")\n') + # Gather stuff needed to emit all: target. + all_inputs = OrderedSet() + all_outputs = OrderedSet() + all_output_dirs = OrderedSet() + first_outputs = [] + for rule in rules: + trigger_files = _FindRuleTriggerFiles(rule, sources) + for tf in trigger_files: + inputs, outputs = _RuleInputsAndOutputs(rule, tf) + all_inputs.update(OrderedSet(inputs)) + all_outputs.update(OrderedSet(outputs)) + # Only use one target from each rule as the dependency for + # 'all' so we don't try to build each rule multiple times. + first_outputs.append(list(outputs)[0]) + # Get the unique output directories for this rule. + output_dirs = [os.path.split(i)[0] for i in outputs] + for od in output_dirs: + all_output_dirs.add(od) + first_outputs_cyg = [_Cygwinify(i) for i in first_outputs] + # Write out all: target, including mkdir for each output directory. + mk_file.write('all: %s\n' % ' '.join(first_outputs_cyg)) + for od in all_output_dirs: + if od: + mk_file.write('\tmkdir -p `cygpath -u "%s"`\n' % od) + mk_file.write('\n') + # Define how each output is generated. + for rule in rules: + trigger_files = _FindRuleTriggerFiles(rule, sources) + for tf in trigger_files: + # Get all the inputs and outputs for this rule for this trigger file. + inputs, outputs = _RuleInputsAndOutputs(rule, tf) + inputs = [_Cygwinify(i) for i in inputs] + outputs = [_Cygwinify(i) for i in outputs] + # Prepare the command line for this rule. + cmd = [_RuleExpandPath(c, tf) for c in rule['action']] + cmd = ['"%s"' % i for i in cmd] + cmd = ' '.join(cmd) + # Add it to the makefile. + mk_file.write('%s: %s\n' % (' '.join(outputs), ' '.join(inputs))) + mk_file.write('\t%s\n\n' % cmd) + # Close up the file. + mk_file.close() + + # Add makefile to list of sources. + sources.add(filename) + # Add a build action to call makefile. + cmd = ['make', + 'OutDir=$(OutDir)', + 'IntDir=$(IntDir)', + '-j', '${NUMBER_OF_PROCESSORS_PLUS_1}', + '-f', filename] + cmd = _BuildCommandLineForRuleRaw(spec, cmd, True, False, True, True) + # Insert makefile as 0'th input, so it gets the action attached there, + # as this is easier to understand from in the IDE. + all_inputs = list(all_inputs) + all_inputs.insert(0, filename) + _AddActionStep(actions_to_add, + inputs=_FixPaths(all_inputs), + outputs=_FixPaths(all_outputs), + description='Running external rules for %s' % + spec['target_name'], + command=cmd) + + +def _EscapeEnvironmentVariableExpansion(s): + """Escapes % characters. + + Escapes any % characters so that Windows-style environment variable + expansions will leave them alone. + See http://connect.microsoft.com/VisualStudio/feedback/details/106127/cl-d-name-text-containing-percentage-characters-doesnt-compile + to understand why we have to do this. + + Args: + s: The string to be escaped. + + Returns: + The escaped string. + """ + s = s.replace('%', '%%') + return s + + +quote_replacer_regex = re.compile(r'(\\*)"') + + +def _EscapeCommandLineArgumentForMSVS(s): + """Escapes a Windows command-line argument. + + So that the Win32 CommandLineToArgv function will turn the escaped result back + into the original string. + See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx + ("Parsing C++ Command-Line Arguments") to understand why we have to do + this. + + Args: + s: the string to be escaped. + Returns: + the escaped string. + """ + + def _Replace(match): + # For a literal quote, CommandLineToArgv requires an odd number of + # backslashes preceding it, and it produces half as many literal backslashes + # (rounded down). So we need to produce 2n+1 backslashes. + return 2 * match.group(1) + '\\"' + + # Escape all quotes so that they are interpreted literally. + s = quote_replacer_regex.sub(_Replace, s) + # Now add unescaped quotes so that any whitespace is interpreted literally. + s = '"' + s + '"' + return s + + +delimiters_replacer_regex = re.compile(r'(\\*)([,;]+)') + + +def _EscapeVCProjCommandLineArgListItem(s): + """Escapes command line arguments for MSVS. + + The VCProj format stores string lists in a single string using commas and + semi-colons as separators, which must be quoted if they are to be + interpreted literally. However, command-line arguments may already have + quotes, and the VCProj parser is ignorant of the backslash escaping + convention used by CommandLineToArgv, so the command-line quotes and the + VCProj quotes may not be the same quotes. So to store a general + command-line argument in a VCProj list, we need to parse the existing + quoting according to VCProj's convention and quote any delimiters that are + not already quoted by that convention. The quotes that we add will also be + seen by CommandLineToArgv, so if backslashes precede them then we also have + to escape those backslashes according to the CommandLineToArgv + convention. + + Args: + s: the string to be escaped. + Returns: + the escaped string. + """ + + def _Replace(match): + # For a non-literal quote, CommandLineToArgv requires an even number of + # backslashes preceding it, and it produces half as many literal + # backslashes. So we need to produce 2n backslashes. + return 2 * match.group(1) + '"' + match.group(2) + '"' + + segments = s.split('"') + # The unquoted segments are at the even-numbered indices. + for i in range(0, len(segments), 2): + segments[i] = delimiters_replacer_regex.sub(_Replace, segments[i]) + # Concatenate back into a single string + s = '"'.join(segments) + if len(segments) % 2 == 0: + # String ends while still quoted according to VCProj's convention. This + # means the delimiter and the next list item that follow this one in the + # .vcproj file will be misinterpreted as part of this item. There is nothing + # we can do about this. Adding an extra quote would correct the problem in + # the VCProj but cause the same problem on the final command-line. Moving + # the item to the end of the list does works, but that's only possible if + # there's only one such item. Let's just warn the user. + print >> sys.stderr, ('Warning: MSVS may misinterpret the odd number of ' + + 'quotes in ' + s) + return s + + +def _EscapeCppDefineForMSVS(s): + """Escapes a CPP define so that it will reach the compiler unaltered.""" + s = _EscapeEnvironmentVariableExpansion(s) + s = _EscapeCommandLineArgumentForMSVS(s) + s = _EscapeVCProjCommandLineArgListItem(s) + # cl.exe replaces literal # characters with = in preprocesor definitions for + # some reason. Octal-encode to work around that. + s = s.replace('#', '\\%03o' % ord('#')) + return s + + +quote_replacer_regex2 = re.compile(r'(\\+)"') + + +def _EscapeCommandLineArgumentForMSBuild(s): + """Escapes a Windows command-line argument for use by MSBuild.""" + + def _Replace(match): + return (len(match.group(1)) / 2 * 4) * '\\' + '\\"' + + # Escape all quotes so that they are interpreted literally. + s = quote_replacer_regex2.sub(_Replace, s) + return s + + +def _EscapeMSBuildSpecialCharacters(s): + escape_dictionary = { + '%': '%25', + '$': '%24', + '@': '%40', + "'": '%27', + ';': '%3B', + '?': '%3F', + '*': '%2A' + } + result = ''.join([escape_dictionary.get(c, c) for c in s]) + return result + + +def _EscapeCppDefineForMSBuild(s): + """Escapes a CPP define so that it will reach the compiler unaltered.""" + s = _EscapeEnvironmentVariableExpansion(s) + s = _EscapeCommandLineArgumentForMSBuild(s) + s = _EscapeMSBuildSpecialCharacters(s) + # cl.exe replaces literal # characters with = in preprocesor definitions for + # some reason. Octal-encode to work around that. + s = s.replace('#', '\\%03o' % ord('#')) + return s + + +def _GenerateRulesForMSVS(p, output_dir, options, spec, + sources, excluded_sources, + actions_to_add): + """Generate all the rules for a particular project. + + Arguments: + p: the project + output_dir: directory to emit rules to + options: global options passed to the generator + spec: the specification for this project + sources: the set of all known source files in this project + excluded_sources: the set of sources excluded from normal processing + actions_to_add: deferred list of actions to add in + """ + rules = spec.get('rules', []) + rules_native = [r for r in rules if not int(r.get('msvs_external_rule', 0))] + rules_external = [r for r in rules if int(r.get('msvs_external_rule', 0))] + + # Handle rules that use a native rules file. + if rules_native: + _GenerateNativeRulesForMSVS(p, rules_native, output_dir, spec, options) + + # Handle external rules (non-native rules). + if rules_external: + _GenerateExternalRules(rules_external, output_dir, spec, + sources, options, actions_to_add) + _AdjustSourcesForRules(spec, rules, sources, excluded_sources) + + +def _AdjustSourcesForRules(spec, rules, sources, excluded_sources): + # Add outputs generated by each rule (if applicable). + for rule in rules: + # Add in the outputs from this rule. + trigger_files = _FindRuleTriggerFiles(rule, sources) + for trigger_file in trigger_files: + # Remove trigger_file from excluded_sources to let the rule be triggered + # (e.g. rule trigger ax_enums.idl is added to excluded_sources + # because it's also in an action's inputs in the same project) + excluded_sources.discard(_FixPath(trigger_file)) + # Done if not processing outputs as sources. + if int(rule.get('process_outputs_as_sources', False)): + inputs, outputs = _RuleInputsAndOutputs(rule, trigger_file) + inputs = OrderedSet(_FixPaths(inputs)) + outputs = OrderedSet(_FixPaths(outputs)) + inputs.remove(_FixPath(trigger_file)) + sources.update(inputs) + if spec['type'] != 'none' and not spec.get('msvs_external_builder'): + excluded_sources.update(inputs) + sources.update(outputs) + + +def _FilterActionsFromExcluded(excluded_sources, actions_to_add): + """Take inputs with actions attached out of the list of exclusions. + + Arguments: + excluded_sources: list of source files not to be built. + actions_to_add: dict of actions keyed on source file they're attached to. + Returns: + excluded_sources with files that have actions attached removed. + """ + must_keep = OrderedSet(_FixPaths(actions_to_add.keys())) + return [s for s in excluded_sources if s not in must_keep] + + +def _GetDefaultConfiguration(spec): + return spec['configurations'][spec['default_configuration']] + + +def _GetGuidOfProject(proj_path, spec): + """Get the guid for the project. + + Arguments: + proj_path: Path of the vcproj or vcxproj file to generate. + spec: The target dictionary containing the properties of the target. + Returns: + the guid. + Raises: + ValueError: if the specified GUID is invalid. + """ + # Pluck out the default configuration. + default_config = _GetDefaultConfiguration(spec) + # Decide the guid of the project. + guid = default_config.get('msvs_guid') + if guid: + if VALID_MSVS_GUID_CHARS.match(guid) is None: + raise ValueError('Invalid MSVS guid: "%s". Must match regex: "%s".' % + (guid, VALID_MSVS_GUID_CHARS.pattern)) + guid = '{%s}' % guid + guid = guid or MSVSNew.MakeGuid(proj_path) + return guid + + +def _GetMsbuildToolsetOfProject(proj_path, spec, version): + """Get the platform toolset for the project. + + Arguments: + proj_path: Path of the vcproj or vcxproj file to generate. + spec: The target dictionary containing the properties of the target. + version: The MSVSVersion object. + Returns: + the platform toolset string or None. + """ + # Pluck out the default configuration. + default_config = _GetDefaultConfiguration(spec) + toolset = default_config.get('msbuild_toolset') + if not toolset and version.DefaultToolset(): + toolset = version.DefaultToolset() + return toolset + + +def _GenerateProject(project, options, version, generator_flags): + """Generates a vcproj file. + + Arguments: + project: the MSVSProject object. + options: global generator options. + version: the MSVSVersion object. + generator_flags: dict of generator-specific flags. + Returns: + A list of source files that cannot be found on disk. + """ + default_config = _GetDefaultConfiguration(project.spec) + + # Skip emitting anything if told to with msvs_existing_vcproj option. + if default_config.get('msvs_existing_vcproj'): + return [] + + if version.UsesVcxproj(): + return _GenerateMSBuildProject(project, options, version, generator_flags) + else: + return _GenerateMSVSProject(project, options, version, generator_flags) + + +def _GenerateMSVSProject(project, options, version, generator_flags): + """Generates a .vcproj file. It may create .rules and .user files too. + + Arguments: + project: The project object we will generate the file for. + options: Global options passed to the generator. + version: The VisualStudioVersion object. + generator_flags: dict of generator-specific flags. + """ + spec = project.spec + gyp.common.EnsureDirExists(project.path) + + platforms = _GetUniquePlatforms(spec) + p = MSVSProject.Writer(project.path, version, spec['target_name'], + project.guid, platforms) + + # Get directory project file is in. + project_dir = os.path.split(project.path)[0] + gyp_path = _NormalizedSource(project.build_file) + relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, project_dir) + + config_type = _GetMSVSConfigurationType(spec, project.build_file) + for config_name, config in spec['configurations'].iteritems(): + _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config) + + # Prepare list of sources and excluded sources. + gyp_file = os.path.split(project.build_file)[1] + sources, excluded_sources = _PrepareListOfSources(spec, generator_flags, + gyp_file) + + # Add rules. + actions_to_add = {} + _GenerateRulesForMSVS(p, project_dir, options, spec, + sources, excluded_sources, + actions_to_add) + list_excluded = generator_flags.get('msvs_list_excluded_files', True) + sources, excluded_sources, excluded_idl = ( + _AdjustSourcesAndConvertToFilterHierarchy(spec, options, project_dir, + sources, excluded_sources, + list_excluded, version)) + + # Add in files. + missing_sources = _VerifySourcesExist(sources, project_dir) + p.AddFiles(sources) + + _AddToolFilesToMSVS(p, spec) + _HandlePreCompiledHeaders(p, sources, spec) + _AddActions(actions_to_add, spec, relative_path_of_gyp_file) + _AddCopies(actions_to_add, spec) + _WriteMSVSUserFile(project.path, version, spec) + + # NOTE: this stanza must appear after all actions have been decided. + # Don't excluded sources with actions attached, or they won't run. + excluded_sources = _FilterActionsFromExcluded( + excluded_sources, actions_to_add) + _ExcludeFilesFromBeingBuilt(p, spec, excluded_sources, excluded_idl, + list_excluded) + _AddAccumulatedActionsToMSVS(p, spec, actions_to_add) + + # Write it out. + p.WriteIfChanged() + + return missing_sources + + +def _GetUniquePlatforms(spec): + """Returns the list of unique platforms for this spec, e.g ['win32', ...]. + + Arguments: + spec: The target dictionary containing the properties of the target. + Returns: + The MSVSUserFile object created. + """ + # Gather list of unique platforms. + platforms = OrderedSet() + for configuration in spec['configurations']: + platforms.add(_ConfigPlatform(spec['configurations'][configuration])) + platforms = list(platforms) + return platforms + + +def _CreateMSVSUserFile(proj_path, version, spec): + """Generates a .user file for the user running this Gyp program. + + Arguments: + proj_path: The path of the project file being created. The .user file + shares the same path (with an appropriate suffix). + version: The VisualStudioVersion object. + spec: The target dictionary containing the properties of the target. + Returns: + The MSVSUserFile object created. + """ + (domain, username) = _GetDomainAndUserName() + vcuser_filename = '.'.join([proj_path, domain, username, 'user']) + user_file = MSVSUserFile.Writer(vcuser_filename, version, + spec['target_name']) + return user_file + + +def _GetMSVSConfigurationType(spec, build_file): + """Returns the configuration type for this project. + + It's a number defined by Microsoft. May raise an exception. + + Args: + spec: The target dictionary containing the properties of the target. + build_file: The path of the gyp file. + Returns: + An integer, the configuration type. + """ + try: + config_type = { + 'executable': '1', # .exe + 'shared_library': '2', # .dll + 'loadable_module': '2', # .dll + 'static_library': '4', # .lib + 'none': '10', # Utility type + }[spec['type']] + except KeyError: + if spec.get('type'): + raise GypError('Target type %s is not a valid target type for ' + 'target %s in %s.' % + (spec['type'], spec['target_name'], build_file)) + else: + raise GypError('Missing type field for target %s in %s.' % + (spec['target_name'], build_file)) + return config_type + + +def _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config): + """Adds a configuration to the MSVS project. + + Many settings in a vcproj file are specific to a configuration. This + function the main part of the vcproj file that's configuration specific. + + Arguments: + p: The target project being generated. + spec: The target dictionary containing the properties of the target. + config_type: The configuration type, a number as defined by Microsoft. + config_name: The name of the configuration. + config: The dictionary that defines the special processing to be done + for this configuration. + """ + # Get the information for this configuration + include_dirs, resource_include_dirs = _GetIncludeDirs(config) + libraries = _GetLibraries(spec) + library_dirs = _GetLibraryDirs(config) + out_file, vc_tool, _ = _GetOutputFilePathAndTool(spec, msbuild=False) + defines = _GetDefines(config) + defines = [_EscapeCppDefineForMSVS(d) for d in defines] + disabled_warnings = _GetDisabledWarnings(config) + prebuild = config.get('msvs_prebuild') + postbuild = config.get('msvs_postbuild') + def_file = _GetModuleDefinition(spec) + precompiled_header = config.get('msvs_precompiled_header') + + # Prepare the list of tools as a dictionary. + tools = dict() + # Add in user specified msvs_settings. + msvs_settings = config.get('msvs_settings', {}) + MSVSSettings.ValidateMSVSSettings(msvs_settings) + + # Prevent default library inheritance from the environment. + _ToolAppend(tools, 'VCLinkerTool', 'AdditionalDependencies', ['$(NOINHERIT)']) + + for tool in msvs_settings: + settings = config['msvs_settings'][tool] + for setting in settings: + _ToolAppend(tools, tool, setting, settings[setting]) + # Add the information to the appropriate tool + _ToolAppend(tools, 'VCCLCompilerTool', + 'AdditionalIncludeDirectories', include_dirs) + _ToolAppend(tools, 'VCResourceCompilerTool', + 'AdditionalIncludeDirectories', resource_include_dirs) + # Add in libraries. + _ToolAppend(tools, 'VCLinkerTool', 'AdditionalDependencies', libraries) + _ToolAppend(tools, 'VCLinkerTool', 'AdditionalLibraryDirectories', + library_dirs) + if out_file: + _ToolAppend(tools, vc_tool, 'OutputFile', out_file, only_if_unset=True) + # Add defines. + _ToolAppend(tools, 'VCCLCompilerTool', 'PreprocessorDefinitions', defines) + _ToolAppend(tools, 'VCResourceCompilerTool', 'PreprocessorDefinitions', + defines) + # Change program database directory to prevent collisions. + _ToolAppend(tools, 'VCCLCompilerTool', 'ProgramDataBaseFileName', + '$(IntDir)$(ProjectName)\\vc80.pdb', only_if_unset=True) + # Add disabled warnings. + _ToolAppend(tools, 'VCCLCompilerTool', + 'DisableSpecificWarnings', disabled_warnings) + # Add Pre-build. + _ToolAppend(tools, 'VCPreBuildEventTool', 'CommandLine', prebuild) + # Add Post-build. + _ToolAppend(tools, 'VCPostBuildEventTool', 'CommandLine', postbuild) + # Turn on precompiled headers if appropriate. + if precompiled_header: + precompiled_header = os.path.split(precompiled_header)[1] + _ToolAppend(tools, 'VCCLCompilerTool', 'UsePrecompiledHeader', '2') + _ToolAppend(tools, 'VCCLCompilerTool', + 'PrecompiledHeaderThrough', precompiled_header) + _ToolAppend(tools, 'VCCLCompilerTool', + 'ForcedIncludeFiles', precompiled_header) + # Loadable modules don't generate import libraries; + # tell dependent projects to not expect one. + if spec['type'] == 'loadable_module': + _ToolAppend(tools, 'VCLinkerTool', 'IgnoreImportLibrary', 'true') + # Set the module definition file if any. + if def_file: + _ToolAppend(tools, 'VCLinkerTool', 'ModuleDefinitionFile', def_file) + + _AddConfigurationToMSVS(p, spec, tools, config, config_type, config_name) + + +def _GetIncludeDirs(config): + """Returns the list of directories to be used for #include directives. + + Arguments: + config: The dictionary that defines the special processing to be done + for this configuration. + Returns: + The list of directory paths. + """ + # TODO(bradnelson): include_dirs should really be flexible enough not to + # require this sort of thing. + include_dirs = ( + config.get('include_dirs', []) + + config.get('msvs_system_include_dirs', [])) + resource_include_dirs = config.get('resource_include_dirs', include_dirs) + include_dirs = _FixPaths(include_dirs) + resource_include_dirs = _FixPaths(resource_include_dirs) + return include_dirs, resource_include_dirs + + +def _GetLibraryDirs(config): + """Returns the list of directories to be used for library search paths. + + Arguments: + config: The dictionary that defines the special processing to be done + for this configuration. + Returns: + The list of directory paths. + """ + + library_dirs = config.get('library_dirs', []) + library_dirs = _FixPaths(library_dirs) + return library_dirs + + +def _GetLibraries(spec): + """Returns the list of libraries for this configuration. + + Arguments: + spec: The target dictionary containing the properties of the target. + Returns: + The list of directory paths. + """ + libraries = spec.get('libraries', []) + # Strip out -l, as it is not used on windows (but is needed so we can pass + # in libraries that are assumed to be in the default library path). + # Also remove duplicate entries, leaving only the last duplicate, while + # preserving order. + found = OrderedSet() + unique_libraries_list = [] + for entry in reversed(libraries): + library = re.sub('^\-l', '', entry) + if not os.path.splitext(library)[1]: + library += '.lib' + if library not in found: + found.add(library) + unique_libraries_list.append(library) + unique_libraries_list.reverse() + return unique_libraries_list + + +def _GetOutputFilePathAndTool(spec, msbuild): + """Returns the path and tool to use for this target. + + Figures out the path of the file this spec will create and the name of + the VC tool that will create it. + + Arguments: + spec: The target dictionary containing the properties of the target. + Returns: + A triple of (file path, name of the vc tool, name of the msbuild tool) + """ + # Select a name for the output file. + out_file = '' + vc_tool = '' + msbuild_tool = '' + output_file_map = { + 'executable': ('VCLinkerTool', 'Link', '$(OutDir)', '.exe'), + 'shared_library': ('VCLinkerTool', 'Link', '$(OutDir)', '.dll'), + 'loadable_module': ('VCLinkerTool', 'Link', '$(OutDir)', '.dll'), + 'static_library': ('VCLibrarianTool', 'Lib', '$(OutDir)lib\\', '.lib'), + } + output_file_props = output_file_map.get(spec['type']) + if output_file_props and int(spec.get('msvs_auto_output_file', 1)): + vc_tool, msbuild_tool, out_dir, suffix = output_file_props + if spec.get('standalone_static_library', 0): + out_dir = '$(OutDir)' + out_dir = spec.get('product_dir', out_dir) + product_extension = spec.get('product_extension') + if product_extension: + suffix = '.' + product_extension + elif msbuild: + suffix = '$(TargetExt)' + prefix = spec.get('product_prefix', '') + product_name = spec.get('product_name', '$(ProjectName)') + out_file = ntpath.join(out_dir, prefix + product_name + suffix) + return out_file, vc_tool, msbuild_tool + + +def _GetOutputTargetExt(spec): + """Returns the extension for this target, including the dot + + If product_extension is specified, set target_extension to this to avoid + MSB8012, returns None otherwise. Ignores any target_extension settings in + the input files. + + Arguments: + spec: The target dictionary containing the properties of the target. + Returns: + A string with the extension, or None + """ + target_extension = spec.get('product_extension') + if target_extension: + return '.' + target_extension + return None + + +def _GetDefines(config): + """Returns the list of preprocessor definitions for this configuation. + + Arguments: + config: The dictionary that defines the special processing to be done + for this configuration. + Returns: + The list of preprocessor definitions. + """ + defines = [] + for d in config.get('defines', []): + if type(d) == list: + fd = '='.join([str(dpart) for dpart in d]) + else: + fd = str(d) + defines.append(fd) + return defines + + +def _GetDisabledWarnings(config): + return [str(i) for i in config.get('msvs_disabled_warnings', [])] + + +def _GetModuleDefinition(spec): + def_file = '' + if spec['type'] in ['shared_library', 'loadable_module', 'executable']: + def_files = [s for s in spec.get('sources', []) if s.endswith('.def')] + if len(def_files) == 1: + def_file = _FixPath(def_files[0]) + elif def_files: + raise ValueError( + 'Multiple module definition files in one target, target %s lists ' + 'multiple .def files: %s' % ( + spec['target_name'], ' '.join(def_files))) + return def_file + + +def _ConvertToolsToExpectedForm(tools): + """Convert tools to a form expected by Visual Studio. + + Arguments: + tools: A dictionary of settings; the tool name is the key. + Returns: + A list of Tool objects. + """ + tool_list = [] + for tool, settings in tools.iteritems(): + # Collapse settings with lists. + settings_fixed = {} + for setting, value in settings.iteritems(): + if type(value) == list: + if ((tool == 'VCLinkerTool' and + setting == 'AdditionalDependencies') or + setting == 'AdditionalOptions'): + settings_fixed[setting] = ' '.join(value) + else: + settings_fixed[setting] = ';'.join(value) + else: + settings_fixed[setting] = value + # Add in this tool. + tool_list.append(MSVSProject.Tool(tool, settings_fixed)) + return tool_list + + +def _AddConfigurationToMSVS(p, spec, tools, config, config_type, config_name): + """Add to the project file the configuration specified by config. + + Arguments: + p: The target project being generated. + spec: the target project dict. + tools: A dictionary of settings; the tool name is the key. + config: The dictionary that defines the special processing to be done + for this configuration. + config_type: The configuration type, a number as defined by Microsoft. + config_name: The name of the configuration. + """ + attributes = _GetMSVSAttributes(spec, config, config_type) + # Add in this configuration. + tool_list = _ConvertToolsToExpectedForm(tools) + p.AddConfig(_ConfigFullName(config_name, config), + attrs=attributes, tools=tool_list) + + +def _GetMSVSAttributes(spec, config, config_type): + # Prepare configuration attributes. + prepared_attrs = {} + source_attrs = config.get('msvs_configuration_attributes', {}) + for a in source_attrs: + prepared_attrs[a] = source_attrs[a] + # Add props files. + vsprops_dirs = config.get('msvs_props', []) + vsprops_dirs = _FixPaths(vsprops_dirs) + if vsprops_dirs: + prepared_attrs['InheritedPropertySheets'] = ';'.join(vsprops_dirs) + # Set configuration type. + prepared_attrs['ConfigurationType'] = config_type + output_dir = prepared_attrs.get('OutputDirectory', + '$(SolutionDir)$(ConfigurationName)') + prepared_attrs['OutputDirectory'] = _FixPath(output_dir) + '\\' + if 'IntermediateDirectory' not in prepared_attrs: + intermediate = '$(ConfigurationName)\\obj\\$(ProjectName)' + prepared_attrs['IntermediateDirectory'] = _FixPath(intermediate) + '\\' + else: + intermediate = _FixPath(prepared_attrs['IntermediateDirectory']) + '\\' + intermediate = MSVSSettings.FixVCMacroSlashes(intermediate) + prepared_attrs['IntermediateDirectory'] = intermediate + return prepared_attrs + + +def _AddNormalizedSources(sources_set, sources_array): + sources_set.update(_NormalizedSource(s) for s in sources_array) + + +def _PrepareListOfSources(spec, generator_flags, gyp_file): + """Prepare list of sources and excluded sources. + + Besides the sources specified directly in the spec, adds the gyp file so + that a change to it will cause a re-compile. Also adds appropriate sources + for actions and copies. Assumes later stage will un-exclude files which + have custom build steps attached. + + Arguments: + spec: The target dictionary containing the properties of the target. + gyp_file: The name of the gyp file. + Returns: + A pair of (list of sources, list of excluded sources). + The sources will be relative to the gyp file. + """ + sources = OrderedSet() + _AddNormalizedSources(sources, spec.get('sources', [])) + excluded_sources = OrderedSet() + # Add in the gyp file. + if not generator_flags.get('standalone'): + sources.add(gyp_file) + + # Add in 'action' inputs and outputs. + for a in spec.get('actions', []): + inputs = a['inputs'] + inputs = [_NormalizedSource(i) for i in inputs] + # Add all inputs to sources and excluded sources. + inputs = OrderedSet(inputs) + sources.update(inputs) + if spec['type'] != 'none' and not spec.get('msvs_external_builder'): + excluded_sources.update(inputs) + if int(a.get('process_outputs_as_sources', False)): + _AddNormalizedSources(sources, a.get('outputs', [])) + # Add in 'copies' inputs and outputs. + for cpy in spec.get('copies', []): + _AddNormalizedSources(sources, cpy.get('files', [])) + return (sources, excluded_sources) + + +def _AdjustSourcesAndConvertToFilterHierarchy( + spec, options, gyp_dir, sources, excluded_sources, list_excluded, version): + """Adjusts the list of sources and excluded sources. + + Also converts the sets to lists. + + Arguments: + spec: The target dictionary containing the properties of the target. + options: Global generator options. + gyp_dir: The path to the gyp file being processed. + sources: A set of sources to be included for this project. + excluded_sources: A set of sources to be excluded for this project. + version: A MSVSVersion object. + Returns: + A trio of (list of sources, list of excluded sources, + path of excluded IDL file) + """ + # Exclude excluded sources coming into the generator. + excluded_sources.update(OrderedSet(spec.get('sources_excluded', []))) + # Add excluded sources into sources for good measure. + sources.update(excluded_sources) + # Convert to proper windows form. + # NOTE: sources goes from being a set to a list here. + # NOTE: excluded_sources goes from being a set to a list here. + sources = _FixPaths(sources) + # Convert to proper windows form. + excluded_sources = _FixPaths(excluded_sources) + + excluded_idl = _IdlFilesHandledNonNatively(spec, sources) + + precompiled_related = _GetPrecompileRelatedFiles(spec) + # Find the excluded ones, minus the precompiled header related ones. + fully_excluded = [i for i in excluded_sources if i not in precompiled_related] + + # Convert to folders and the right slashes. + sources = [i.split('\\') for i in sources] + sources = _ConvertSourcesToFilterHierarchy(sources, excluded=fully_excluded, + list_excluded=list_excluded, + msvs_version=version) + + # Prune filters with a single child to flatten ugly directory structures + # such as ../../src/modules/module1 etc. + if version.UsesVcxproj(): + while all([isinstance(s, MSVSProject.Filter) for s in sources]) \ + and len(set([s.name for s in sources])) == 1: + assert all([len(s.contents) == 1 for s in sources]) + sources = [s.contents[0] for s in sources] + else: + while len(sources) == 1 and isinstance(sources[0], MSVSProject.Filter): + sources = sources[0].contents + + return sources, excluded_sources, excluded_idl + + +def _IdlFilesHandledNonNatively(spec, sources): + # If any non-native rules use 'idl' as an extension exclude idl files. + # Gather a list here to use later. + using_idl = False + for rule in spec.get('rules', []): + if rule['extension'] == 'idl' and int(rule.get('msvs_external_rule', 0)): + using_idl = True + break + if using_idl: + excluded_idl = [i for i in sources if i.endswith('.idl')] + else: + excluded_idl = [] + return excluded_idl + + +def _GetPrecompileRelatedFiles(spec): + # Gather a list of precompiled header related sources. + precompiled_related = [] + for _, config in spec['configurations'].iteritems(): + for k in precomp_keys: + f = config.get(k) + if f: + precompiled_related.append(_FixPath(f)) + return precompiled_related + + +def _ExcludeFilesFromBeingBuilt(p, spec, excluded_sources, excluded_idl, + list_excluded): + exclusions = _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl) + for file_name, excluded_configs in exclusions.iteritems(): + if (not list_excluded and + len(excluded_configs) == len(spec['configurations'])): + # If we're not listing excluded files, then they won't appear in the + # project, so don't try to configure them to be excluded. + pass + else: + for config_name, config in excluded_configs: + p.AddFileConfig(file_name, _ConfigFullName(config_name, config), + {'ExcludedFromBuild': 'true'}) + + +def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl): + exclusions = {} + # Exclude excluded sources from being built. + for f in excluded_sources: + excluded_configs = [] + for config_name, config in spec['configurations'].iteritems(): + precomped = [_FixPath(config.get(i, '')) for i in precomp_keys] + # Don't do this for ones that are precompiled header related. + if f not in precomped: + excluded_configs.append((config_name, config)) + exclusions[f] = excluded_configs + # If any non-native rules use 'idl' as an extension exclude idl files. + # Exclude them now. + for f in excluded_idl: + excluded_configs = [] + for config_name, config in spec['configurations'].iteritems(): + excluded_configs.append((config_name, config)) + exclusions[f] = excluded_configs + return exclusions + + +def _AddToolFilesToMSVS(p, spec): + # Add in tool files (rules). + tool_files = OrderedSet() + for _, config in spec['configurations'].iteritems(): + for f in config.get('msvs_tool_files', []): + tool_files.add(f) + for f in tool_files: + p.AddToolFile(f) + + +def _HandlePreCompiledHeaders(p, sources, spec): + # Pre-compiled header source stubs need a different compiler flag + # (generate precompiled header) and any source file not of the same + # kind (i.e. C vs. C++) as the precompiled header source stub needs + # to have use of precompiled headers disabled. + extensions_excluded_from_precompile = [] + for config_name, config in spec['configurations'].iteritems(): + source = config.get('msvs_precompiled_source') + if source: + source = _FixPath(source) + # UsePrecompiledHeader=1 for if using precompiled headers. + tool = MSVSProject.Tool('VCCLCompilerTool', + {'UsePrecompiledHeader': '1'}) + p.AddFileConfig(source, _ConfigFullName(config_name, config), + {}, tools=[tool]) + basename, extension = os.path.splitext(source) + if extension == '.c': + extensions_excluded_from_precompile = ['.cc', '.cpp', '.cxx'] + else: + extensions_excluded_from_precompile = ['.c'] + def DisableForSourceTree(source_tree): + for source in source_tree: + if isinstance(source, MSVSProject.Filter): + DisableForSourceTree(source.contents) + else: + basename, extension = os.path.splitext(source) + if extension in extensions_excluded_from_precompile: + for config_name, config in spec['configurations'].iteritems(): + tool = MSVSProject.Tool('VCCLCompilerTool', + {'UsePrecompiledHeader': '0', + 'ForcedIncludeFiles': '$(NOINHERIT)'}) + p.AddFileConfig(_FixPath(source), + _ConfigFullName(config_name, config), + {}, tools=[tool]) + # Do nothing if there was no precompiled source. + if extensions_excluded_from_precompile: + DisableForSourceTree(sources) + + +def _AddActions(actions_to_add, spec, relative_path_of_gyp_file): + # Add actions. + actions = spec.get('actions', []) + # Don't setup_env every time. When all the actions are run together in one + # batch file in VS, the PATH will grow too long. + # Membership in this set means that the cygwin environment has been set up, + # and does not need to be set up again. + have_setup_env = set() + for a in actions: + # Attach actions to the gyp file if nothing else is there. + inputs = a.get('inputs') or [relative_path_of_gyp_file] + attached_to = inputs[0] + need_setup_env = attached_to not in have_setup_env + cmd = _BuildCommandLineForRule(spec, a, has_input_path=False, + do_setup_env=need_setup_env) + have_setup_env.add(attached_to) + # Add the action. + _AddActionStep(actions_to_add, + inputs=inputs, + outputs=a.get('outputs', []), + description=a.get('message', a['action_name']), + command=cmd) + + +def _WriteMSVSUserFile(project_path, version, spec): + # Add run_as and test targets. + if 'run_as' in spec: + run_as = spec['run_as'] + action = run_as.get('action', []) + environment = run_as.get('environment', []) + working_directory = run_as.get('working_directory', '.') + elif int(spec.get('test', 0)): + action = ['$(TargetPath)', '--gtest_print_time'] + environment = [] + working_directory = '.' + else: + return # Nothing to add + # Write out the user file. + user_file = _CreateMSVSUserFile(project_path, version, spec) + for config_name, c_data in spec['configurations'].iteritems(): + user_file.AddDebugSettings(_ConfigFullName(config_name, c_data), + action, environment, working_directory) + user_file.WriteIfChanged() + + +def _AddCopies(actions_to_add, spec): + copies = _GetCopies(spec) + for inputs, outputs, cmd, description in copies: + _AddActionStep(actions_to_add, inputs=inputs, outputs=outputs, + description=description, command=cmd) + + +def _GetCopies(spec): + copies = [] + # Add copies. + for cpy in spec.get('copies', []): + for src in cpy.get('files', []): + dst = os.path.join(cpy['destination'], os.path.basename(src)) + # _AddCustomBuildToolForMSVS() will call _FixPath() on the inputs and + # outputs, so do the same for our generated command line. + if src.endswith('/'): + src_bare = src[:-1] + base_dir = posixpath.split(src_bare)[0] + outer_dir = posixpath.split(src_bare)[1] + cmd = 'cd "%s" && xcopy /e /f /y "%s" "%s\\%s\\"' % ( + _FixPath(base_dir), outer_dir, _FixPath(dst), outer_dir) + copies.append(([src], ['dummy_copies', dst], cmd, + 'Copying %s to %s' % (src, dst))) + else: + cmd = 'mkdir "%s" 2>nul & set ERRORLEVEL=0 & copy /Y "%s" "%s"' % ( + _FixPath(cpy['destination']), _FixPath(src), _FixPath(dst)) + copies.append(([src], [dst], cmd, 'Copying %s to %s' % (src, dst))) + return copies + + +def _GetPathDict(root, path): + # |path| will eventually be empty (in the recursive calls) if it was initially + # relative; otherwise it will eventually end up as '\', 'D:\', etc. + if not path or path.endswith(os.sep): + return root + parent, folder = os.path.split(path) + parent_dict = _GetPathDict(root, parent) + if folder not in parent_dict: + parent_dict[folder] = dict() + return parent_dict[folder] + + +def _DictsToFolders(base_path, bucket, flat): + # Convert to folders recursively. + children = [] + for folder, contents in bucket.iteritems(): + if type(contents) == dict: + folder_children = _DictsToFolders(os.path.join(base_path, folder), + contents, flat) + if flat: + children += folder_children + else: + folder_children = MSVSNew.MSVSFolder(os.path.join(base_path, folder), + name='(' + folder + ')', + entries=folder_children) + children.append(folder_children) + else: + children.append(contents) + return children + + +def _CollapseSingles(parent, node): + # Recursively explorer the tree of dicts looking for projects which are + # the sole item in a folder which has the same name as the project. Bring + # such projects up one level. + if (type(node) == dict and + len(node) == 1 and + node.keys()[0] == parent + '.vcproj'): + return node[node.keys()[0]] + if type(node) != dict: + return node + for child in node: + node[child] = _CollapseSingles(child, node[child]) + return node + + +def _GatherSolutionFolders(sln_projects, project_objects, flat): + root = {} + # Convert into a tree of dicts on path. + for p in sln_projects: + gyp_file, target = gyp.common.ParseQualifiedTarget(p)[0:2] + gyp_dir = os.path.dirname(gyp_file) + path_dict = _GetPathDict(root, gyp_dir) + path_dict[target + '.vcproj'] = project_objects[p] + # Walk down from the top until we hit a folder that has more than one entry. + # In practice, this strips the top-level "src/" dir from the hierarchy in + # the solution. + while len(root) == 1 and type(root[root.keys()[0]]) == dict: + root = root[root.keys()[0]] + # Collapse singles. + root = _CollapseSingles('', root) + # Merge buckets until everything is a root entry. + return _DictsToFolders('', root, flat) + + +def _GetPathOfProject(qualified_target, spec, options, msvs_version): + default_config = _GetDefaultConfiguration(spec) + proj_filename = default_config.get('msvs_existing_vcproj') + if not proj_filename: + proj_filename = (spec['target_name'] + options.suffix + + msvs_version.ProjectExtension()) + + build_file = gyp.common.BuildFile(qualified_target) + proj_path = os.path.join(os.path.dirname(build_file), proj_filename) + fix_prefix = None + if options.generator_output: + project_dir_path = os.path.dirname(os.path.abspath(proj_path)) + proj_path = os.path.join(options.generator_output, proj_path) + fix_prefix = gyp.common.RelativePath(project_dir_path, + os.path.dirname(proj_path)) + return proj_path, fix_prefix + + +def _GetPlatformOverridesOfProject(spec): + # Prepare a dict indicating which project configurations are used for which + # solution configurations for this target. + config_platform_overrides = {} + for config_name, c in spec['configurations'].iteritems(): + config_fullname = _ConfigFullName(config_name, c) + platform = c.get('msvs_target_platform', _ConfigPlatform(c)) + fixed_config_fullname = '%s|%s' % ( + _ConfigBaseName(config_name, _ConfigPlatform(c)), platform) + config_platform_overrides[config_fullname] = fixed_config_fullname + return config_platform_overrides + + +def _CreateProjectObjects(target_list, target_dicts, options, msvs_version): + """Create a MSVSProject object for the targets found in target list. + + Arguments: + target_list: the list of targets to generate project objects for. + target_dicts: the dictionary of specifications. + options: global generator options. + msvs_version: the MSVSVersion object. + Returns: + A set of created projects, keyed by target. + """ + global fixpath_prefix + # Generate each project. + projects = {} + for qualified_target in target_list: + spec = target_dicts[qualified_target] + if spec['toolset'] != 'target': + raise GypError( + 'Multiple toolsets not supported in msvs build (target %s)' % + qualified_target) + proj_path, fixpath_prefix = _GetPathOfProject(qualified_target, spec, + options, msvs_version) + guid = _GetGuidOfProject(proj_path, spec) + overrides = _GetPlatformOverridesOfProject(spec) + build_file = gyp.common.BuildFile(qualified_target) + # Create object for this project. + obj = MSVSNew.MSVSProject( + proj_path, + name=spec['target_name'], + guid=guid, + spec=spec, + build_file=build_file, + config_platform_overrides=overrides, + fixpath_prefix=fixpath_prefix) + # Set project toolset if any (MS build only) + if msvs_version.UsesVcxproj(): + obj.set_msbuild_toolset( + _GetMsbuildToolsetOfProject(proj_path, spec, msvs_version)) + projects[qualified_target] = obj + # Set all the dependencies, but not if we are using an external builder like + # ninja + for project in projects.values(): + if not project.spec.get('msvs_external_builder'): + deps = project.spec.get('dependencies', []) + deps = [projects[d] for d in deps] + project.set_dependencies(deps) + return projects + + +def _InitNinjaFlavor(options, target_list, target_dicts): + """Initialize targets for the ninja flavor. + + This sets up the necessary variables in the targets to generate msvs projects + that use ninja as an external builder. The variables in the spec are only set + if they have not been set. This allows individual specs to override the + default values initialized here. + Arguments: + options: Options provided to the generator. + target_list: List of target pairs: 'base/base.gyp:base'. + target_dicts: Dict of target properties keyed on target pair. + """ + for qualified_target in target_list: + spec = target_dicts[qualified_target] + if spec.get('msvs_external_builder'): + # The spec explicitly defined an external builder, so don't change it. + continue + + path_to_ninja = spec.get('msvs_path_to_ninja', 'ninja.exe') + + spec['msvs_external_builder'] = 'ninja' + if not spec.get('msvs_external_builder_out_dir'): + spec['msvs_external_builder_out_dir'] = \ + options.depth + '/out/$(Configuration)' + if not spec.get('msvs_external_builder_build_cmd'): + spec['msvs_external_builder_build_cmd'] = [ + path_to_ninja, + '-C', + '$(OutDir)', + '$(ProjectName)', + ] + if not spec.get('msvs_external_builder_clean_cmd'): + spec['msvs_external_builder_clean_cmd'] = [ + path_to_ninja, + '-C', + '$(OutDir)', + '-t', + 'clean', + '$(ProjectName)', + ] + + +def CalculateVariables(default_variables, params): + """Generated variables that require params to be known.""" + + generator_flags = params.get('generator_flags', {}) + + # Select project file format version (if unset, default to auto detecting). + msvs_version = MSVSVersion.SelectVisualStudioVersion( + generator_flags.get('msvs_version', 'auto')) + # Stash msvs_version for later (so we don't have to probe the system twice). + params['msvs_version'] = msvs_version + + # Set a variable so conditions can be based on msvs_version. + default_variables['MSVS_VERSION'] = msvs_version.ShortName() + + # To determine processor word size on Windows, in addition to checking + # PROCESSOR_ARCHITECTURE (which reflects the word size of the current + # process), it is also necessary to check PROCESSOR_ARCITEW6432 (which + # contains the actual word size of the system when running thru WOW64). + if (os.environ.get('PROCESSOR_ARCHITECTURE', '').find('64') >= 0 or + os.environ.get('PROCESSOR_ARCHITEW6432', '').find('64') >= 0): + default_variables['MSVS_OS_BITS'] = 64 + else: + default_variables['MSVS_OS_BITS'] = 32 + + if gyp.common.GetFlavor(params) == 'ninja': + default_variables['SHARED_INTERMEDIATE_DIR'] = '$(OutDir)gen' + + +def PerformBuild(data, configurations, params): + options = params['options'] + msvs_version = params['msvs_version'] + devenv = os.path.join(msvs_version.path, 'Common7', 'IDE', 'devenv.com') + + for build_file, build_file_dict in data.iteritems(): + (build_file_root, build_file_ext) = os.path.splitext(build_file) + if build_file_ext != '.gyp': + continue + sln_path = build_file_root + options.suffix + '.sln' + if options.generator_output: + sln_path = os.path.join(options.generator_output, sln_path) + + for config in configurations: + arguments = [devenv, sln_path, '/Build', config] + print 'Building [%s]: %s' % (config, arguments) + rtn = subprocess.check_call(arguments) + + +def GenerateOutput(target_list, target_dicts, data, params): + """Generate .sln and .vcproj files. + + This is the entry point for this generator. + Arguments: + target_list: List of target pairs: 'base/base.gyp:base'. + target_dicts: Dict of target properties keyed on target pair. + data: Dictionary containing per .gyp data. + """ + global fixpath_prefix + + options = params['options'] + + # Get the project file format version back out of where we stashed it in + # GeneratorCalculatedVariables. + msvs_version = params['msvs_version'] + + generator_flags = params.get('generator_flags', {}) + + # Optionally shard targets marked with 'msvs_shard': SHARD_COUNT. + (target_list, target_dicts) = MSVSUtil.ShardTargets(target_list, target_dicts) + + # Optionally use the large PDB workaround for targets marked with + # 'msvs_large_pdb': 1. + (target_list, target_dicts) = MSVSUtil.InsertLargePdbShims( + target_list, target_dicts, generator_default_variables) + + # Optionally configure each spec to use ninja as the external builder. + if params.get('flavor') == 'ninja': + _InitNinjaFlavor(options, target_list, target_dicts) + + # Prepare the set of configurations. + configs = set() + for qualified_target in target_list: + spec = target_dicts[qualified_target] + for config_name, config in spec['configurations'].iteritems(): + configs.add(_ConfigFullName(config_name, config)) + configs = list(configs) + + # Figure out all the projects that will be generated and their guids + project_objects = _CreateProjectObjects(target_list, target_dicts, options, + msvs_version) + + # Generate each project. + missing_sources = [] + for project in project_objects.values(): + fixpath_prefix = project.fixpath_prefix + missing_sources.extend(_GenerateProject(project, options, msvs_version, + generator_flags)) + fixpath_prefix = None + + for build_file in data: + # Validate build_file extension + if not build_file.endswith('.gyp'): + continue + sln_path = os.path.splitext(build_file)[0] + options.suffix + '.sln' + if options.generator_output: + sln_path = os.path.join(options.generator_output, sln_path) + # Get projects in the solution, and their dependents. + sln_projects = gyp.common.BuildFileTargets(target_list, build_file) + sln_projects += gyp.common.DeepDependencyTargets(target_dicts, sln_projects) + # Create folder hierarchy. + root_entries = _GatherSolutionFolders( + sln_projects, project_objects, flat=msvs_version.FlatSolution()) + # Create solution. + sln = MSVSNew.MSVSSolution(sln_path, + entries=root_entries, + variants=configs, + websiteProperties=False, + version=msvs_version) + sln.Write() + + if missing_sources: + error_message = "Missing input files:\n" + \ + '\n'.join(set(missing_sources)) + if generator_flags.get('msvs_error_on_missing_sources', False): + raise GypError(error_message) + else: + print >> sys.stdout, "Warning: " + error_message + + +def _GenerateMSBuildFiltersFile(filters_path, source_files, + extension_to_rule_name): + """Generate the filters file. + + This file is used by Visual Studio to organize the presentation of source + files into folders. + + Arguments: + filters_path: The path of the file to be created. + source_files: The hierarchical structure of all the sources. + extension_to_rule_name: A dictionary mapping file extensions to rules. + """ + filter_group = [] + source_group = [] + _AppendFiltersForMSBuild('', source_files, extension_to_rule_name, + filter_group, source_group) + if filter_group: + content = ['Project', + {'ToolsVersion': '4.0', + 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003' + }, + ['ItemGroup'] + filter_group, + ['ItemGroup'] + source_group + ] + easy_xml.WriteXmlIfChanged(content, filters_path, pretty=True, win32=True) + elif os.path.exists(filters_path): + # We don't need this filter anymore. Delete the old filter file. + os.unlink(filters_path) + + +def _AppendFiltersForMSBuild(parent_filter_name, sources, + extension_to_rule_name, + filter_group, source_group): + """Creates the list of filters and sources to be added in the filter file. + + Args: + parent_filter_name: The name of the filter under which the sources are + found. + sources: The hierarchy of filters and sources to process. + extension_to_rule_name: A dictionary mapping file extensions to rules. + filter_group: The list to which filter entries will be appended. + source_group: The list to which source entries will be appeneded. + """ + for source in sources: + if isinstance(source, MSVSProject.Filter): + # We have a sub-filter. Create the name of that sub-filter. + if not parent_filter_name: + filter_name = source.name + else: + filter_name = '%s\\%s' % (parent_filter_name, source.name) + # Add the filter to the group. + filter_group.append( + ['Filter', {'Include': filter_name}, + ['UniqueIdentifier', MSVSNew.MakeGuid(source.name)]]) + # Recurse and add its dependents. + _AppendFiltersForMSBuild(filter_name, source.contents, + extension_to_rule_name, + filter_group, source_group) + else: + # It's a source. Create a source entry. + _, element = _MapFileToMsBuildSourceType(source, extension_to_rule_name) + source_entry = [element, {'Include': source}] + # Specify the filter it is part of, if any. + if parent_filter_name: + source_entry.append(['Filter', parent_filter_name]) + source_group.append(source_entry) + + +def _MapFileToMsBuildSourceType(source, extension_to_rule_name): + """Returns the group and element type of the source file. + + Arguments: + source: The source file name. + extension_to_rule_name: A dictionary mapping file extensions to rules. + + Returns: + A pair of (group this file should be part of, the label of element) + """ + _, ext = os.path.splitext(source) + if ext in extension_to_rule_name: + group = 'rule' + element = extension_to_rule_name[ext] + elif ext in ['.cc', '.cpp', '.c', '.cxx']: + group = 'compile' + element = 'ClCompile' + elif ext in ['.h', '.hxx']: + group = 'include' + element = 'ClInclude' + elif ext == '.rc': + group = 'resource' + element = 'ResourceCompile' + elif ext == '.idl': + group = 'midl' + element = 'Midl' + else: + group = 'none' + element = 'None' + return (group, element) + + +def _GenerateRulesForMSBuild(output_dir, options, spec, + sources, excluded_sources, + props_files_of_rules, targets_files_of_rules, + actions_to_add, extension_to_rule_name): + # MSBuild rules are implemented using three files: an XML file, a .targets + # file and a .props file. + # See http://blogs.msdn.com/b/vcblog/archive/2010/04/21/quick-help-on-vs2010-custom-build-rule.aspx + # for more details. + rules = spec.get('rules', []) + rules_native = [r for r in rules if not int(r.get('msvs_external_rule', 0))] + rules_external = [r for r in rules if int(r.get('msvs_external_rule', 0))] + + msbuild_rules = [] + for rule in rules_native: + # Skip a rule with no action and no inputs. + if 'action' not in rule and not rule.get('rule_sources', []): + continue + msbuild_rule = MSBuildRule(rule, spec) + msbuild_rules.append(msbuild_rule) + extension_to_rule_name[msbuild_rule.extension] = msbuild_rule.rule_name + if msbuild_rules: + base = spec['target_name'] + options.suffix + props_name = base + '.props' + targets_name = base + '.targets' + xml_name = base + '.xml' + + props_files_of_rules.add(props_name) + targets_files_of_rules.add(targets_name) + + props_path = os.path.join(output_dir, props_name) + targets_path = os.path.join(output_dir, targets_name) + xml_path = os.path.join(output_dir, xml_name) + + _GenerateMSBuildRulePropsFile(props_path, msbuild_rules) + _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules) + _GenerateMSBuildRuleXmlFile(xml_path, msbuild_rules) + + if rules_external: + _GenerateExternalRules(rules_external, output_dir, spec, + sources, options, actions_to_add) + _AdjustSourcesForRules(spec, rules, sources, excluded_sources) + + +class MSBuildRule(object): + """Used to store information used to generate an MSBuild rule. + + Attributes: + rule_name: The rule name, sanitized to use in XML. + target_name: The name of the target. + after_targets: The name of the AfterTargets element. + before_targets: The name of the BeforeTargets element. + depends_on: The name of the DependsOn element. + compute_output: The name of the ComputeOutput element. + dirs_to_make: The name of the DirsToMake element. + inputs: The name of the _inputs element. + tlog: The name of the _tlog element. + extension: The extension this rule applies to. + description: The message displayed when this rule is invoked. + additional_dependencies: A string listing additional dependencies. + outputs: The outputs of this rule. + command: The command used to run the rule. + """ + + def __init__(self, rule, spec): + self.display_name = rule['rule_name'] + # Assure that the rule name is only characters and numbers + self.rule_name = re.sub(r'\W', '_', self.display_name) + # Create the various element names, following the example set by the + # Visual Studio 2008 to 2010 conversion. I don't know if VS2010 + # is sensitive to the exact names. + self.target_name = '_' + self.rule_name + self.after_targets = self.rule_name + 'AfterTargets' + self.before_targets = self.rule_name + 'BeforeTargets' + self.depends_on = self.rule_name + 'DependsOn' + self.compute_output = 'Compute%sOutput' % self.rule_name + self.dirs_to_make = self.rule_name + 'DirsToMake' + self.inputs = self.rule_name + '_inputs' + self.tlog = self.rule_name + '_tlog' + self.extension = rule['extension'] + if not self.extension.startswith('.'): + self.extension = '.' + self.extension + + self.description = MSVSSettings.ConvertVCMacrosToMSBuild( + rule.get('message', self.rule_name)) + old_additional_dependencies = _FixPaths(rule.get('inputs', [])) + self.additional_dependencies = ( + ';'.join([MSVSSettings.ConvertVCMacrosToMSBuild(i) + for i in old_additional_dependencies])) + old_outputs = _FixPaths(rule.get('outputs', [])) + self.outputs = ';'.join([MSVSSettings.ConvertVCMacrosToMSBuild(i) + for i in old_outputs]) + old_command = _BuildCommandLineForRule(spec, rule, has_input_path=True, + do_setup_env=True) + self.command = MSVSSettings.ConvertVCMacrosToMSBuild(old_command) + + +def _GenerateMSBuildRulePropsFile(props_path, msbuild_rules): + """Generate the .props file.""" + content = ['Project', + {'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}] + for rule in msbuild_rules: + content.extend([ + ['PropertyGroup', + {'Condition': "'$(%s)' == '' and '$(%s)' == '' and " + "'$(ConfigurationType)' != 'Makefile'" % (rule.before_targets, + rule.after_targets) + }, + [rule.before_targets, 'Midl'], + [rule.after_targets, 'CustomBuild'], + ], + ['PropertyGroup', + [rule.depends_on, + {'Condition': "'$(ConfigurationType)' != 'Makefile'"}, + '_SelectedFiles;$(%s)' % rule.depends_on + ], + ], + ['ItemDefinitionGroup', + [rule.rule_name, + ['CommandLineTemplate', rule.command], + ['Outputs', rule.outputs], + ['ExecutionDescription', rule.description], + ['AdditionalDependencies', rule.additional_dependencies], + ], + ] + ]) + easy_xml.WriteXmlIfChanged(content, props_path, pretty=True, win32=True) + + +def _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules): + """Generate the .targets file.""" + content = ['Project', + {'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003' + } + ] + item_group = [ + 'ItemGroup', + ['PropertyPageSchema', + {'Include': '$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml'} + ] + ] + for rule in msbuild_rules: + item_group.append( + ['AvailableItemName', + {'Include': rule.rule_name}, + ['Targets', rule.target_name], + ]) + content.append(item_group) + + for rule in msbuild_rules: + content.append( + ['UsingTask', + {'TaskName': rule.rule_name, + 'TaskFactory': 'XamlTaskFactory', + 'AssemblyName': 'Microsoft.Build.Tasks.v4.0' + }, + ['Task', '$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml'], + ]) + for rule in msbuild_rules: + rule_name = rule.rule_name + target_outputs = '%%(%s.Outputs)' % rule_name + target_inputs = ('%%(%s.Identity);%%(%s.AdditionalDependencies);' + '$(MSBuildProjectFile)') % (rule_name, rule_name) + rule_inputs = '%%(%s.Identity)' % rule_name + extension_condition = ("'%(Extension)'=='.obj' or " + "'%(Extension)'=='.res' or " + "'%(Extension)'=='.rsc' or " + "'%(Extension)'=='.lib'") + remove_section = [ + 'ItemGroup', + {'Condition': "'@(SelectedFiles)' != ''"}, + [rule_name, + {'Remove': '@(%s)' % rule_name, + 'Condition': "'%(Identity)' != '@(SelectedFiles)'" + } + ] + ] + inputs_section = [ + 'ItemGroup', + [rule.inputs, {'Include': '%%(%s.AdditionalDependencies)' % rule_name}] + ] + logging_section = [ + 'ItemGroup', + [rule.tlog, + {'Include': '%%(%s.Outputs)' % rule_name, + 'Condition': ("'%%(%s.Outputs)' != '' and " + "'%%(%s.ExcludedFromBuild)' != 'true'" % + (rule_name, rule_name)) + }, + ['Source', "@(%s, '|')" % rule_name], + ['Inputs', "@(%s -> '%%(Fullpath)', ';')" % rule.inputs], + ], + ] + message_section = [ + 'Message', + {'Importance': 'High', + 'Text': '%%(%s.ExecutionDescription)' % rule_name + } + ] + write_tlog_section = [ + 'WriteLinesToFile', + {'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != " + "'true'" % (rule.tlog, rule.tlog), + 'File': '$(IntDir)$(ProjectName).write.1.tlog', + 'Lines': "^%%(%s.Source);@(%s->'%%(Fullpath)')" % (rule.tlog, + rule.tlog) + } + ] + read_tlog_section = [ + 'WriteLinesToFile', + {'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != " + "'true'" % (rule.tlog, rule.tlog), + 'File': '$(IntDir)$(ProjectName).read.1.tlog', + 'Lines': "^%%(%s.Source);%%(%s.Inputs)" % (rule.tlog, rule.tlog) + } + ] + command_and_input_section = [ + rule_name, + {'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != " + "'true'" % (rule_name, rule_name), + 'CommandLineTemplate': '%%(%s.CommandLineTemplate)' % rule_name, + 'AdditionalOptions': '%%(%s.AdditionalOptions)' % rule_name, + 'Inputs': rule_inputs + } + ] + content.extend([ + ['Target', + {'Name': rule.target_name, + 'BeforeTargets': '$(%s)' % rule.before_targets, + 'AfterTargets': '$(%s)' % rule.after_targets, + 'Condition': "'@(%s)' != ''" % rule_name, + 'DependsOnTargets': '$(%s);%s' % (rule.depends_on, + rule.compute_output), + 'Outputs': target_outputs, + 'Inputs': target_inputs + }, + remove_section, + inputs_section, + logging_section, + message_section, + write_tlog_section, + read_tlog_section, + command_and_input_section, + ], + ['PropertyGroup', + ['ComputeLinkInputsTargets', + '$(ComputeLinkInputsTargets);', + '%s;' % rule.compute_output + ], + ['ComputeLibInputsTargets', + '$(ComputeLibInputsTargets);', + '%s;' % rule.compute_output + ], + ], + ['Target', + {'Name': rule.compute_output, + 'Condition': "'@(%s)' != ''" % rule_name + }, + ['ItemGroup', + [rule.dirs_to_make, + {'Condition': "'@(%s)' != '' and " + "'%%(%s.ExcludedFromBuild)' != 'true'" % (rule_name, rule_name), + 'Include': '%%(%s.Outputs)' % rule_name + } + ], + ['Link', + {'Include': '%%(%s.Identity)' % rule.dirs_to_make, + 'Condition': extension_condition + } + ], + ['Lib', + {'Include': '%%(%s.Identity)' % rule.dirs_to_make, + 'Condition': extension_condition + } + ], + ['ImpLib', + {'Include': '%%(%s.Identity)' % rule.dirs_to_make, + 'Condition': extension_condition + } + ], + ], + ['MakeDir', + {'Directories': ("@(%s->'%%(RootDir)%%(Directory)')" % + rule.dirs_to_make) + } + ] + ], + ]) + easy_xml.WriteXmlIfChanged(content, targets_path, pretty=True, win32=True) + + +def _GenerateMSBuildRuleXmlFile(xml_path, msbuild_rules): + # Generate the .xml file + content = [ + 'ProjectSchemaDefinitions', + {'xmlns': ('clr-namespace:Microsoft.Build.Framework.XamlTypes;' + 'assembly=Microsoft.Build.Framework'), + 'xmlns:x': 'http://schemas.microsoft.com/winfx/2006/xaml', + 'xmlns:sys': 'clr-namespace:System;assembly=mscorlib', + 'xmlns:transformCallback': + 'Microsoft.Cpp.Dev10.ConvertPropertyCallback' + } + ] + for rule in msbuild_rules: + content.extend([ + ['Rule', + {'Name': rule.rule_name, + 'PageTemplate': 'tool', + 'DisplayName': rule.display_name, + 'Order': '200' + }, + ['Rule.DataSource', + ['DataSource', + {'Persistence': 'ProjectFile', + 'ItemType': rule.rule_name + } + ] + ], + ['Rule.Categories', + ['Category', + {'Name': 'General'}, + ['Category.DisplayName', + ['sys:String', 'General'], + ], + ], + ['Category', + {'Name': 'Command Line', + 'Subtype': 'CommandLine' + }, + ['Category.DisplayName', + ['sys:String', 'Command Line'], + ], + ], + ], + ['StringListProperty', + {'Name': 'Inputs', + 'Category': 'Command Line', + 'IsRequired': 'true', + 'Switch': ' ' + }, + ['StringListProperty.DataSource', + ['DataSource', + {'Persistence': 'ProjectFile', + 'ItemType': rule.rule_name, + 'SourceType': 'Item' + } + ] + ], + ], + ['StringProperty', + {'Name': 'CommandLineTemplate', + 'DisplayName': 'Command Line', + 'Visible': 'False', + 'IncludeInCommandLine': 'False' + } + ], + ['DynamicEnumProperty', + {'Name': rule.before_targets, + 'Category': 'General', + 'EnumProvider': 'Targets', + 'IncludeInCommandLine': 'False' + }, + ['DynamicEnumProperty.DisplayName', + ['sys:String', 'Execute Before'], + ], + ['DynamicEnumProperty.Description', + ['sys:String', 'Specifies the targets for the build customization' + ' to run before.' + ], + ], + ['DynamicEnumProperty.ProviderSettings', + ['NameValuePair', + {'Name': 'Exclude', + 'Value': '^%s|^Compute' % rule.before_targets + } + ] + ], + ['DynamicEnumProperty.DataSource', + ['DataSource', + {'Persistence': 'ProjectFile', + 'HasConfigurationCondition': 'true' + } + ] + ], + ], + ['DynamicEnumProperty', + {'Name': rule.after_targets, + 'Category': 'General', + 'EnumProvider': 'Targets', + 'IncludeInCommandLine': 'False' + }, + ['DynamicEnumProperty.DisplayName', + ['sys:String', 'Execute After'], + ], + ['DynamicEnumProperty.Description', + ['sys:String', ('Specifies the targets for the build customization' + ' to run after.') + ], + ], + ['DynamicEnumProperty.ProviderSettings', + ['NameValuePair', + {'Name': 'Exclude', + 'Value': '^%s|^Compute' % rule.after_targets + } + ] + ], + ['DynamicEnumProperty.DataSource', + ['DataSource', + {'Persistence': 'ProjectFile', + 'ItemType': '', + 'HasConfigurationCondition': 'true' + } + ] + ], + ], + ['StringListProperty', + {'Name': 'Outputs', + 'DisplayName': 'Outputs', + 'Visible': 'False', + 'IncludeInCommandLine': 'False' + } + ], + ['StringProperty', + {'Name': 'ExecutionDescription', + 'DisplayName': 'Execution Description', + 'Visible': 'False', + 'IncludeInCommandLine': 'False' + } + ], + ['StringListProperty', + {'Name': 'AdditionalDependencies', + 'DisplayName': 'Additional Dependencies', + 'IncludeInCommandLine': 'False', + 'Visible': 'false' + } + ], + ['StringProperty', + {'Subtype': 'AdditionalOptions', + 'Name': 'AdditionalOptions', + 'Category': 'Command Line' + }, + ['StringProperty.DisplayName', + ['sys:String', 'Additional Options'], + ], + ['StringProperty.Description', + ['sys:String', 'Additional Options'], + ], + ], + ], + ['ItemType', + {'Name': rule.rule_name, + 'DisplayName': rule.display_name + } + ], + ['FileExtension', + {'Name': '*' + rule.extension, + 'ContentType': rule.rule_name + } + ], + ['ContentType', + {'Name': rule.rule_name, + 'DisplayName': '', + 'ItemType': rule.rule_name + } + ] + ]) + easy_xml.WriteXmlIfChanged(content, xml_path, pretty=True, win32=True) + + +def _GetConfigurationAndPlatform(name, settings): + configuration = name.rsplit('_', 1)[0] + platform = settings.get('msvs_configuration_platform', 'Win32') + return (configuration, platform) + + +def _GetConfigurationCondition(name, settings): + return (r"'$(Configuration)|$(Platform)'=='%s|%s'" % + _GetConfigurationAndPlatform(name, settings)) + + +def _GetMSBuildProjectConfigurations(configurations): + group = ['ItemGroup', {'Label': 'ProjectConfigurations'}] + for (name, settings) in sorted(configurations.iteritems()): + configuration, platform = _GetConfigurationAndPlatform(name, settings) + designation = '%s|%s' % (configuration, platform) + group.append( + ['ProjectConfiguration', {'Include': designation}, + ['Configuration', configuration], + ['Platform', platform]]) + return [group] + + +def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name): + namespace = os.path.splitext(gyp_file_name)[0] + return [ + ['PropertyGroup', {'Label': 'Globals'}, + ['ProjectGuid', guid], + ['Keyword', 'Win32Proj'], + ['RootNamespace', namespace], + ['IgnoreWarnCompileDuplicatedFilename', 'true'], + ] + ] + + +def _GetMSBuildConfigurationDetails(spec, build_file): + properties = {} + for name, settings in spec['configurations'].iteritems(): + msbuild_attributes = _GetMSBuildAttributes(spec, settings, build_file) + condition = _GetConfigurationCondition(name, settings) + character_set = msbuild_attributes.get('CharacterSet') + _AddConditionalProperty(properties, condition, 'ConfigurationType', + msbuild_attributes['ConfigurationType']) + if character_set: + _AddConditionalProperty(properties, condition, 'CharacterSet', + character_set) + return _GetMSBuildPropertyGroup(spec, 'Configuration', properties) + + +def _GetMSBuildLocalProperties(msbuild_toolset): + # Currently the only local property we support is PlatformToolset + properties = {} + if msbuild_toolset: + properties = [ + ['PropertyGroup', {'Label': 'Locals'}, + ['PlatformToolset', msbuild_toolset], + ] + ] + return properties + + +def _GetMSBuildPropertySheets(configurations): + user_props = r'$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props' + additional_props = {} + props_specified = False + for name, settings in sorted(configurations.iteritems()): + configuration = _GetConfigurationCondition(name, settings) + if settings.has_key('msbuild_props'): + additional_props[configuration] = _FixPaths(settings['msbuild_props']) + props_specified = True + else: + additional_props[configuration] = '' + + if not props_specified: + return [ + ['ImportGroup', + {'Label': 'PropertySheets'}, + ['Import', + {'Project': user_props, + 'Condition': "exists('%s')" % user_props, + 'Label': 'LocalAppDataPlatform' + } + ] + ] + ] + else: + sheets = [] + for condition, props in additional_props.iteritems(): + import_group = [ + 'ImportGroup', + {'Label': 'PropertySheets', + 'Condition': condition + }, + ['Import', + {'Project': user_props, + 'Condition': "exists('%s')" % user_props, + 'Label': 'LocalAppDataPlatform' + } + ] + ] + for props_file in props: + import_group.append(['Import', {'Project':props_file}]) + sheets.append(import_group) + return sheets + +def _ConvertMSVSBuildAttributes(spec, config, build_file): + config_type = _GetMSVSConfigurationType(spec, build_file) + msvs_attributes = _GetMSVSAttributes(spec, config, config_type) + msbuild_attributes = {} + for a in msvs_attributes: + if a in ['IntermediateDirectory', 'OutputDirectory']: + directory = MSVSSettings.ConvertVCMacrosToMSBuild(msvs_attributes[a]) + if not directory.endswith('\\'): + directory += '\\' + msbuild_attributes[a] = directory + elif a == 'CharacterSet': + msbuild_attributes[a] = _ConvertMSVSCharacterSet(msvs_attributes[a]) + elif a == 'ConfigurationType': + msbuild_attributes[a] = _ConvertMSVSConfigurationType(msvs_attributes[a]) + else: + print 'Warning: Do not know how to convert MSVS attribute ' + a + return msbuild_attributes + + +def _ConvertMSVSCharacterSet(char_set): + if char_set.isdigit(): + char_set = { + '0': 'MultiByte', + '1': 'Unicode', + '2': 'MultiByte', + }[char_set] + return char_set + + +def _ConvertMSVSConfigurationType(config_type): + if config_type.isdigit(): + config_type = { + '1': 'Application', + '2': 'DynamicLibrary', + '4': 'StaticLibrary', + '10': 'Utility' + }[config_type] + return config_type + + +def _GetMSBuildAttributes(spec, config, build_file): + if 'msbuild_configuration_attributes' not in config: + msbuild_attributes = _ConvertMSVSBuildAttributes(spec, config, build_file) + + else: + config_type = _GetMSVSConfigurationType(spec, build_file) + config_type = _ConvertMSVSConfigurationType(config_type) + msbuild_attributes = config.get('msbuild_configuration_attributes', {}) + msbuild_attributes.setdefault('ConfigurationType', config_type) + output_dir = msbuild_attributes.get('OutputDirectory', + '$(SolutionDir)$(Configuration)') + msbuild_attributes['OutputDirectory'] = _FixPath(output_dir) + '\\' + if 'IntermediateDirectory' not in msbuild_attributes: + intermediate = _FixPath('$(Configuration)') + '\\' + msbuild_attributes['IntermediateDirectory'] = intermediate + if 'CharacterSet' in msbuild_attributes: + msbuild_attributes['CharacterSet'] = _ConvertMSVSCharacterSet( + msbuild_attributes['CharacterSet']) + if 'TargetName' not in msbuild_attributes: + prefix = spec.get('product_prefix', '') + product_name = spec.get('product_name', '$(ProjectName)') + target_name = prefix + product_name + msbuild_attributes['TargetName'] = target_name + + if spec.get('msvs_external_builder'): + external_out_dir = spec.get('msvs_external_builder_out_dir', '.') + msbuild_attributes['OutputDirectory'] = _FixPath(external_out_dir) + '\\' + + # Make sure that 'TargetPath' matches 'Lib.OutputFile' or 'Link.OutputFile' + # (depending on the tool used) to avoid MSB8012 warning. + msbuild_tool_map = { + 'executable': 'Link', + 'shared_library': 'Link', + 'loadable_module': 'Link', + 'static_library': 'Lib', + } + msbuild_tool = msbuild_tool_map.get(spec['type']) + if msbuild_tool: + msbuild_settings = config['finalized_msbuild_settings'] + out_file = msbuild_settings[msbuild_tool].get('OutputFile') + if out_file: + msbuild_attributes['TargetPath'] = _FixPath(out_file) + target_ext = msbuild_settings[msbuild_tool].get('TargetExt') + if target_ext: + msbuild_attributes['TargetExt'] = target_ext + + return msbuild_attributes + + +def _GetMSBuildConfigurationGlobalProperties(spec, configurations, build_file): + # TODO(jeanluc) We could optimize out the following and do it only if + # there are actions. + # TODO(jeanluc) Handle the equivalent of setting 'CYGWIN=nontsec'. + new_paths = [] + cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])[0] + if cygwin_dirs: + cyg_path = '$(MSBuildProjectDirectory)\\%s\\bin\\' % _FixPath(cygwin_dirs) + new_paths.append(cyg_path) + # TODO(jeanluc) Change the convention to have both a cygwin_dir and a + # python_dir. + python_path = cyg_path.replace('cygwin\\bin', 'python_26') + new_paths.append(python_path) + if new_paths: + new_paths = '$(ExecutablePath);' + ';'.join(new_paths) + + properties = {} + for (name, configuration) in sorted(configurations.iteritems()): + condition = _GetConfigurationCondition(name, configuration) + attributes = _GetMSBuildAttributes(spec, configuration, build_file) + msbuild_settings = configuration['finalized_msbuild_settings'] + _AddConditionalProperty(properties, condition, 'IntDir', + attributes['IntermediateDirectory']) + _AddConditionalProperty(properties, condition, 'OutDir', + attributes['OutputDirectory']) + _AddConditionalProperty(properties, condition, 'TargetName', + attributes['TargetName']) + + if attributes.get('TargetPath'): + _AddConditionalProperty(properties, condition, 'TargetPath', + attributes['TargetPath']) + if attributes.get('TargetExt'): + _AddConditionalProperty(properties, condition, 'TargetExt', + attributes['TargetExt']) + + if new_paths: + _AddConditionalProperty(properties, condition, 'ExecutablePath', + new_paths) + tool_settings = msbuild_settings.get('', {}) + for name, value in sorted(tool_settings.iteritems()): + formatted_value = _GetValueFormattedForMSBuild('', name, value) + _AddConditionalProperty(properties, condition, name, formatted_value) + return _GetMSBuildPropertyGroup(spec, None, properties) + + +def _AddConditionalProperty(properties, condition, name, value): + """Adds a property / conditional value pair to a dictionary. + + Arguments: + properties: The dictionary to be modified. The key is the name of the + property. The value is itself a dictionary; its key is the value and + the value a list of condition for which this value is true. + condition: The condition under which the named property has the value. + name: The name of the property. + value: The value of the property. + """ + if name not in properties: + properties[name] = {} + values = properties[name] + if value not in values: + values[value] = [] + conditions = values[value] + conditions.append(condition) + + +# Regex for msvs variable references ( i.e. $(FOO) ). +MSVS_VARIABLE_REFERENCE = re.compile('\$\(([a-zA-Z_][a-zA-Z0-9_]*)\)') + + +def _GetMSBuildPropertyGroup(spec, label, properties): + """Returns a PropertyGroup definition for the specified properties. + + Arguments: + spec: The target project dict. + label: An optional label for the PropertyGroup. + properties: The dictionary to be converted. The key is the name of the + property. The value is itself a dictionary; its key is the value and + the value a list of condition for which this value is true. + """ + group = ['PropertyGroup'] + if label: + group.append({'Label': label}) + num_configurations = len(spec['configurations']) + def GetEdges(node): + # Use a definition of edges such that user_of_variable -> used_varible. + # This happens to be easier in this case, since a variable's + # definition contains all variables it references in a single string. + edges = set() + for value in sorted(properties[node].keys()): + # Add to edges all $(...) references to variables. + # + # Variable references that refer to names not in properties are excluded + # These can exist for instance to refer built in definitions like + # $(SolutionDir). + # + # Self references are ignored. Self reference is used in a few places to + # append to the default value. I.e. PATH=$(PATH);other_path + edges.update(set([v for v in MSVS_VARIABLE_REFERENCE.findall(value) + if v in properties and v != node])) + return edges + properties_ordered = gyp.common.TopologicallySorted( + properties.keys(), GetEdges) + # Walk properties in the reverse of a topological sort on + # user_of_variable -> used_variable as this ensures variables are + # defined before they are used. + # NOTE: reverse(topsort(DAG)) = topsort(reverse_edges(DAG)) + for name in reversed(properties_ordered): + values = properties[name] + for value, conditions in sorted(values.iteritems()): + if len(conditions) == num_configurations: + # If the value is the same all configurations, + # just add one unconditional entry. + group.append([name, value]) + else: + for condition in conditions: + group.append([name, {'Condition': condition}, value]) + return [group] + + +def _GetMSBuildToolSettingsSections(spec, configurations): + groups = [] + for (name, configuration) in sorted(configurations.iteritems()): + msbuild_settings = configuration['finalized_msbuild_settings'] + group = ['ItemDefinitionGroup', + {'Condition': _GetConfigurationCondition(name, configuration)} + ] + for tool_name, tool_settings in sorted(msbuild_settings.iteritems()): + # Skip the tool named '' which is a holder of global settings handled + # by _GetMSBuildConfigurationGlobalProperties. + if tool_name: + if tool_settings: + tool = [tool_name] + for name, value in sorted(tool_settings.iteritems()): + formatted_value = _GetValueFormattedForMSBuild(tool_name, name, + value) + tool.append([name, formatted_value]) + group.append(tool) + groups.append(group) + return groups + + +def _FinalizeMSBuildSettings(spec, configuration): + if 'msbuild_settings' in configuration: + converted = False + msbuild_settings = configuration['msbuild_settings'] + MSVSSettings.ValidateMSBuildSettings(msbuild_settings) + else: + converted = True + msvs_settings = configuration.get('msvs_settings', {}) + msbuild_settings = MSVSSettings.ConvertToMSBuildSettings(msvs_settings) + include_dirs, resource_include_dirs = _GetIncludeDirs(configuration) + libraries = _GetLibraries(spec) + library_dirs = _GetLibraryDirs(configuration) + out_file, _, msbuild_tool = _GetOutputFilePathAndTool(spec, msbuild=True) + target_ext = _GetOutputTargetExt(spec) + defines = _GetDefines(configuration) + if converted: + # Visual Studio 2010 has TR1 + defines = [d for d in defines if d != '_HAS_TR1=0'] + # Warn of ignored settings + ignored_settings = ['msvs_tool_files'] + for ignored_setting in ignored_settings: + value = configuration.get(ignored_setting) + if value: + print ('Warning: The automatic conversion to MSBuild does not handle ' + '%s. Ignoring setting of %s' % (ignored_setting, str(value))) + + defines = [_EscapeCppDefineForMSBuild(d) for d in defines] + disabled_warnings = _GetDisabledWarnings(configuration) + prebuild = configuration.get('msvs_prebuild') + postbuild = configuration.get('msvs_postbuild') + def_file = _GetModuleDefinition(spec) + precompiled_header = configuration.get('msvs_precompiled_header') + + # Add the information to the appropriate tool + # TODO(jeanluc) We could optimize and generate these settings only if + # the corresponding files are found, e.g. don't generate ResourceCompile + # if you don't have any resources. + _ToolAppend(msbuild_settings, 'ClCompile', + 'AdditionalIncludeDirectories', include_dirs) + _ToolAppend(msbuild_settings, 'ResourceCompile', + 'AdditionalIncludeDirectories', resource_include_dirs) + # Add in libraries, note that even for empty libraries, we want this + # set, to prevent inheriting default libraries from the enviroment. + _ToolSetOrAppend(msbuild_settings, 'Link', 'AdditionalDependencies', + libraries) + _ToolAppend(msbuild_settings, 'Link', 'AdditionalLibraryDirectories', + library_dirs) + if out_file: + _ToolAppend(msbuild_settings, msbuild_tool, 'OutputFile', out_file, + only_if_unset=True) + if target_ext: + _ToolAppend(msbuild_settings, msbuild_tool, 'TargetExt', target_ext, + only_if_unset=True) + # Add defines. + _ToolAppend(msbuild_settings, 'ClCompile', + 'PreprocessorDefinitions', defines) + _ToolAppend(msbuild_settings, 'ResourceCompile', + 'PreprocessorDefinitions', defines) + # Add disabled warnings. + _ToolAppend(msbuild_settings, 'ClCompile', + 'DisableSpecificWarnings', disabled_warnings) + # Turn on precompiled headers if appropriate. + if precompiled_header: + precompiled_header = os.path.split(precompiled_header)[1] + _ToolAppend(msbuild_settings, 'ClCompile', 'PrecompiledHeader', 'Use') + _ToolAppend(msbuild_settings, 'ClCompile', + 'PrecompiledHeaderFile', precompiled_header) + _ToolAppend(msbuild_settings, 'ClCompile', + 'ForcedIncludeFiles', [precompiled_header]) + # Loadable modules don't generate import libraries; + # tell dependent projects to not expect one. + if spec['type'] == 'loadable_module': + _ToolAppend(msbuild_settings, '', 'IgnoreImportLibrary', 'true') + # Set the module definition file if any. + if def_file: + _ToolAppend(msbuild_settings, 'Link', 'ModuleDefinitionFile', def_file) + configuration['finalized_msbuild_settings'] = msbuild_settings + if prebuild: + _ToolAppend(msbuild_settings, 'PreBuildEvent', 'Command', prebuild) + if postbuild: + _ToolAppend(msbuild_settings, 'PostBuildEvent', 'Command', postbuild) + + +def _GetValueFormattedForMSBuild(tool_name, name, value): + if type(value) == list: + # For some settings, VS2010 does not automatically extends the settings + # TODO(jeanluc) Is this what we want? + if name in ['AdditionalIncludeDirectories', + 'AdditionalLibraryDirectories', + 'AdditionalOptions', + 'DelayLoadDLLs', + 'DisableSpecificWarnings', + 'PreprocessorDefinitions']: + value.append('%%(%s)' % name) + # For most tools, entries in a list should be separated with ';' but some + # settings use a space. Check for those first. + exceptions = { + 'ClCompile': ['AdditionalOptions'], + 'Link': ['AdditionalOptions'], + 'Lib': ['AdditionalOptions']} + if tool_name in exceptions and name in exceptions[tool_name]: + char = ' ' + else: + char = ';' + formatted_value = char.join( + [MSVSSettings.ConvertVCMacrosToMSBuild(i) for i in value]) + else: + formatted_value = MSVSSettings.ConvertVCMacrosToMSBuild(value) + return formatted_value + + +def _VerifySourcesExist(sources, root_dir): + """Verifies that all source files exist on disk. + + Checks that all regular source files, i.e. not created at run time, + exist on disk. Missing files cause needless recompilation but no otherwise + visible errors. + + Arguments: + sources: A recursive list of Filter/file names. + root_dir: The root directory for the relative path names. + Returns: + A list of source files that cannot be found on disk. + """ + missing_sources = [] + for source in sources: + if isinstance(source, MSVSProject.Filter): + missing_sources.extend(_VerifySourcesExist(source.contents, root_dir)) + else: + if '$' not in source: + full_path = os.path.join(root_dir, source) + if not os.path.exists(full_path): + missing_sources.append(full_path) + return missing_sources + + +def _GetMSBuildSources(spec, sources, exclusions, extension_to_rule_name, + actions_spec, sources_handled_by_action, list_excluded): + groups = ['none', 'midl', 'include', 'compile', 'resource', 'rule'] + grouped_sources = {} + for g in groups: + grouped_sources[g] = [] + + _AddSources2(spec, sources, exclusions, grouped_sources, + extension_to_rule_name, sources_handled_by_action, list_excluded) + sources = [] + for g in groups: + if grouped_sources[g]: + sources.append(['ItemGroup'] + grouped_sources[g]) + if actions_spec: + sources.append(['ItemGroup'] + actions_spec) + return sources + + +def _AddSources2(spec, sources, exclusions, grouped_sources, + extension_to_rule_name, sources_handled_by_action, + list_excluded): + extensions_excluded_from_precompile = [] + for source in sources: + if isinstance(source, MSVSProject.Filter): + _AddSources2(spec, source.contents, exclusions, grouped_sources, + extension_to_rule_name, sources_handled_by_action, + list_excluded) + else: + if not source in sources_handled_by_action: + detail = [] + excluded_configurations = exclusions.get(source, []) + if len(excluded_configurations) == len(spec['configurations']): + detail.append(['ExcludedFromBuild', 'true']) + else: + for config_name, configuration in sorted(excluded_configurations): + condition = _GetConfigurationCondition(config_name, configuration) + detail.append(['ExcludedFromBuild', + {'Condition': condition}, + 'true']) + # Add precompile if needed + for config_name, configuration in spec['configurations'].iteritems(): + precompiled_source = configuration.get('msvs_precompiled_source', '') + if precompiled_source != '': + precompiled_source = _FixPath(precompiled_source) + if not extensions_excluded_from_precompile: + # If the precompiled header is generated by a C source, we must + # not try to use it for C++ sources, and vice versa. + basename, extension = os.path.splitext(precompiled_source) + if extension == '.c': + extensions_excluded_from_precompile = ['.cc', '.cpp', '.cxx'] + else: + extensions_excluded_from_precompile = ['.c'] + + if precompiled_source == source: + condition = _GetConfigurationCondition(config_name, configuration) + detail.append(['PrecompiledHeader', + {'Condition': condition}, + 'Create' + ]) + else: + # Turn off precompiled header usage for source files of a + # different type than the file that generated the + # precompiled header. + for extension in extensions_excluded_from_precompile: + if source.endswith(extension): + detail.append(['PrecompiledHeader', '']) + detail.append(['ForcedIncludeFiles', '']) + + group, element = _MapFileToMsBuildSourceType(source, + extension_to_rule_name) + grouped_sources[group].append([element, {'Include': source}] + detail) + + +def _GetMSBuildProjectReferences(project): + references = [] + if project.dependencies: + group = ['ItemGroup'] + for dependency in project.dependencies: + guid = dependency.guid + project_dir = os.path.split(project.path)[0] + relative_path = gyp.common.RelativePath(dependency.path, project_dir) + project_ref = ['ProjectReference', + {'Include': relative_path}, + ['Project', guid], + ['ReferenceOutputAssembly', 'false'] + ] + for config in dependency.spec.get('configurations', {}).itervalues(): + # If it's disabled in any config, turn it off in the reference. + if config.get('msvs_2010_disable_uldi_when_referenced', 0): + project_ref.append(['UseLibraryDependencyInputs', 'false']) + break + group.append(project_ref) + references.append(group) + return references + + +def _GenerateMSBuildProject(project, options, version, generator_flags): + spec = project.spec + configurations = spec['configurations'] + project_dir, project_file_name = os.path.split(project.path) + gyp.common.EnsureDirExists(project.path) + # Prepare list of sources and excluded sources. + gyp_path = _NormalizedSource(project.build_file) + relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, project_dir) + + gyp_file = os.path.split(project.build_file)[1] + sources, excluded_sources = _PrepareListOfSources(spec, generator_flags, + gyp_file) + # Add rules. + actions_to_add = {} + props_files_of_rules = set() + targets_files_of_rules = set() + extension_to_rule_name = {} + list_excluded = generator_flags.get('msvs_list_excluded_files', True) + + # Don't generate rules if we are using an external builder like ninja. + if not spec.get('msvs_external_builder'): + _GenerateRulesForMSBuild(project_dir, options, spec, + sources, excluded_sources, + props_files_of_rules, targets_files_of_rules, + actions_to_add, extension_to_rule_name) + else: + rules = spec.get('rules', []) + _AdjustSourcesForRules(spec, rules, sources, excluded_sources) + + sources, excluded_sources, excluded_idl = ( + _AdjustSourcesAndConvertToFilterHierarchy(spec, options, + project_dir, sources, + excluded_sources, + list_excluded, version)) + + # Don't add actions if we are using an external builder like ninja. + if not spec.get('msvs_external_builder'): + _AddActions(actions_to_add, spec, project.build_file) + _AddCopies(actions_to_add, spec) + + # NOTE: this stanza must appear after all actions have been decided. + # Don't excluded sources with actions attached, or they won't run. + excluded_sources = _FilterActionsFromExcluded( + excluded_sources, actions_to_add) + + exclusions = _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl) + actions_spec, sources_handled_by_action = _GenerateActionsForMSBuild( + spec, actions_to_add) + + _GenerateMSBuildFiltersFile(project.path + '.filters', sources, + extension_to_rule_name) + missing_sources = _VerifySourcesExist(sources, project_dir) + + for configuration in configurations.itervalues(): + _FinalizeMSBuildSettings(spec, configuration) + + # Add attributes to root element + + import_default_section = [ + ['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.Default.props'}]] + import_cpp_props_section = [ + ['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.props'}]] + import_cpp_targets_section = [ + ['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.targets'}]] + macro_section = [['PropertyGroup', {'Label': 'UserMacros'}]] + + content = [ + 'Project', + {'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003', + 'ToolsVersion': version.ProjectVersion(), + 'DefaultTargets': 'Build' + }] + + content += _GetMSBuildProjectConfigurations(configurations) + content += _GetMSBuildGlobalProperties(spec, project.guid, project_file_name) + content += import_default_section + content += _GetMSBuildConfigurationDetails(spec, project.build_file) + content += _GetMSBuildLocalProperties(project.msbuild_toolset) + content += import_cpp_props_section + content += _GetMSBuildExtensions(props_files_of_rules) + content += _GetMSBuildPropertySheets(configurations) + content += macro_section + content += _GetMSBuildConfigurationGlobalProperties(spec, configurations, + project.build_file) + content += _GetMSBuildToolSettingsSections(spec, configurations) + content += _GetMSBuildSources( + spec, sources, exclusions, extension_to_rule_name, actions_spec, + sources_handled_by_action, list_excluded) + content += _GetMSBuildProjectReferences(project) + content += import_cpp_targets_section + content += _GetMSBuildExtensionTargets(targets_files_of_rules) + + if spec.get('msvs_external_builder'): + content += _GetMSBuildExternalBuilderTargets(spec) + + # TODO(jeanluc) File a bug to get rid of runas. We had in MSVS: + # has_run_as = _WriteMSVSUserFile(project.path, version, spec) + + easy_xml.WriteXmlIfChanged(content, project.path, pretty=True, win32=True) + + return missing_sources + + +def _GetMSBuildExternalBuilderTargets(spec): + """Return a list of MSBuild targets for external builders. + + The "Build" and "Clean" targets are always generated. If the spec contains + 'msvs_external_builder_clcompile_cmd', then the "ClCompile" target will also + be generated, to support building selected C/C++ files. + + Arguments: + spec: The gyp target spec. + Returns: + List of MSBuild 'Target' specs. + """ + build_cmd = _BuildCommandLineForRuleRaw( + spec, spec['msvs_external_builder_build_cmd'], + False, False, False, False) + build_target = ['Target', {'Name': 'Build'}] + build_target.append(['Exec', {'Command': build_cmd}]) + + clean_cmd = _BuildCommandLineForRuleRaw( + spec, spec['msvs_external_builder_clean_cmd'], + False, False, False, False) + clean_target = ['Target', {'Name': 'Clean'}] + clean_target.append(['Exec', {'Command': clean_cmd}]) + + targets = [build_target, clean_target] + + if spec.get('msvs_external_builder_clcompile_cmd'): + clcompile_cmd = _BuildCommandLineForRuleRaw( + spec, spec['msvs_external_builder_clcompile_cmd'], + False, False, False, False) + clcompile_target = ['Target', {'Name': 'ClCompile'}] + clcompile_target.append(['Exec', {'Command': clcompile_cmd}]) + targets.append(clcompile_target) + + return targets + + +def _GetMSBuildExtensions(props_files_of_rules): + extensions = ['ImportGroup', {'Label': 'ExtensionSettings'}] + for props_file in props_files_of_rules: + extensions.append(['Import', {'Project': props_file}]) + return [extensions] + + +def _GetMSBuildExtensionTargets(targets_files_of_rules): + targets_node = ['ImportGroup', {'Label': 'ExtensionTargets'}] + for targets_file in sorted(targets_files_of_rules): + targets_node.append(['Import', {'Project': targets_file}]) + return [targets_node] + + +def _GenerateActionsForMSBuild(spec, actions_to_add): + """Add actions accumulated into an actions_to_add, merging as needed. + + Arguments: + spec: the target project dict + actions_to_add: dictionary keyed on input name, which maps to a list of + dicts describing the actions attached to that input file. + + Returns: + A pair of (action specification, the sources handled by this action). + """ + sources_handled_by_action = OrderedSet() + actions_spec = [] + for primary_input, actions in actions_to_add.iteritems(): + inputs = OrderedSet() + outputs = OrderedSet() + descriptions = [] + commands = [] + for action in actions: + inputs.update(OrderedSet(action['inputs'])) + outputs.update(OrderedSet(action['outputs'])) + descriptions.append(action['description']) + cmd = action['command'] + # For most actions, add 'call' so that actions that invoke batch files + # return and continue executing. msbuild_use_call provides a way to + # disable this but I have not seen any adverse effect from doing that + # for everything. + if action.get('msbuild_use_call', True): + cmd = 'call ' + cmd + commands.append(cmd) + # Add the custom build action for one input file. + description = ', and also '.join(descriptions) + + # We can't join the commands simply with && because the command line will + # get too long. See also _AddActions: cygwin's setup_env mustn't be called + # for every invocation or the command that sets the PATH will grow too + # long. + command = ( + '\r\nif %errorlevel% neq 0 exit /b %errorlevel%\r\n'.join(commands)) + _AddMSBuildAction(spec, + primary_input, + inputs, + outputs, + command, + description, + sources_handled_by_action, + actions_spec) + return actions_spec, sources_handled_by_action + + +def _AddMSBuildAction(spec, primary_input, inputs, outputs, cmd, description, + sources_handled_by_action, actions_spec): + command = MSVSSettings.ConvertVCMacrosToMSBuild(cmd) + primary_input = _FixPath(primary_input) + inputs_array = _FixPaths(inputs) + outputs_array = _FixPaths(outputs) + additional_inputs = ';'.join([i for i in inputs_array + if i != primary_input]) + outputs = ';'.join(outputs_array) + sources_handled_by_action.add(primary_input) + action_spec = ['CustomBuild', {'Include': primary_input}] + action_spec.extend( + # TODO(jeanluc) 'Document' for all or just if as_sources? + [['FileType', 'Document'], + ['Command', command], + ['Message', description], + ['Outputs', outputs] + ]) + if additional_inputs: + action_spec.append(['AdditionalInputs', additional_inputs]) + actions_spec.append(action_spec) diff --git a/deps/gyp/pylib/gyp/generator/msvs_test.py b/deps/gyp/pylib/gyp/generator/msvs_test.py new file mode 100755 index 000000000..c0b021df5 --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/msvs_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" Unit tests for the msvs.py file. """ + +import gyp.generator.msvs as msvs +import unittest +import StringIO + + +class TestSequenceFunctions(unittest.TestCase): + + def setUp(self): + self.stderr = StringIO.StringIO() + + def test_GetLibraries(self): + self.assertEqual( + msvs._GetLibraries({}), + []) + self.assertEqual( + msvs._GetLibraries({'libraries': []}), + []) + self.assertEqual( + msvs._GetLibraries({'other':'foo', 'libraries': ['a.lib']}), + ['a.lib']) + self.assertEqual( + msvs._GetLibraries({'libraries': ['-la']}), + ['a.lib']) + self.assertEqual( + msvs._GetLibraries({'libraries': ['a.lib', 'b.lib', 'c.lib', '-lb.lib', + '-lb.lib', 'd.lib', 'a.lib']}), + ['c.lib', 'b.lib', 'd.lib', 'a.lib']) + +if __name__ == '__main__': + unittest.main() diff --git a/deps/gyp/pylib/gyp/generator/ninja.py b/deps/gyp/pylib/gyp/generator/ninja.py new file mode 100644 index 000000000..e3fafb5d4 --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/ninja.py @@ -0,0 +1,2213 @@ +# Copyright (c) 2013 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import collections +import copy +import hashlib +import json +import multiprocessing +import os.path +import re +import signal +import subprocess +import sys +import gyp +import gyp.common +import gyp.msvs_emulation +import gyp.MSVSUtil as MSVSUtil +import gyp.xcode_emulation +from cStringIO import StringIO + +from gyp.common import GetEnvironFallback +import gyp.ninja_syntax as ninja_syntax + +generator_default_variables = { + 'EXECUTABLE_PREFIX': '', + 'EXECUTABLE_SUFFIX': '', + 'STATIC_LIB_PREFIX': 'lib', + 'STATIC_LIB_SUFFIX': '.a', + 'SHARED_LIB_PREFIX': 'lib', + + # Gyp expects the following variables to be expandable by the build + # system to the appropriate locations. Ninja prefers paths to be + # known at gyp time. To resolve this, introduce special + # variables starting with $! and $| (which begin with a $ so gyp knows it + # should be treated specially, but is otherwise an invalid + # ninja/shell variable) that are passed to gyp here but expanded + # before writing out into the target .ninja files; see + # ExpandSpecial. + # $! is used for variables that represent a path and that can only appear at + # the start of a string, while $| is used for variables that can appear + # anywhere in a string. + 'INTERMEDIATE_DIR': '$!INTERMEDIATE_DIR', + 'SHARED_INTERMEDIATE_DIR': '$!PRODUCT_DIR/gen', + 'PRODUCT_DIR': '$!PRODUCT_DIR', + 'CONFIGURATION_NAME': '$|CONFIGURATION_NAME', + + # Special variables that may be used by gyp 'rule' targets. + # We generate definitions for these variables on the fly when processing a + # rule. + 'RULE_INPUT_ROOT': '${root}', + 'RULE_INPUT_DIRNAME': '${dirname}', + 'RULE_INPUT_PATH': '${source}', + 'RULE_INPUT_EXT': '${ext}', + 'RULE_INPUT_NAME': '${name}', +} + +# Placates pylint. +generator_additional_non_configuration_keys = [] +generator_additional_path_sections = [] +generator_extra_sources_for_rules = [] +generator_filelist_paths = None + +# TODO: figure out how to not build extra host objects in the non-cross-compile +# case when this is enabled, and enable unconditionally. +generator_supports_multiple_toolsets = ( + os.environ.get('GYP_CROSSCOMPILE') or + os.environ.get('AR_host') or + os.environ.get('CC_host') or + os.environ.get('CXX_host') or + os.environ.get('AR_target') or + os.environ.get('CC_target') or + os.environ.get('CXX_target')) + + +def StripPrefix(arg, prefix): + if arg.startswith(prefix): + return arg[len(prefix):] + return arg + + +def QuoteShellArgument(arg, flavor): + """Quote a string such that it will be interpreted as a single argument + by the shell.""" + # Rather than attempting to enumerate the bad shell characters, just + # whitelist common OK ones and quote anything else. + if re.match(r'^[a-zA-Z0-9_=.\\/-]+$', arg): + return arg # No quoting necessary. + if flavor == 'win': + return gyp.msvs_emulation.QuoteForRspFile(arg) + return "'" + arg.replace("'", "'" + '"\'"' + "'") + "'" + + +def Define(d, flavor): + """Takes a preprocessor define and returns a -D parameter that's ninja- and + shell-escaped.""" + if flavor == 'win': + # cl.exe replaces literal # characters with = in preprocesor definitions for + # some reason. Octal-encode to work around that. + d = d.replace('#', '\\%03o' % ord('#')) + return QuoteShellArgument(ninja_syntax.escape('-D' + d), flavor) + + +def AddArch(output, arch): + """Adds an arch string to an output path.""" + output, extension = os.path.splitext(output) + return '%s.%s%s' % (output, arch, extension) + + +class Target: + """Target represents the paths used within a single gyp target. + + Conceptually, building a single target A is a series of steps: + + 1) actions/rules/copies generates source/resources/etc. + 2) compiles generates .o files + 3) link generates a binary (library/executable) + 4) bundle merges the above in a mac bundle + + (Any of these steps can be optional.) + + From a build ordering perspective, a dependent target B could just + depend on the last output of this series of steps. + + But some dependent commands sometimes need to reach inside the box. + For example, when linking B it needs to get the path to the static + library generated by A. + + This object stores those paths. To keep things simple, member + variables only store concrete paths to single files, while methods + compute derived values like "the last output of the target". + """ + def __init__(self, type): + # Gyp type ("static_library", etc.) of this target. + self.type = type + # File representing whether any input dependencies necessary for + # dependent actions have completed. + self.preaction_stamp = None + # File representing whether any input dependencies necessary for + # dependent compiles have completed. + self.precompile_stamp = None + # File representing the completion of actions/rules/copies, if any. + self.actions_stamp = None + # Path to the output of the link step, if any. + self.binary = None + # Path to the file representing the completion of building the bundle, + # if any. + self.bundle = None + # On Windows, incremental linking requires linking against all the .objs + # that compose a .lib (rather than the .lib itself). That list is stored + # here. + self.component_objs = None + # Windows only. The import .lib is the output of a build step, but + # because dependents only link against the lib (not both the lib and the + # dll) we keep track of the import library here. + self.import_lib = None + + def Linkable(self): + """Return true if this is a target that can be linked against.""" + return self.type in ('static_library', 'shared_library') + + def UsesToc(self, flavor): + """Return true if the target should produce a restat rule based on a TOC + file.""" + # For bundles, the .TOC should be produced for the binary, not for + # FinalOutput(). But the naive approach would put the TOC file into the + # bundle, so don't do this for bundles for now. + if flavor == 'win' or self.bundle: + return False + return self.type in ('shared_library', 'loadable_module') + + def PreActionInput(self, flavor): + """Return the path, if any, that should be used as a dependency of + any dependent action step.""" + if self.UsesToc(flavor): + return self.FinalOutput() + '.TOC' + return self.FinalOutput() or self.preaction_stamp + + def PreCompileInput(self): + """Return the path, if any, that should be used as a dependency of + any dependent compile step.""" + return self.actions_stamp or self.precompile_stamp + + def FinalOutput(self): + """Return the last output of the target, which depends on all prior + steps.""" + return self.bundle or self.binary or self.actions_stamp + + +# A small discourse on paths as used within the Ninja build: +# All files we produce (both at gyp and at build time) appear in the +# build directory (e.g. out/Debug). +# +# Paths within a given .gyp file are always relative to the directory +# containing the .gyp file. Call these "gyp paths". This includes +# sources as well as the starting directory a given gyp rule/action +# expects to be run from. We call the path from the source root to +# the gyp file the "base directory" within the per-.gyp-file +# NinjaWriter code. +# +# All paths as written into the .ninja files are relative to the build +# directory. Call these paths "ninja paths". +# +# We translate between these two notions of paths with two helper +# functions: +# +# - GypPathToNinja translates a gyp path (i.e. relative to the .gyp file) +# into the equivalent ninja path. +# +# - GypPathToUniqueOutput translates a gyp path into a ninja path to write +# an output file; the result can be namespaced such that it is unique +# to the input file name as well as the output target name. + +class NinjaWriter: + def __init__(self, qualified_target, target_outputs, base_dir, build_dir, + output_file, toplevel_build, output_file_name, flavor, + toplevel_dir=None): + """ + base_dir: path from source root to directory containing this gyp file, + by gyp semantics, all input paths are relative to this + build_dir: path from source root to build output + toplevel_dir: path to the toplevel directory + """ + + self.qualified_target = qualified_target + self.target_outputs = target_outputs + self.base_dir = base_dir + self.build_dir = build_dir + self.ninja = ninja_syntax.Writer(output_file) + self.toplevel_build = toplevel_build + self.output_file_name = output_file_name + + self.flavor = flavor + self.abs_build_dir = None + if toplevel_dir is not None: + self.abs_build_dir = os.path.abspath(os.path.join(toplevel_dir, + build_dir)) + self.obj_ext = '.obj' if flavor == 'win' else '.o' + if flavor == 'win': + # See docstring of msvs_emulation.GenerateEnvironmentFiles(). + self.win_env = {} + for arch in ('x86', 'x64'): + self.win_env[arch] = 'environment.' + arch + + # Relative path from build output dir to base dir. + build_to_top = gyp.common.InvertRelativePath(build_dir, toplevel_dir) + self.build_to_base = os.path.join(build_to_top, base_dir) + # Relative path from base dir to build dir. + base_to_top = gyp.common.InvertRelativePath(base_dir, toplevel_dir) + self.base_to_build = os.path.join(base_to_top, build_dir) + + def ExpandSpecial(self, path, product_dir=None): + """Expand specials like $!PRODUCT_DIR in |path|. + + If |product_dir| is None, assumes the cwd is already the product + dir. Otherwise, |product_dir| is the relative path to the product + dir. + """ + + PRODUCT_DIR = '$!PRODUCT_DIR' + if PRODUCT_DIR in path: + if product_dir: + path = path.replace(PRODUCT_DIR, product_dir) + else: + path = path.replace(PRODUCT_DIR + '/', '') + path = path.replace(PRODUCT_DIR + '\\', '') + path = path.replace(PRODUCT_DIR, '.') + + INTERMEDIATE_DIR = '$!INTERMEDIATE_DIR' + if INTERMEDIATE_DIR in path: + int_dir = self.GypPathToUniqueOutput('gen') + # GypPathToUniqueOutput generates a path relative to the product dir, + # so insert product_dir in front if it is provided. + path = path.replace(INTERMEDIATE_DIR, + os.path.join(product_dir or '', int_dir)) + + CONFIGURATION_NAME = '$|CONFIGURATION_NAME' + path = path.replace(CONFIGURATION_NAME, self.config_name) + + return path + + def ExpandRuleVariables(self, path, root, dirname, source, ext, name): + if self.flavor == 'win': + path = self.msvs_settings.ConvertVSMacros( + path, config=self.config_name) + path = path.replace(generator_default_variables['RULE_INPUT_ROOT'], root) + path = path.replace(generator_default_variables['RULE_INPUT_DIRNAME'], + dirname) + path = path.replace(generator_default_variables['RULE_INPUT_PATH'], source) + path = path.replace(generator_default_variables['RULE_INPUT_EXT'], ext) + path = path.replace(generator_default_variables['RULE_INPUT_NAME'], name) + return path + + def GypPathToNinja(self, path, env=None): + """Translate a gyp path to a ninja path, optionally expanding environment + variable references in |path| with |env|. + + See the above discourse on path conversions.""" + if env: + if self.flavor == 'mac': + path = gyp.xcode_emulation.ExpandEnvVars(path, env) + elif self.flavor == 'win': + path = gyp.msvs_emulation.ExpandMacros(path, env) + if path.startswith('$!'): + expanded = self.ExpandSpecial(path) + if self.flavor == 'win': + expanded = os.path.normpath(expanded) + return expanded + if '$|' in path: + path = self.ExpandSpecial(path) + assert '$' not in path, path + return os.path.normpath(os.path.join(self.build_to_base, path)) + + def GypPathToUniqueOutput(self, path, qualified=True): + """Translate a gyp path to a ninja path for writing output. + + If qualified is True, qualify the resulting filename with the name + of the target. This is necessary when e.g. compiling the same + path twice for two separate output targets. + + See the above discourse on path conversions.""" + + path = self.ExpandSpecial(path) + assert not path.startswith('$'), path + + # Translate the path following this scheme: + # Input: foo/bar.gyp, target targ, references baz/out.o + # Output: obj/foo/baz/targ.out.o (if qualified) + # obj/foo/baz/out.o (otherwise) + # (and obj.host instead of obj for cross-compiles) + # + # Why this scheme and not some other one? + # 1) for a given input, you can compute all derived outputs by matching + # its path, even if the input is brought via a gyp file with '..'. + # 2) simple files like libraries and stamps have a simple filename. + + obj = 'obj' + if self.toolset != 'target': + obj += '.' + self.toolset + + path_dir, path_basename = os.path.split(path) + if qualified: + path_basename = self.name + '.' + path_basename + return os.path.normpath(os.path.join(obj, self.base_dir, path_dir, + path_basename)) + + def WriteCollapsedDependencies(self, name, targets, order_only=None): + """Given a list of targets, return a path for a single file + representing the result of building all the targets or None. + + Uses a stamp file if necessary.""" + + assert targets == filter(None, targets), targets + if len(targets) == 0: + assert not order_only + return None + if len(targets) > 1 or order_only: + stamp = self.GypPathToUniqueOutput(name + '.stamp') + targets = self.ninja.build(stamp, 'stamp', targets, order_only=order_only) + self.ninja.newline() + return targets[0] + + def _SubninjaNameForArch(self, arch): + output_file_base = os.path.splitext(self.output_file_name)[0] + return '%s.%s.ninja' % (output_file_base, arch) + + def WriteSpec(self, spec, config_name, generator_flags): + """The main entry point for NinjaWriter: write the build rules for a spec. + + Returns a Target object, which represents the output paths for this spec. + Returns None if there are no outputs (e.g. a settings-only 'none' type + target).""" + + self.config_name = config_name + self.name = spec['target_name'] + self.toolset = spec['toolset'] + config = spec['configurations'][config_name] + self.target = Target(spec['type']) + self.is_standalone_static_library = bool( + spec.get('standalone_static_library', 0)) + # Track if this target contains any C++ files, to decide if gcc or g++ + # should be used for linking. + self.uses_cpp = False + + self.is_mac_bundle = gyp.xcode_emulation.IsMacBundle(self.flavor, spec) + self.xcode_settings = self.msvs_settings = None + if self.flavor == 'mac': + self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec) + if self.flavor == 'win': + self.msvs_settings = gyp.msvs_emulation.MsvsSettings(spec, + generator_flags) + arch = self.msvs_settings.GetArch(config_name) + self.ninja.variable('arch', self.win_env[arch]) + self.ninja.variable('cc', '$cl_' + arch) + self.ninja.variable('cxx', '$cl_' + arch) + + if self.flavor == 'mac': + self.archs = self.xcode_settings.GetActiveArchs(config_name) + if len(self.archs) > 1: + self.arch_subninjas = dict( + (arch, ninja_syntax.Writer( + OpenOutput(os.path.join(self.toplevel_build, + self._SubninjaNameForArch(arch)), + 'w'))) + for arch in self.archs) + + # Compute predepends for all rules. + # actions_depends is the dependencies this target depends on before running + # any of its action/rule/copy steps. + # compile_depends is the dependencies this target depends on before running + # any of its compile steps. + actions_depends = [] + compile_depends = [] + # TODO(evan): it is rather confusing which things are lists and which + # are strings. Fix these. + if 'dependencies' in spec: + for dep in spec['dependencies']: + if dep in self.target_outputs: + target = self.target_outputs[dep] + actions_depends.append(target.PreActionInput(self.flavor)) + compile_depends.append(target.PreCompileInput()) + actions_depends = filter(None, actions_depends) + compile_depends = filter(None, compile_depends) + actions_depends = self.WriteCollapsedDependencies('actions_depends', + actions_depends) + compile_depends = self.WriteCollapsedDependencies('compile_depends', + compile_depends) + self.target.preaction_stamp = actions_depends + self.target.precompile_stamp = compile_depends + + # Write out actions, rules, and copies. These must happen before we + # compile any sources, so compute a list of predependencies for sources + # while we do it. + extra_sources = [] + mac_bundle_depends = [] + self.target.actions_stamp = self.WriteActionsRulesCopies( + spec, extra_sources, actions_depends, mac_bundle_depends) + + # If we have actions/rules/copies, we depend directly on those, but + # otherwise we depend on dependent target's actions/rules/copies etc. + # We never need to explicitly depend on previous target's link steps, + # because no compile ever depends on them. + compile_depends_stamp = (self.target.actions_stamp or compile_depends) + + # Write out the compilation steps, if any. + link_deps = [] + sources = extra_sources + spec.get('sources', []) + if sources: + if self.flavor == 'mac' and len(self.archs) > 1: + # Write subninja file containing compile and link commands scoped to + # a single arch if a fat binary is being built. + for arch in self.archs: + self.ninja.subninja(self._SubninjaNameForArch(arch)) + + pch = None + if self.flavor == 'win': + gyp.msvs_emulation.VerifyMissingSources( + sources, self.abs_build_dir, generator_flags, self.GypPathToNinja) + pch = gyp.msvs_emulation.PrecompiledHeader( + self.msvs_settings, config_name, self.GypPathToNinja, + self.GypPathToUniqueOutput, self.obj_ext) + else: + pch = gyp.xcode_emulation.MacPrefixHeader( + self.xcode_settings, self.GypPathToNinja, + lambda path, lang: self.GypPathToUniqueOutput(path + '-' + lang)) + link_deps = self.WriteSources( + self.ninja, config_name, config, sources, compile_depends_stamp, pch, + spec) + # Some actions/rules output 'sources' that are already object files. + obj_outputs = [f for f in sources if f.endswith(self.obj_ext)] + if obj_outputs: + if self.flavor != 'mac' or len(self.archs) == 1: + link_deps += [self.GypPathToNinja(o) for o in obj_outputs] + else: + print "Warning: Actions/rules writing object files don't work with " \ + "multiarch targets, dropping. (target %s)" % spec['target_name'] + elif self.flavor == 'mac' and len(self.archs) > 1: + link_deps = collections.defaultdict(list) + + + if self.flavor == 'win' and self.target.type == 'static_library': + self.target.component_objs = link_deps + + # Write out a link step, if needed. + output = None + is_empty_bundle = not link_deps and not mac_bundle_depends + if link_deps or self.target.actions_stamp or actions_depends: + output = self.WriteTarget(spec, config_name, config, link_deps, + self.target.actions_stamp or actions_depends) + if self.is_mac_bundle: + mac_bundle_depends.append(output) + + # Bundle all of the above together, if needed. + if self.is_mac_bundle: + output = self.WriteMacBundle(spec, mac_bundle_depends, is_empty_bundle) + + if not output: + return None + + assert self.target.FinalOutput(), output + return self.target + + def _WinIdlRule(self, source, prebuild, outputs): + """Handle the implicit VS .idl rule for one source file. Fills |outputs| + with files that are generated.""" + outdir, output, vars, flags = self.msvs_settings.GetIdlBuildData( + source, self.config_name) + outdir = self.GypPathToNinja(outdir) + def fix_path(path, rel=None): + path = os.path.join(outdir, path) + dirname, basename = os.path.split(source) + root, ext = os.path.splitext(basename) + path = self.ExpandRuleVariables( + path, root, dirname, source, ext, basename) + if rel: + path = os.path.relpath(path, rel) + return path + vars = [(name, fix_path(value, outdir)) for name, value in vars] + output = [fix_path(p) for p in output] + vars.append(('outdir', outdir)) + vars.append(('idlflags', flags)) + input = self.GypPathToNinja(source) + self.ninja.build(output, 'idl', input, + variables=vars, order_only=prebuild) + outputs.extend(output) + + def WriteWinIdlFiles(self, spec, prebuild): + """Writes rules to match MSVS's implicit idl handling.""" + assert self.flavor == 'win' + if self.msvs_settings.HasExplicitIdlRules(spec): + return [] + outputs = [] + for source in filter(lambda x: x.endswith('.idl'), spec['sources']): + self._WinIdlRule(source, prebuild, outputs) + return outputs + + def WriteActionsRulesCopies(self, spec, extra_sources, prebuild, + mac_bundle_depends): + """Write out the Actions, Rules, and Copies steps. Return a path + representing the outputs of these steps.""" + outputs = [] + if self.is_mac_bundle: + mac_bundle_resources = spec.get('mac_bundle_resources', [])[:] + else: + mac_bundle_resources = [] + extra_mac_bundle_resources = [] + + if 'actions' in spec: + outputs += self.WriteActions(spec['actions'], extra_sources, prebuild, + extra_mac_bundle_resources) + if 'rules' in spec: + outputs += self.WriteRules(spec['rules'], extra_sources, prebuild, + mac_bundle_resources, + extra_mac_bundle_resources) + if 'copies' in spec: + outputs += self.WriteCopies(spec['copies'], prebuild, mac_bundle_depends) + + if 'sources' in spec and self.flavor == 'win': + outputs += self.WriteWinIdlFiles(spec, prebuild) + + stamp = self.WriteCollapsedDependencies('actions_rules_copies', outputs) + + if self.is_mac_bundle: + self.WriteMacBundleResources( + extra_mac_bundle_resources + mac_bundle_resources, mac_bundle_depends) + self.WriteMacInfoPlist(mac_bundle_depends) + + return stamp + + def GenerateDescription(self, verb, message, fallback): + """Generate and return a description of a build step. + + |verb| is the short summary, e.g. ACTION or RULE. + |message| is a hand-written description, or None if not available. + |fallback| is the gyp-level name of the step, usable as a fallback. + """ + if self.toolset != 'target': + verb += '(%s)' % self.toolset + if message: + return '%s %s' % (verb, self.ExpandSpecial(message)) + else: + return '%s %s: %s' % (verb, self.name, fallback) + + def WriteActions(self, actions, extra_sources, prebuild, + extra_mac_bundle_resources): + # Actions cd into the base directory. + env = self.GetToolchainEnv() + all_outputs = [] + for action in actions: + # First write out a rule for the action. + name = '%s_%s' % (action['action_name'], + hashlib.md5(self.qualified_target).hexdigest()) + description = self.GenerateDescription('ACTION', + action.get('message', None), + name) + is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(action) + if self.flavor == 'win' else False) + args = action['action'] + rule_name, _ = self.WriteNewNinjaRule(name, args, description, + is_cygwin, env=env) + + inputs = [self.GypPathToNinja(i, env) for i in action['inputs']] + if int(action.get('process_outputs_as_sources', False)): + extra_sources += action['outputs'] + if int(action.get('process_outputs_as_mac_bundle_resources', False)): + extra_mac_bundle_resources += action['outputs'] + outputs = [self.GypPathToNinja(o, env) for o in action['outputs']] + + # Then write out an edge using the rule. + self.ninja.build(outputs, rule_name, inputs, + order_only=prebuild) + all_outputs += outputs + + self.ninja.newline() + + return all_outputs + + def WriteRules(self, rules, extra_sources, prebuild, + mac_bundle_resources, extra_mac_bundle_resources): + env = self.GetToolchainEnv() + all_outputs = [] + for rule in rules: + # Skip a rule with no action and no inputs. + if 'action' not in rule and not rule.get('rule_sources', []): + continue + + # First write out a rule for the rule action. + name = '%s_%s' % (rule['rule_name'], + hashlib.md5(self.qualified_target).hexdigest()) + + args = rule['action'] + description = self.GenerateDescription( + 'RULE', + rule.get('message', None), + ('%s ' + generator_default_variables['RULE_INPUT_PATH']) % name) + is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(rule) + if self.flavor == 'win' else False) + rule_name, args = self.WriteNewNinjaRule( + name, args, description, is_cygwin, env=env) + + # TODO: if the command references the outputs directly, we should + # simplify it to just use $out. + + # Rules can potentially make use of some special variables which + # must vary per source file. + # Compute the list of variables we'll need to provide. + special_locals = ('source', 'root', 'dirname', 'ext', 'name') + needed_variables = set(['source']) + for argument in args: + for var in special_locals: + if ('${%s}' % var) in argument: + needed_variables.add(var) + + def cygwin_munge(path): + if is_cygwin: + return path.replace('\\', '/') + return path + + inputs = [self.GypPathToNinja(i, env) for i in rule.get('inputs', [])] + + # If there are n source files matching the rule, and m additional rule + # inputs, then adding 'inputs' to each build edge written below will + # write m * n inputs. Collapsing reduces this to m + n. + sources = rule.get('rule_sources', []) + num_inputs = len(inputs) + if prebuild: + num_inputs += 1 + if num_inputs > 2 and len(sources) > 2: + inputs = [self.WriteCollapsedDependencies( + rule['rule_name'], inputs, order_only=prebuild)] + prebuild = [] + + # For each source file, write an edge that generates all the outputs. + for source in sources: + source = os.path.normpath(source) + dirname, basename = os.path.split(source) + root, ext = os.path.splitext(basename) + + # Gather the list of inputs and outputs, expanding $vars if possible. + outputs = [self.ExpandRuleVariables(o, root, dirname, + source, ext, basename) + for o in rule['outputs']] + + if int(rule.get('process_outputs_as_sources', False)): + extra_sources += outputs + + was_mac_bundle_resource = source in mac_bundle_resources + if was_mac_bundle_resource or \ + int(rule.get('process_outputs_as_mac_bundle_resources', False)): + extra_mac_bundle_resources += outputs + # Note: This is n_resources * n_outputs_in_rule. Put to-be-removed + # items in a set and remove them all in a single pass if this becomes + # a performance issue. + if was_mac_bundle_resource: + mac_bundle_resources.remove(source) + + extra_bindings = [] + for var in needed_variables: + if var == 'root': + extra_bindings.append(('root', cygwin_munge(root))) + elif var == 'dirname': + # '$dirname' is a parameter to the rule action, which means + # it shouldn't be converted to a Ninja path. But we don't + # want $!PRODUCT_DIR in there either. + dirname_expanded = self.ExpandSpecial(dirname, self.base_to_build) + extra_bindings.append(('dirname', cygwin_munge(dirname_expanded))) + elif var == 'source': + # '$source' is a parameter to the rule action, which means + # it shouldn't be converted to a Ninja path. But we don't + # want $!PRODUCT_DIR in there either. + source_expanded = self.ExpandSpecial(source, self.base_to_build) + extra_bindings.append(('source', cygwin_munge(source_expanded))) + elif var == 'ext': + extra_bindings.append(('ext', ext)) + elif var == 'name': + extra_bindings.append(('name', cygwin_munge(basename))) + else: + assert var == None, repr(var) + + outputs = [self.GypPathToNinja(o, env) for o in outputs] + if self.flavor == 'win': + # WriteNewNinjaRule uses unique_name for creating an rsp file on win. + extra_bindings.append(('unique_name', + hashlib.md5(outputs[0]).hexdigest())) + self.ninja.build(outputs, rule_name, self.GypPathToNinja(source), + implicit=inputs, + order_only=prebuild, + variables=extra_bindings) + + all_outputs.extend(outputs) + + return all_outputs + + def WriteCopies(self, copies, prebuild, mac_bundle_depends): + outputs = [] + env = self.GetToolchainEnv() + for copy in copies: + for path in copy['files']: + # Normalize the path so trailing slashes don't confuse us. + path = os.path.normpath(path) + basename = os.path.split(path)[1] + src = self.GypPathToNinja(path, env) + dst = self.GypPathToNinja(os.path.join(copy['destination'], basename), + env) + outputs += self.ninja.build(dst, 'copy', src, order_only=prebuild) + if self.is_mac_bundle: + # gyp has mac_bundle_resources to copy things into a bundle's + # Resources folder, but there's no built-in way to copy files to other + # places in the bundle. Hence, some targets use copies for this. Check + # if this file is copied into the current bundle, and if so add it to + # the bundle depends so that dependent targets get rebuilt if the copy + # input changes. + if dst.startswith(self.xcode_settings.GetBundleContentsFolderPath()): + mac_bundle_depends.append(dst) + + return outputs + + def WriteMacBundleResources(self, resources, bundle_depends): + """Writes ninja edges for 'mac_bundle_resources'.""" + for output, res in gyp.xcode_emulation.GetMacBundleResources( + generator_default_variables['PRODUCT_DIR'], + self.xcode_settings, map(self.GypPathToNinja, resources)): + output = self.ExpandSpecial(output) + self.ninja.build(output, 'mac_tool', res, + variables=[('mactool_cmd', 'copy-bundle-resource')]) + bundle_depends.append(output) + + def WriteMacInfoPlist(self, bundle_depends): + """Write build rules for bundle Info.plist files.""" + info_plist, out, defines, extra_env = gyp.xcode_emulation.GetMacInfoPlist( + generator_default_variables['PRODUCT_DIR'], + self.xcode_settings, self.GypPathToNinja) + if not info_plist: + return + out = self.ExpandSpecial(out) + if defines: + # Create an intermediate file to store preprocessed results. + intermediate_plist = self.GypPathToUniqueOutput( + os.path.basename(info_plist)) + defines = ' '.join([Define(d, self.flavor) for d in defines]) + info_plist = self.ninja.build( + intermediate_plist, 'preprocess_infoplist', info_plist, + variables=[('defines',defines)]) + + env = self.GetSortedXcodeEnv(additional_settings=extra_env) + env = self.ComputeExportEnvString(env) + + keys = self.xcode_settings.GetExtraPlistItems(self.config_name) + keys = QuoteShellArgument(json.dumps(keys), self.flavor) + self.ninja.build(out, 'copy_infoplist', info_plist, + variables=[('env', env), ('keys', keys)]) + bundle_depends.append(out) + + def WriteSources(self, ninja_file, config_name, config, sources, predepends, + precompiled_header, spec): + """Write build rules to compile all of |sources|.""" + if self.toolset == 'host': + self.ninja.variable('ar', '$ar_host') + self.ninja.variable('cc', '$cc_host') + self.ninja.variable('cxx', '$cxx_host') + self.ninja.variable('ld', '$ld_host') + self.ninja.variable('ldxx', '$ldxx_host') + + if self.flavor != 'mac' or len(self.archs) == 1: + return self.WriteSourcesForArch( + self.ninja, config_name, config, sources, predepends, + precompiled_header, spec) + else: + return dict((arch, self.WriteSourcesForArch( + self.arch_subninjas[arch], config_name, config, sources, predepends, + precompiled_header, spec, arch=arch)) + for arch in self.archs) + + def WriteSourcesForArch(self, ninja_file, config_name, config, sources, + predepends, precompiled_header, spec, arch=None): + """Write build rules to compile all of |sources|.""" + + extra_defines = [] + if self.flavor == 'mac': + cflags = self.xcode_settings.GetCflags(config_name, arch=arch) + cflags_c = self.xcode_settings.GetCflagsC(config_name) + cflags_cc = self.xcode_settings.GetCflagsCC(config_name) + cflags_objc = ['$cflags_c'] + \ + self.xcode_settings.GetCflagsObjC(config_name) + cflags_objcc = ['$cflags_cc'] + \ + self.xcode_settings.GetCflagsObjCC(config_name) + elif self.flavor == 'win': + asmflags = self.msvs_settings.GetAsmflags(config_name) + cflags = self.msvs_settings.GetCflags(config_name) + cflags_c = self.msvs_settings.GetCflagsC(config_name) + cflags_cc = self.msvs_settings.GetCflagsCC(config_name) + extra_defines = self.msvs_settings.GetComputedDefines(config_name) + # See comment at cc_command for why there's two .pdb files. + pdbpath_c = pdbpath_cc = self.msvs_settings.GetCompilerPdbName( + config_name, self.ExpandSpecial) + if not pdbpath_c: + obj = 'obj' + if self.toolset != 'target': + obj += '.' + self.toolset + pdbpath = os.path.normpath(os.path.join(obj, self.base_dir, self.name)) + pdbpath_c = pdbpath + '.c.pdb' + pdbpath_cc = pdbpath + '.cc.pdb' + self.WriteVariableList(ninja_file, 'pdbname_c', [pdbpath_c]) + self.WriteVariableList(ninja_file, 'pdbname_cc', [pdbpath_cc]) + self.WriteVariableList(ninja_file, 'pchprefix', [self.name]) + else: + cflags = config.get('cflags', []) + cflags_c = config.get('cflags_c', []) + cflags_cc = config.get('cflags_cc', []) + + # Respect environment variables related to build, but target-specific + # flags can still override them. + if self.toolset == 'target': + cflags_c = (os.environ.get('CPPFLAGS', '').split() + + os.environ.get('CFLAGS', '').split() + cflags_c) + cflags_cc = (os.environ.get('CPPFLAGS', '').split() + + os.environ.get('CXXFLAGS', '').split() + cflags_cc) + + defines = config.get('defines', []) + extra_defines + self.WriteVariableList(ninja_file, 'defines', + [Define(d, self.flavor) for d in defines]) + if self.flavor == 'win': + self.WriteVariableList(ninja_file, 'asmflags', + map(self.ExpandSpecial, asmflags)) + self.WriteVariableList(ninja_file, 'rcflags', + [QuoteShellArgument(self.ExpandSpecial(f), self.flavor) + for f in self.msvs_settings.GetRcflags(config_name, + self.GypPathToNinja)]) + + include_dirs = config.get('include_dirs', []) + + env = self.GetToolchainEnv() + if self.flavor == 'win': + include_dirs = self.msvs_settings.AdjustIncludeDirs(include_dirs, + config_name) + self.WriteVariableList(ninja_file, 'includes', + [QuoteShellArgument('-I' + self.GypPathToNinja(i, env), self.flavor) + for i in include_dirs]) + + pch_commands = precompiled_header.GetPchBuildCommands(arch) + if self.flavor == 'mac': + # Most targets use no precompiled headers, so only write these if needed. + for ext, var in [('c', 'cflags_pch_c'), ('cc', 'cflags_pch_cc'), + ('m', 'cflags_pch_objc'), ('mm', 'cflags_pch_objcc')]: + include = precompiled_header.GetInclude(ext, arch) + if include: ninja_file.variable(var, include) + + self.WriteVariableList(ninja_file, 'cflags', + map(self.ExpandSpecial, cflags)) + self.WriteVariableList(ninja_file, 'cflags_c', + map(self.ExpandSpecial, cflags_c)) + self.WriteVariableList(ninja_file, 'cflags_cc', + map(self.ExpandSpecial, cflags_cc)) + if self.flavor == 'mac': + self.WriteVariableList(ninja_file, 'cflags_objc', + map(self.ExpandSpecial, cflags_objc)) + self.WriteVariableList(ninja_file, 'cflags_objcc', + map(self.ExpandSpecial, cflags_objcc)) + ninja_file.newline() + outputs = [] + has_rc_source = False + for source in sources: + filename, ext = os.path.splitext(source) + ext = ext[1:] + obj_ext = self.obj_ext + if ext in ('cc', 'cpp', 'cxx'): + command = 'cxx' + self.uses_cpp = True + elif ext == 'c' or (ext == 'S' and self.flavor != 'win'): + command = 'cc' + elif ext == 's' and self.flavor != 'win': # Doesn't generate .o.d files. + command = 'cc_s' + elif (self.flavor == 'win' and ext == 'asm' and + self.msvs_settings.GetArch(config_name) == 'x86' and + not self.msvs_settings.HasExplicitAsmRules(spec)): + # Asm files only get auto assembled for x86 (not x64). + command = 'asm' + # Add the _asm suffix as msvs is capable of handling .cc and + # .asm files of the same name without collision. + obj_ext = '_asm.obj' + elif self.flavor == 'mac' and ext == 'm': + command = 'objc' + elif self.flavor == 'mac' and ext == 'mm': + command = 'objcxx' + self.uses_cpp = True + elif self.flavor == 'win' and ext == 'rc': + command = 'rc' + obj_ext = '.res' + has_rc_source = True + else: + # Ignore unhandled extensions. + continue + input = self.GypPathToNinja(source) + output = self.GypPathToUniqueOutput(filename + obj_ext) + if arch is not None: + output = AddArch(output, arch) + implicit = precompiled_header.GetObjDependencies([input], [output], arch) + variables = [] + if self.flavor == 'win': + variables, output, implicit = precompiled_header.GetFlagsModifications( + input, output, implicit, command, cflags_c, cflags_cc, + self.ExpandSpecial) + ninja_file.build(output, command, input, + implicit=[gch for _, _, gch in implicit], + order_only=predepends, variables=variables) + outputs.append(output) + + if has_rc_source: + resource_include_dirs = config.get('resource_include_dirs', include_dirs) + self.WriteVariableList(ninja_file, 'resource_includes', + [QuoteShellArgument('-I' + self.GypPathToNinja(i, env), self.flavor) + for i in resource_include_dirs]) + + self.WritePchTargets(ninja_file, pch_commands) + + ninja_file.newline() + return outputs + + def WritePchTargets(self, ninja_file, pch_commands): + """Writes ninja rules to compile prefix headers.""" + if not pch_commands: + return + + for gch, lang_flag, lang, input in pch_commands: + var_name = { + 'c': 'cflags_pch_c', + 'cc': 'cflags_pch_cc', + 'm': 'cflags_pch_objc', + 'mm': 'cflags_pch_objcc', + }[lang] + + map = { 'c': 'cc', 'cc': 'cxx', 'm': 'objc', 'mm': 'objcxx', } + cmd = map.get(lang) + ninja_file.build(gch, cmd, input, variables=[(var_name, lang_flag)]) + + def WriteLink(self, spec, config_name, config, link_deps): + """Write out a link step. Fills out target.binary. """ + if self.flavor != 'mac' or len(self.archs) == 1: + return self.WriteLinkForArch( + self.ninja, spec, config_name, config, link_deps) + else: + output = self.ComputeOutput(spec) + inputs = [self.WriteLinkForArch(self.arch_subninjas[arch], spec, + config_name, config, link_deps[arch], + arch=arch) + for arch in self.archs] + extra_bindings = [] + if not self.is_mac_bundle: + self.AppendPostbuildVariable(extra_bindings, spec, output, output) + self.ninja.build(output, 'lipo', inputs, variables=extra_bindings) + return output + + def WriteLinkForArch(self, ninja_file, spec, config_name, config, + link_deps, arch=None): + """Write out a link step. Fills out target.binary. """ + command = { + 'executable': 'link', + 'loadable_module': 'solink_module', + 'shared_library': 'solink', + }[spec['type']] + command_suffix = '' + + implicit_deps = set() + solibs = set() + + if 'dependencies' in spec: + # Two kinds of dependencies: + # - Linkable dependencies (like a .a or a .so): add them to the link line. + # - Non-linkable dependencies (like a rule that generates a file + # and writes a stamp file): add them to implicit_deps + extra_link_deps = set() + for dep in spec['dependencies']: + target = self.target_outputs.get(dep) + if not target: + continue + linkable = target.Linkable() + if linkable: + new_deps = [] + if (self.flavor == 'win' and + target.component_objs and + self.msvs_settings.IsUseLibraryDependencyInputs(config_name)): + new_deps = target.component_objs + elif self.flavor == 'win' and target.import_lib: + new_deps = [target.import_lib] + elif target.UsesToc(self.flavor): + solibs.add(target.binary) + implicit_deps.add(target.binary + '.TOC') + else: + new_deps = [target.binary] + for new_dep in new_deps: + if new_dep not in extra_link_deps: + extra_link_deps.add(new_dep) + link_deps.append(new_dep) + + final_output = target.FinalOutput() + if not linkable or final_output != target.binary: + implicit_deps.add(final_output) + + extra_bindings = [] + if self.uses_cpp and self.flavor != 'win': + extra_bindings.append(('ld', '$ldxx')) + + output = self.ComputeOutput(spec, arch) + if arch is None and not self.is_mac_bundle: + self.AppendPostbuildVariable(extra_bindings, spec, output, output) + + is_executable = spec['type'] == 'executable' + # The ldflags config key is not used on mac or win. On those platforms + # linker flags are set via xcode_settings and msvs_settings, respectively. + env_ldflags = os.environ.get('LDFLAGS', '').split() + if self.flavor == 'mac': + ldflags = self.xcode_settings.GetLdflags(config_name, + self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']), + self.GypPathToNinja, arch) + ldflags = env_ldflags + ldflags + elif self.flavor == 'win': + manifest_base_name = self.GypPathToUniqueOutput( + self.ComputeOutputFileName(spec)) + ldflags, intermediate_manifest, manifest_files = \ + self.msvs_settings.GetLdflags(config_name, self.GypPathToNinja, + self.ExpandSpecial, manifest_base_name, + output, is_executable, + self.toplevel_build) + ldflags = env_ldflags + ldflags + self.WriteVariableList(ninja_file, 'manifests', manifest_files) + implicit_deps = implicit_deps.union(manifest_files) + if intermediate_manifest: + self.WriteVariableList( + ninja_file, 'intermediatemanifest', [intermediate_manifest]) + command_suffix = _GetWinLinkRuleNameSuffix( + self.msvs_settings.IsEmbedManifest(config_name)) + def_file = self.msvs_settings.GetDefFile(self.GypPathToNinja) + if def_file: + implicit_deps.add(def_file) + else: + # Respect environment variables related to build, but target-specific + # flags can still override them. + ldflags = env_ldflags + config.get('ldflags', []) + if is_executable and len(solibs): + rpath = 'lib/' + if self.toolset != 'target': + rpath += self.toolset + ldflags.append('-Wl,-rpath=\$$ORIGIN/%s' % rpath) + ldflags.append('-Wl,-rpath-link=%s' % rpath) + self.WriteVariableList(ninja_file, 'ldflags', + gyp.common.uniquer(map(self.ExpandSpecial, ldflags))) + + library_dirs = config.get('library_dirs', []) + if self.flavor == 'win': + library_dirs = [self.msvs_settings.ConvertVSMacros(l, config_name) + for l in library_dirs] + library_dirs = ['/LIBPATH:' + QuoteShellArgument(self.GypPathToNinja(l), + self.flavor) + for l in library_dirs] + else: + library_dirs = [QuoteShellArgument('-L' + self.GypPathToNinja(l), + self.flavor) + for l in library_dirs] + + libraries = gyp.common.uniquer(map(self.ExpandSpecial, + spec.get('libraries', []))) + if self.flavor == 'mac': + libraries = self.xcode_settings.AdjustLibraries(libraries, config_name) + elif self.flavor == 'win': + libraries = self.msvs_settings.AdjustLibraries(libraries) + + self.WriteVariableList(ninja_file, 'libs', library_dirs + libraries) + + linked_binary = output + + if command in ('solink', 'solink_module'): + extra_bindings.append(('soname', os.path.split(output)[1])) + extra_bindings.append(('lib', + gyp.common.EncodePOSIXShellArgument(output))) + if self.flavor != 'win': + link_file_list = output + if self.is_mac_bundle: + # 'Dependency Framework.framework/Versions/A/Dependency Framework' -> + # 'Dependency Framework.framework.rsp' + link_file_list = self.xcode_settings.GetWrapperName() + if arch: + link_file_list += '.' + arch + link_file_list += '.rsp' + # If an rspfile contains spaces, ninja surrounds the filename with + # quotes around it and then passes it to open(), creating a file with + # quotes in its name (and when looking for the rsp file, the name + # makes it through bash which strips the quotes) :-/ + link_file_list = link_file_list.replace(' ', '_') + extra_bindings.append( + ('link_file_list', + gyp.common.EncodePOSIXShellArgument(link_file_list))) + if self.flavor == 'win': + extra_bindings.append(('binary', output)) + if '/NOENTRY' not in ldflags: + self.target.import_lib = output + '.lib' + extra_bindings.append(('implibflag', + '/IMPLIB:%s' % self.target.import_lib)) + pdbname = self.msvs_settings.GetPDBName( + config_name, self.ExpandSpecial, output + '.pdb') + output = [output, self.target.import_lib] + if pdbname: + output.append(pdbname) + elif not self.is_mac_bundle: + output = [output, output + '.TOC'] + else: + command = command + '_notoc' + elif self.flavor == 'win': + extra_bindings.append(('binary', output)) + pdbname = self.msvs_settings.GetPDBName( + config_name, self.ExpandSpecial, output + '.pdb') + if pdbname: + output = [output, pdbname] + + + if len(solibs): + extra_bindings.append(('solibs', gyp.common.EncodePOSIXShellList(solibs))) + + ninja_file.build(output, command + command_suffix, link_deps, + implicit=list(implicit_deps), + variables=extra_bindings) + return linked_binary + + def WriteTarget(self, spec, config_name, config, link_deps, compile_deps): + extra_link_deps = any(self.target_outputs.get(dep).Linkable() + for dep in spec.get('dependencies', []) + if dep in self.target_outputs) + if spec['type'] == 'none' or (not link_deps and not extra_link_deps): + # TODO(evan): don't call this function for 'none' target types, as + # it doesn't do anything, and we fake out a 'binary' with a stamp file. + self.target.binary = compile_deps + self.target.type = 'none' + elif spec['type'] == 'static_library': + self.target.binary = self.ComputeOutput(spec) + if (self.flavor not in ('mac', 'openbsd', 'win') and not + self.is_standalone_static_library): + self.ninja.build(self.target.binary, 'alink_thin', link_deps, + order_only=compile_deps) + else: + variables = [] + if self.xcode_settings: + libtool_flags = self.xcode_settings.GetLibtoolflags(config_name) + if libtool_flags: + variables.append(('libtool_flags', libtool_flags)) + if self.msvs_settings: + libflags = self.msvs_settings.GetLibFlags(config_name, + self.GypPathToNinja) + variables.append(('libflags', libflags)) + + if self.flavor != 'mac' or len(self.archs) == 1: + self.AppendPostbuildVariable(variables, spec, + self.target.binary, self.target.binary) + self.ninja.build(self.target.binary, 'alink', link_deps, + order_only=compile_deps, variables=variables) + else: + inputs = [] + for arch in self.archs: + output = self.ComputeOutput(spec, arch) + self.arch_subninjas[arch].build(output, 'alink', link_deps[arch], + order_only=compile_deps, + variables=variables) + inputs.append(output) + # TODO: It's not clear if libtool_flags should be passed to the alink + # call that combines single-arch .a files into a fat .a file. + self.AppendPostbuildVariable(variables, spec, + self.target.binary, self.target.binary) + self.ninja.build(self.target.binary, 'alink', inputs, + # FIXME: test proving order_only=compile_deps isn't + # needed. + variables=variables) + else: + self.target.binary = self.WriteLink(spec, config_name, config, link_deps) + return self.target.binary + + def WriteMacBundle(self, spec, mac_bundle_depends, is_empty): + assert self.is_mac_bundle + package_framework = spec['type'] in ('shared_library', 'loadable_module') + output = self.ComputeMacBundleOutput() + if is_empty: + output += '.stamp' + variables = [] + self.AppendPostbuildVariable(variables, spec, output, self.target.binary, + is_command_start=not package_framework) + if package_framework and not is_empty: + variables.append(('version', self.xcode_settings.GetFrameworkVersion())) + self.ninja.build(output, 'package_framework', mac_bundle_depends, + variables=variables) + else: + self.ninja.build(output, 'stamp', mac_bundle_depends, + variables=variables) + self.target.bundle = output + return output + + def GetToolchainEnv(self, additional_settings=None): + """Returns the variables toolchain would set for build steps.""" + env = self.GetSortedXcodeEnv(additional_settings=additional_settings) + if self.flavor == 'win': + env = self.GetMsvsToolchainEnv( + additional_settings=additional_settings) + return env + + def GetMsvsToolchainEnv(self, additional_settings=None): + """Returns the variables Visual Studio would set for build steps.""" + return self.msvs_settings.GetVSMacroEnv('$!PRODUCT_DIR', + config=self.config_name) + + def GetSortedXcodeEnv(self, additional_settings=None): + """Returns the variables Xcode would set for build steps.""" + assert self.abs_build_dir + abs_build_dir = self.abs_build_dir + return gyp.xcode_emulation.GetSortedXcodeEnv( + self.xcode_settings, abs_build_dir, + os.path.join(abs_build_dir, self.build_to_base), self.config_name, + additional_settings) + + def GetSortedXcodePostbuildEnv(self): + """Returns the variables Xcode would set for postbuild steps.""" + postbuild_settings = {} + # CHROMIUM_STRIP_SAVE_FILE is a chromium-specific hack. + # TODO(thakis): It would be nice to have some general mechanism instead. + strip_save_file = self.xcode_settings.GetPerTargetSetting( + 'CHROMIUM_STRIP_SAVE_FILE') + if strip_save_file: + postbuild_settings['CHROMIUM_STRIP_SAVE_FILE'] = strip_save_file + return self.GetSortedXcodeEnv(additional_settings=postbuild_settings) + + def AppendPostbuildVariable(self, variables, spec, output, binary, + is_command_start=False): + """Adds a 'postbuild' variable if there is a postbuild for |output|.""" + postbuild = self.GetPostbuildCommand(spec, output, binary, is_command_start) + if postbuild: + variables.append(('postbuilds', postbuild)) + + def GetPostbuildCommand(self, spec, output, output_binary, is_command_start): + """Returns a shell command that runs all the postbuilds, and removes + |output| if any of them fails. If |is_command_start| is False, then the + returned string will start with ' && '.""" + if not self.xcode_settings or spec['type'] == 'none' or not output: + return '' + output = QuoteShellArgument(output, self.flavor) + postbuilds = gyp.xcode_emulation.GetSpecPostbuildCommands(spec, quiet=True) + if output_binary is not None: + postbuilds = self.xcode_settings.AddImplicitPostbuilds( + self.config_name, + os.path.normpath(os.path.join(self.base_to_build, output)), + QuoteShellArgument( + os.path.normpath(os.path.join(self.base_to_build, output_binary)), + self.flavor), + postbuilds, quiet=True) + + if not postbuilds: + return '' + # Postbuilds expect to be run in the gyp file's directory, so insert an + # implicit postbuild to cd to there. + postbuilds.insert(0, gyp.common.EncodePOSIXShellList( + ['cd', self.build_to_base])) + env = self.ComputeExportEnvString(self.GetSortedXcodePostbuildEnv()) + # G will be non-null if any postbuild fails. Run all postbuilds in a + # subshell. + commands = env + ' (' + \ + ' && '.join([ninja_syntax.escape(command) for command in postbuilds]) + command_string = (commands + '); G=$$?; ' + # Remove the final output if any postbuild failed. + '((exit $$G) || rm -rf %s) ' % output + '&& exit $$G)') + if is_command_start: + return '(' + command_string + ' && ' + else: + return '$ && (' + command_string + + def ComputeExportEnvString(self, env): + """Given an environment, returns a string looking like + 'export FOO=foo; export BAR="${FOO} bar;' + that exports |env| to the shell.""" + export_str = [] + for k, v in env: + export_str.append('export %s=%s;' % + (k, ninja_syntax.escape(gyp.common.EncodePOSIXShellArgument(v)))) + return ' '.join(export_str) + + def ComputeMacBundleOutput(self): + """Return the 'output' (full output path) to a bundle output directory.""" + assert self.is_mac_bundle + path = generator_default_variables['PRODUCT_DIR'] + return self.ExpandSpecial( + os.path.join(path, self.xcode_settings.GetWrapperName())) + + def ComputeOutputFileName(self, spec, type=None): + """Compute the filename of the final output for the current target.""" + if not type: + type = spec['type'] + + default_variables = copy.copy(generator_default_variables) + CalculateVariables(default_variables, {'flavor': self.flavor}) + + # Compute filename prefix: the product prefix, or a default for + # the product type. + DEFAULT_PREFIX = { + 'loadable_module': default_variables['SHARED_LIB_PREFIX'], + 'shared_library': default_variables['SHARED_LIB_PREFIX'], + 'static_library': default_variables['STATIC_LIB_PREFIX'], + 'executable': default_variables['EXECUTABLE_PREFIX'], + } + prefix = spec.get('product_prefix', DEFAULT_PREFIX.get(type, '')) + + # Compute filename extension: the product extension, or a default + # for the product type. + DEFAULT_EXTENSION = { + 'loadable_module': default_variables['SHARED_LIB_SUFFIX'], + 'shared_library': default_variables['SHARED_LIB_SUFFIX'], + 'static_library': default_variables['STATIC_LIB_SUFFIX'], + 'executable': default_variables['EXECUTABLE_SUFFIX'], + } + extension = spec.get('product_extension') + if extension: + extension = '.' + extension + else: + extension = DEFAULT_EXTENSION.get(type, '') + + if 'product_name' in spec: + # If we were given an explicit name, use that. + target = spec['product_name'] + else: + # Otherwise, derive a name from the target name. + target = spec['target_name'] + if prefix == 'lib': + # Snip out an extra 'lib' from libs if appropriate. + target = StripPrefix(target, 'lib') + + if type in ('static_library', 'loadable_module', 'shared_library', + 'executable'): + return '%s%s%s' % (prefix, target, extension) + elif type == 'none': + return '%s.stamp' % target + else: + raise Exception('Unhandled output type %s' % type) + + def ComputeOutput(self, spec, arch=None): + """Compute the path for the final output of the spec.""" + type = spec['type'] + + if self.flavor == 'win': + override = self.msvs_settings.GetOutputName(self.config_name, + self.ExpandSpecial) + if override: + return override + + if arch is None and self.flavor == 'mac' and type in ( + 'static_library', 'executable', 'shared_library', 'loadable_module'): + filename = self.xcode_settings.GetExecutablePath() + else: + filename = self.ComputeOutputFileName(spec, type) + + if arch is None and 'product_dir' in spec: + path = os.path.join(spec['product_dir'], filename) + return self.ExpandSpecial(path) + + # Some products go into the output root, libraries go into shared library + # dir, and everything else goes into the normal place. + type_in_output_root = ['executable', 'loadable_module'] + if self.flavor == 'mac' and self.toolset == 'target': + type_in_output_root += ['shared_library', 'static_library'] + elif self.flavor == 'win' and self.toolset == 'target': + type_in_output_root += ['shared_library'] + + if arch is not None: + # Make sure partial executables don't end up in a bundle or the regular + # output directory. + archdir = 'arch' + if self.toolset != 'target': + archdir = os.path.join('arch', '%s' % self.toolset) + return os.path.join(archdir, AddArch(filename, arch)) + elif type in type_in_output_root or self.is_standalone_static_library: + return filename + elif type == 'shared_library': + libdir = 'lib' + if self.toolset != 'target': + libdir = os.path.join('lib', '%s' % self.toolset) + return os.path.join(libdir, filename) + else: + return self.GypPathToUniqueOutput(filename, qualified=False) + + def WriteVariableList(self, ninja_file, var, values): + assert not isinstance(values, str) + if values is None: + values = [] + ninja_file.variable(var, ' '.join(values)) + + def WriteNewNinjaRule(self, name, args, description, is_cygwin, env): + """Write out a new ninja "rule" statement for a given command. + + Returns the name of the new rule, and a copy of |args| with variables + expanded.""" + + if self.flavor == 'win': + args = [self.msvs_settings.ConvertVSMacros( + arg, self.base_to_build, config=self.config_name) + for arg in args] + description = self.msvs_settings.ConvertVSMacros( + description, config=self.config_name) + elif self.flavor == 'mac': + # |env| is an empty list on non-mac. + args = [gyp.xcode_emulation.ExpandEnvVars(arg, env) for arg in args] + description = gyp.xcode_emulation.ExpandEnvVars(description, env) + + # TODO: we shouldn't need to qualify names; we do it because + # currently the ninja rule namespace is global, but it really + # should be scoped to the subninja. + rule_name = self.name + if self.toolset == 'target': + rule_name += '.' + self.toolset + rule_name += '.' + name + rule_name = re.sub('[^a-zA-Z0-9_]', '_', rule_name) + + # Remove variable references, but not if they refer to the magic rule + # variables. This is not quite right, as it also protects these for + # actions, not just for rules where they are valid. Good enough. + protect = [ '${root}', '${dirname}', '${source}', '${ext}', '${name}' ] + protect = '(?!' + '|'.join(map(re.escape, protect)) + ')' + description = re.sub(protect + r'\$', '_', description) + + # gyp dictates that commands are run from the base directory. + # cd into the directory before running, and adjust paths in + # the arguments to point to the proper locations. + rspfile = None + rspfile_content = None + args = [self.ExpandSpecial(arg, self.base_to_build) for arg in args] + if self.flavor == 'win': + rspfile = rule_name + '.$unique_name.rsp' + # The cygwin case handles this inside the bash sub-shell. + run_in = '' if is_cygwin else ' ' + self.build_to_base + if is_cygwin: + rspfile_content = self.msvs_settings.BuildCygwinBashCommandLine( + args, self.build_to_base) + else: + rspfile_content = gyp.msvs_emulation.EncodeRspFileList(args) + command = ('%s gyp-win-tool action-wrapper $arch ' % sys.executable + + rspfile + run_in) + else: + env = self.ComputeExportEnvString(env) + command = gyp.common.EncodePOSIXShellList(args) + command = 'cd %s; ' % self.build_to_base + env + command + + # GYP rules/actions express being no-ops by not touching their outputs. + # Avoid executing downstream dependencies in this case by specifying + # restat=1 to ninja. + self.ninja.rule(rule_name, command, description, restat=True, + rspfile=rspfile, rspfile_content=rspfile_content) + self.ninja.newline() + + return rule_name, args + + +def CalculateVariables(default_variables, params): + """Calculate additional variables for use in the build (called by gyp).""" + global generator_additional_non_configuration_keys + global generator_additional_path_sections + flavor = gyp.common.GetFlavor(params) + if flavor == 'mac': + default_variables.setdefault('OS', 'mac') + default_variables.setdefault('SHARED_LIB_SUFFIX', '.dylib') + default_variables.setdefault('SHARED_LIB_DIR', + generator_default_variables['PRODUCT_DIR']) + default_variables.setdefault('LIB_DIR', + generator_default_variables['PRODUCT_DIR']) + + # Copy additional generator configuration data from Xcode, which is shared + # by the Mac Ninja generator. + import gyp.generator.xcode as xcode_generator + generator_additional_non_configuration_keys = getattr(xcode_generator, + 'generator_additional_non_configuration_keys', []) + generator_additional_path_sections = getattr(xcode_generator, + 'generator_additional_path_sections', []) + global generator_extra_sources_for_rules + generator_extra_sources_for_rules = getattr(xcode_generator, + 'generator_extra_sources_for_rules', []) + elif flavor == 'win': + default_variables.setdefault('OS', 'win') + default_variables['EXECUTABLE_SUFFIX'] = '.exe' + default_variables['STATIC_LIB_PREFIX'] = '' + default_variables['STATIC_LIB_SUFFIX'] = '.lib' + default_variables['SHARED_LIB_PREFIX'] = '' + default_variables['SHARED_LIB_SUFFIX'] = '.dll' + + # Copy additional generator configuration data from VS, which is shared + # by the Windows Ninja generator. + import gyp.generator.msvs as msvs_generator + generator_additional_non_configuration_keys = getattr(msvs_generator, + 'generator_additional_non_configuration_keys', []) + generator_additional_path_sections = getattr(msvs_generator, + 'generator_additional_path_sections', []) + + gyp.msvs_emulation.CalculateCommonVariables(default_variables, params) + else: + operating_system = flavor + if flavor == 'android': + operating_system = 'linux' # Keep this legacy behavior for now. + default_variables.setdefault('OS', operating_system) + default_variables.setdefault('SHARED_LIB_SUFFIX', '.so') + default_variables.setdefault('SHARED_LIB_DIR', + os.path.join('$!PRODUCT_DIR', 'lib')) + default_variables.setdefault('LIB_DIR', + os.path.join('$!PRODUCT_DIR', 'obj')) + +def ComputeOutputDir(params): + """Returns the path from the toplevel_dir to the build output directory.""" + # generator_dir: relative path from pwd to where make puts build files. + # Makes migrating from make to ninja easier, ninja doesn't put anything here. + generator_dir = os.path.relpath(params['options'].generator_output or '.') + + # output_dir: relative path from generator_dir to the build directory. + output_dir = params.get('generator_flags', {}).get('output_dir', 'out') + + # Relative path from source root to our output files. e.g. "out" + return os.path.normpath(os.path.join(generator_dir, output_dir)) + + +def CalculateGeneratorInputInfo(params): + """Called by __init__ to initialize generator values based on params.""" + # E.g. "out/gypfiles" + toplevel = params['options'].toplevel_dir + qualified_out_dir = os.path.normpath(os.path.join( + toplevel, ComputeOutputDir(params), 'gypfiles')) + + global generator_filelist_paths + generator_filelist_paths = { + 'toplevel': toplevel, + 'qualified_out_dir': qualified_out_dir, + } + + +def OpenOutput(path, mode='w'): + """Open |path| for writing, creating directories if necessary.""" + gyp.common.EnsureDirExists(path) + return open(path, mode) + + +def CommandWithWrapper(cmd, wrappers, prog): + wrapper = wrappers.get(cmd, '') + if wrapper: + return wrapper + ' ' + prog + return prog + + +def GetDefaultConcurrentLinks(): + """Returns a best-guess for a number of concurrent links.""" + if sys.platform in ('win32', 'cygwin'): + import ctypes + + class MEMORYSTATUSEX(ctypes.Structure): + _fields_ = [ + ("dwLength", ctypes.c_ulong), + ("dwMemoryLoad", ctypes.c_ulong), + ("ullTotalPhys", ctypes.c_ulonglong), + ("ullAvailPhys", ctypes.c_ulonglong), + ("ullTotalPageFile", ctypes.c_ulonglong), + ("ullAvailPageFile", ctypes.c_ulonglong), + ("ullTotalVirtual", ctypes.c_ulonglong), + ("ullAvailVirtual", ctypes.c_ulonglong), + ("sullAvailExtendedVirtual", ctypes.c_ulonglong), + ] + + stat = MEMORYSTATUSEX() + stat.dwLength = ctypes.sizeof(stat) + ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat)) + + mem_limit = max(1, stat.ullTotalPhys / (4 * (2 ** 30))) # total / 4GB + hard_cap = max(1, int(os.getenv('GYP_LINK_CONCURRENCY_MAX', 2**32))) + return min(mem_limit, hard_cap) + elif sys.platform.startswith('linux'): + if os.path.exists("/proc/meminfo"): + with open("/proc/meminfo") as meminfo: + memtotal_re = re.compile(r'^MemTotal:\s*(\d*)\s*kB') + for line in meminfo: + match = memtotal_re.match(line) + if not match: + continue + # Allow 8Gb per link on Linux because Gold is quite memory hungry + return max(1, int(match.group(1)) / (8 * (2 ** 20))) + return 1 + elif sys.platform == 'darwin': + try: + avail_bytes = int(subprocess.check_output(['sysctl', '-n', 'hw.memsize'])) + # A static library debug build of Chromium's unit_tests takes ~2.7GB, so + # 4GB per ld process allows for some more bloat. + return max(1, avail_bytes / (4 * (2 ** 30))) # total / 4GB + except: + return 1 + else: + # TODO(scottmg): Implement this for other platforms. + return 1 + + +def _GetWinLinkRuleNameSuffix(embed_manifest): + """Returns the suffix used to select an appropriate linking rule depending on + whether the manifest embedding is enabled.""" + return '_embed' if embed_manifest else '' + + +def _AddWinLinkRules(master_ninja, embed_manifest): + """Adds link rules for Windows platform to |master_ninja|.""" + def FullLinkCommand(ldcmd, out, binary_type): + resource_name = { + 'exe': '1', + 'dll': '2', + }[binary_type] + return '%(python)s gyp-win-tool link-with-manifests $arch %(embed)s ' \ + '%(out)s "%(ldcmd)s" %(resname)s $mt $rc "$intermediatemanifest" ' \ + '$manifests' % { + 'python': sys.executable, + 'out': out, + 'ldcmd': ldcmd, + 'resname': resource_name, + 'embed': embed_manifest } + rule_name_suffix = _GetWinLinkRuleNameSuffix(embed_manifest) + use_separate_mspdbsrv = ( + int(os.environ.get('GYP_USE_SEPARATE_MSPDBSRV', '0')) != 0) + dlldesc = 'LINK%s(DLL) $binary' % rule_name_suffix.upper() + dllcmd = ('%s gyp-win-tool link-wrapper $arch %s ' + '$ld /nologo $implibflag /DLL /OUT:$binary ' + '@$binary.rsp' % (sys.executable, use_separate_mspdbsrv)) + dllcmd = FullLinkCommand(dllcmd, '$binary', 'dll') + master_ninja.rule('solink' + rule_name_suffix, + description=dlldesc, command=dllcmd, + rspfile='$binary.rsp', + rspfile_content='$libs $in_newline $ldflags', + restat=True, + pool='link_pool') + master_ninja.rule('solink_module' + rule_name_suffix, + description=dlldesc, command=dllcmd, + rspfile='$binary.rsp', + rspfile_content='$libs $in_newline $ldflags', + restat=True, + pool='link_pool') + # Note that ldflags goes at the end so that it has the option of + # overriding default settings earlier in the command line. + exe_cmd = ('%s gyp-win-tool link-wrapper $arch %s ' + '$ld /nologo /OUT:$binary @$binary.rsp' % + (sys.executable, use_separate_mspdbsrv)) + exe_cmd = FullLinkCommand(exe_cmd, '$binary', 'exe') + master_ninja.rule('link' + rule_name_suffix, + description='LINK%s $binary' % rule_name_suffix.upper(), + command=exe_cmd, + rspfile='$binary.rsp', + rspfile_content='$in_newline $libs $ldflags', + pool='link_pool') + + +def GenerateOutputForConfig(target_list, target_dicts, data, params, + config_name): + options = params['options'] + flavor = gyp.common.GetFlavor(params) + generator_flags = params.get('generator_flags', {}) + + # build_dir: relative path from source root to our output files. + # e.g. "out/Debug" + build_dir = os.path.normpath( + os.path.join(ComputeOutputDir(params), config_name)) + + toplevel_build = os.path.join(options.toplevel_dir, build_dir) + + master_ninja_file = OpenOutput(os.path.join(toplevel_build, 'build.ninja')) + master_ninja = ninja_syntax.Writer(master_ninja_file, width=120) + + # Put build-time support tools in out/{config_name}. + gyp.common.CopyTool(flavor, toplevel_build) + + # Grab make settings for CC/CXX. + # The rules are + # - The priority from low to high is gcc/g++, the 'make_global_settings' in + # gyp, the environment variable. + # - If there is no 'make_global_settings' for CC.host/CXX.host or + # 'CC_host'/'CXX_host' enviroment variable, cc_host/cxx_host should be set + # to cc/cxx. + if flavor == 'win': + # Overridden by local arch choice in the use_deps case. + # Chromium's ffmpeg c99conv.py currently looks for a 'cc =' line in + # build.ninja so needs something valid here. http://crbug.com/233985 + cc = 'cl.exe' + cxx = 'cl.exe' + ld = 'link.exe' + ld_host = '$ld' + else: + cc = 'cc' + cxx = 'c++' + ld = '$cc' + ldxx = '$cxx' + ld_host = '$cc_host' + ldxx_host = '$cxx_host' + + cc_host = None + cxx_host = None + cc_host_global_setting = None + cxx_host_global_setting = None + clang_cl = None + + build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) + make_global_settings = data[build_file].get('make_global_settings', []) + build_to_root = gyp.common.InvertRelativePath(build_dir, + options.toplevel_dir) + wrappers = {} + for key, value in make_global_settings: + if key == 'CC': + cc = os.path.join(build_to_root, value) + if cc.endswith('clang-cl'): + clang_cl = cc + if key == 'CXX': + cxx = os.path.join(build_to_root, value) + if key == 'CC.host': + cc_host = os.path.join(build_to_root, value) + cc_host_global_setting = value + if key == 'CXX.host': + cxx_host = os.path.join(build_to_root, value) + cxx_host_global_setting = value + if key.endswith('_wrapper'): + wrappers[key[:-len('_wrapper')]] = os.path.join(build_to_root, value) + + # Support wrappers from environment variables too. + for key, value in os.environ.iteritems(): + if key.lower().endswith('_wrapper'): + key_prefix = key[:-len('_wrapper')] + key_prefix = re.sub(r'\.HOST$', '.host', key_prefix) + wrappers[key_prefix] = os.path.join(build_to_root, value) + + if flavor == 'win': + cl_paths = gyp.msvs_emulation.GenerateEnvironmentFiles( + toplevel_build, generator_flags, OpenOutput) + for arch, path in cl_paths.iteritems(): + if clang_cl: + # If we have selected clang-cl, use that instead. + path = clang_cl + command = CommandWithWrapper('CC', wrappers, + QuoteShellArgument(path, 'win')) + if clang_cl: + # Use clang-cl to cross-compile for x86 or x86_64. + command += (' -m32' if arch == 'x86' else ' -m64') + master_ninja.variable('cl_' + arch, command) + + cc = GetEnvironFallback(['CC_target', 'CC'], cc) + master_ninja.variable('cc', CommandWithWrapper('CC', wrappers, cc)) + cxx = GetEnvironFallback(['CXX_target', 'CXX'], cxx) + master_ninja.variable('cxx', CommandWithWrapper('CXX', wrappers, cxx)) + + if flavor == 'win': + master_ninja.variable('ld', ld) + master_ninja.variable('idl', 'midl.exe') + master_ninja.variable('ar', 'lib.exe') + master_ninja.variable('rc', 'rc.exe') + master_ninja.variable('asm', 'ml.exe') + master_ninja.variable('mt', 'mt.exe') + else: + master_ninja.variable('ld', CommandWithWrapper('LINK', wrappers, ld)) + master_ninja.variable('ldxx', CommandWithWrapper('LINK', wrappers, ldxx)) + master_ninja.variable('ar', GetEnvironFallback(['AR_target', 'AR'], 'ar')) + + if generator_supports_multiple_toolsets: + if not cc_host: + cc_host = cc + if not cxx_host: + cxx_host = cxx + + master_ninja.variable('ar_host', GetEnvironFallback(['AR_host'], 'ar')) + cc_host = GetEnvironFallback(['CC_host'], cc_host) + cxx_host = GetEnvironFallback(['CXX_host'], cxx_host) + + # The environment variable could be used in 'make_global_settings', like + # ['CC.host', '$(CC)'] or ['CXX.host', '$(CXX)'], transform them here. + if '$(CC)' in cc_host and cc_host_global_setting: + cc_host = cc_host_global_setting.replace('$(CC)', cc) + if '$(CXX)' in cxx_host and cxx_host_global_setting: + cxx_host = cxx_host_global_setting.replace('$(CXX)', cxx) + master_ninja.variable('cc_host', + CommandWithWrapper('CC.host', wrappers, cc_host)) + master_ninja.variable('cxx_host', + CommandWithWrapper('CXX.host', wrappers, cxx_host)) + if flavor == 'win': + master_ninja.variable('ld_host', ld_host) + else: + master_ninja.variable('ld_host', CommandWithWrapper( + 'LINK', wrappers, ld_host)) + master_ninja.variable('ldxx_host', CommandWithWrapper( + 'LINK', wrappers, ldxx_host)) + + master_ninja.newline() + + master_ninja.pool('link_pool', depth=GetDefaultConcurrentLinks()) + master_ninja.newline() + + deps = 'msvc' if flavor == 'win' else 'gcc' + + if flavor != 'win': + master_ninja.rule( + 'cc', + description='CC $out', + command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_c ' + '$cflags_pch_c -c $in -o $out'), + depfile='$out.d', + deps=deps) + master_ninja.rule( + 'cc_s', + description='CC $out', + command=('$cc $defines $includes $cflags $cflags_c ' + '$cflags_pch_c -c $in -o $out')) + master_ninja.rule( + 'cxx', + description='CXX $out', + command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc ' + '$cflags_pch_cc -c $in -o $out'), + depfile='$out.d', + deps=deps) + else: + # TODO(scottmg) Separate pdb names is a test to see if it works around + # http://crbug.com/142362. It seems there's a race between the creation of + # the .pdb by the precompiled header step for .cc and the compilation of + # .c files. This should be handled by mspdbsrv, but rarely errors out with + # c1xx : fatal error C1033: cannot open program database + # By making the rules target separate pdb files this might be avoided. + cc_command = ('ninja -t msvc -e $arch ' + + '-- ' + '$cc /nologo /showIncludes /FC ' + '@$out.rsp /c $in /Fo$out /Fd$pdbname_c ') + cxx_command = ('ninja -t msvc -e $arch ' + + '-- ' + '$cxx /nologo /showIncludes /FC ' + '@$out.rsp /c $in /Fo$out /Fd$pdbname_cc ') + master_ninja.rule( + 'cc', + description='CC $out', + command=cc_command, + rspfile='$out.rsp', + rspfile_content='$defines $includes $cflags $cflags_c', + deps=deps) + master_ninja.rule( + 'cxx', + description='CXX $out', + command=cxx_command, + rspfile='$out.rsp', + rspfile_content='$defines $includes $cflags $cflags_cc', + deps=deps) + master_ninja.rule( + 'idl', + description='IDL $in', + command=('%s gyp-win-tool midl-wrapper $arch $outdir ' + '$tlb $h $dlldata $iid $proxy $in ' + '$idlflags' % sys.executable)) + master_ninja.rule( + 'rc', + description='RC $in', + # Note: $in must be last otherwise rc.exe complains. + command=('%s gyp-win-tool rc-wrapper ' + '$arch $rc $defines $resource_includes $rcflags /fo$out $in' % + sys.executable)) + master_ninja.rule( + 'asm', + description='ASM $out', + command=('%s gyp-win-tool asm-wrapper ' + '$arch $asm $defines $includes $asmflags /c /Fo $out $in' % + sys.executable)) + + if flavor != 'mac' and flavor != 'win': + master_ninja.rule( + 'alink', + description='AR $out', + command='rm -f $out && $ar rcs $out $in') + master_ninja.rule( + 'alink_thin', + description='AR $out', + command='rm -f $out && $ar rcsT $out $in') + + # This allows targets that only need to depend on $lib's API to declare an + # order-only dependency on $lib.TOC and avoid relinking such downstream + # dependencies when $lib changes only in non-public ways. + # The resulting string leaves an uninterpolated %{suffix} which + # is used in the final substitution below. + mtime_preserving_solink_base = ( + 'if [ ! -e $lib -o ! -e $lib.TOC ]; then ' + '%(solink)s && %(extract_toc)s > $lib.TOC; else ' + '%(solink)s && %(extract_toc)s > $lib.tmp && ' + 'if ! cmp -s $lib.tmp $lib.TOC; then mv $lib.tmp $lib.TOC ; ' + 'fi; fi' + % { 'solink': + '$ld -shared $ldflags -o $lib -Wl,-soname=$soname %(suffix)s', + 'extract_toc': + ('{ readelf -d $lib | grep SONAME ; ' + 'nm -gD -f p $lib | cut -f1-2 -d\' \'; }')}) + + master_ninja.rule( + 'solink', + description='SOLINK $lib', + restat=True, + command=mtime_preserving_solink_base % {'suffix': '@$link_file_list'}, + rspfile='$link_file_list', + rspfile_content= + '-Wl,--whole-archive $in $solibs -Wl,--no-whole-archive $libs', + pool='link_pool') + master_ninja.rule( + 'solink_module', + description='SOLINK(module) $lib', + restat=True, + command=mtime_preserving_solink_base % {'suffix': '@$link_file_list'}, + rspfile='$link_file_list', + rspfile_content='-Wl,--start-group $in $solibs -Wl,--end-group $libs', + pool='link_pool') + master_ninja.rule( + 'link', + description='LINK $out', + command=('$ld $ldflags -o $out ' + '-Wl,--start-group $in $solibs -Wl,--end-group $libs'), + pool='link_pool') + elif flavor == 'win': + master_ninja.rule( + 'alink', + description='LIB $out', + command=('%s gyp-win-tool link-wrapper $arch False ' + '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' % + sys.executable), + rspfile='$out.rsp', + rspfile_content='$in_newline $libflags') + _AddWinLinkRules(master_ninja, embed_manifest=True) + _AddWinLinkRules(master_ninja, embed_manifest=False) + else: + master_ninja.rule( + 'objc', + description='OBJC $out', + command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_objc ' + '$cflags_pch_objc -c $in -o $out'), + depfile='$out.d', + deps=deps) + master_ninja.rule( + 'objcxx', + description='OBJCXX $out', + command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_objcc ' + '$cflags_pch_objcc -c $in -o $out'), + depfile='$out.d', + deps=deps) + master_ninja.rule( + 'alink', + description='LIBTOOL-STATIC $out, POSTBUILDS', + command='rm -f $out && ' + './gyp-mac-tool filter-libtool libtool $libtool_flags ' + '-static -o $out $in' + '$postbuilds') + master_ninja.rule( + 'lipo', + description='LIPO $out, POSTBUILDS', + command='rm -f $out && lipo -create $in -output $out$postbuilds') + + # Record the public interface of $lib in $lib.TOC. See the corresponding + # comment in the posix section above for details. + solink_base = '$ld %(type)s $ldflags -o $lib %(suffix)s' + mtime_preserving_solink_base = ( + 'if [ ! -e $lib -o ! -e $lib.TOC ] || ' + # Always force dependent targets to relink if this library + # reexports something. Handling this correctly would require + # recursive TOC dumping but this is rare in practice, so punt. + 'otool -l $lib | grep -q LC_REEXPORT_DYLIB ; then ' + '%(solink)s && %(extract_toc)s > $lib.TOC; ' + 'else ' + '%(solink)s && %(extract_toc)s > $lib.tmp && ' + 'if ! cmp -s $lib.tmp $lib.TOC; then ' + 'mv $lib.tmp $lib.TOC ; ' + 'fi; ' + 'fi' + % { 'solink': solink_base, + 'extract_toc': + '{ otool -l $lib | grep LC_ID_DYLIB -A 5; ' + 'nm -gP $lib | cut -f1-2 -d\' \' | grep -v U$$; true; }'}) + + + solink_suffix = '@$link_file_list$postbuilds' + master_ninja.rule( + 'solink', + description='SOLINK $lib, POSTBUILDS', + restat=True, + command=mtime_preserving_solink_base % {'suffix': solink_suffix, + 'type': '-shared'}, + rspfile='$link_file_list', + rspfile_content='$in $solibs $libs', + pool='link_pool') + master_ninja.rule( + 'solink_notoc', + description='SOLINK $lib, POSTBUILDS', + restat=True, + command=solink_base % {'suffix':solink_suffix, 'type': '-shared'}, + rspfile='$link_file_list', + rspfile_content='$in $solibs $libs', + pool='link_pool') + + master_ninja.rule( + 'solink_module', + description='SOLINK(module) $lib, POSTBUILDS', + restat=True, + command=mtime_preserving_solink_base % {'suffix': solink_suffix, + 'type': '-bundle'}, + rspfile='$link_file_list', + rspfile_content='$in $solibs $libs', + pool='link_pool') + master_ninja.rule( + 'solink_module_notoc', + description='SOLINK(module) $lib, POSTBUILDS', + restat=True, + command=solink_base % {'suffix': solink_suffix, 'type': '-bundle'}, + rspfile='$link_file_list', + rspfile_content='$in $solibs $libs', + pool='link_pool') + + master_ninja.rule( + 'link', + description='LINK $out, POSTBUILDS', + command=('$ld $ldflags -o $out ' + '$in $solibs $libs$postbuilds'), + pool='link_pool') + master_ninja.rule( + 'preprocess_infoplist', + description='PREPROCESS INFOPLIST $out', + command=('$cc -E -P -Wno-trigraphs -x c $defines $in -o $out && ' + 'plutil -convert xml1 $out $out')) + master_ninja.rule( + 'copy_infoplist', + description='COPY INFOPLIST $in', + command='$env ./gyp-mac-tool copy-info-plist $in $out $keys') + master_ninja.rule( + 'mac_tool', + description='MACTOOL $mactool_cmd $in', + command='$env ./gyp-mac-tool $mactool_cmd $in $out') + master_ninja.rule( + 'package_framework', + description='PACKAGE FRAMEWORK $out, POSTBUILDS', + command='./gyp-mac-tool package-framework $out $version$postbuilds ' + '&& touch $out') + if flavor == 'win': + master_ninja.rule( + 'stamp', + description='STAMP $out', + command='%s gyp-win-tool stamp $out' % sys.executable) + master_ninja.rule( + 'copy', + description='COPY $in $out', + command='%s gyp-win-tool recursive-mirror $in $out' % sys.executable) + else: + master_ninja.rule( + 'stamp', + description='STAMP $out', + command='${postbuilds}touch $out') + master_ninja.rule( + 'copy', + description='COPY $in $out', + command='ln -f $in $out 2>/dev/null || (rm -rf $out && cp -af $in $out)') + master_ninja.newline() + + all_targets = set() + for build_file in params['build_files']: + for target in gyp.common.AllTargets(target_list, + target_dicts, + os.path.normpath(build_file)): + all_targets.add(target) + all_outputs = set() + + # target_outputs is a map from qualified target name to a Target object. + target_outputs = {} + # target_short_names is a map from target short name to a list of Target + # objects. + target_short_names = {} + + for qualified_target in target_list: + # qualified_target is like: third_party/icu/icu.gyp:icui18n#target + build_file, name, toolset = \ + gyp.common.ParseQualifiedTarget(qualified_target) + + this_make_global_settings = data[build_file].get('make_global_settings', []) + assert make_global_settings == this_make_global_settings, ( + "make_global_settings needs to be the same for all targets. %s vs. %s" % + (this_make_global_settings, make_global_settings)) + + spec = target_dicts[qualified_target] + if flavor == 'mac': + gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec) + + build_file = gyp.common.RelativePath(build_file, options.toplevel_dir) + + base_path = os.path.dirname(build_file) + obj = 'obj' + if toolset != 'target': + obj += '.' + toolset + output_file = os.path.join(obj, base_path, name + '.ninja') + + ninja_output = StringIO() + writer = NinjaWriter(qualified_target, target_outputs, base_path, build_dir, + ninja_output, + toplevel_build, output_file, + flavor, toplevel_dir=options.toplevel_dir) + + target = writer.WriteSpec(spec, config_name, generator_flags) + + if ninja_output.tell() > 0: + # Only create files for ninja files that actually have contents. + with OpenOutput(os.path.join(toplevel_build, output_file)) as ninja_file: + ninja_file.write(ninja_output.getvalue()) + ninja_output.close() + master_ninja.subninja(output_file) + + if target: + if name != target.FinalOutput() and spec['toolset'] == 'target': + target_short_names.setdefault(name, []).append(target) + target_outputs[qualified_target] = target + if qualified_target in all_targets: + all_outputs.add(target.FinalOutput()) + + if target_short_names: + # Write a short name to build this target. This benefits both the + # "build chrome" case as well as the gyp tests, which expect to be + # able to run actions and build libraries by their short name. + master_ninja.newline() + master_ninja.comment('Short names for targets.') + for short_name in target_short_names: + master_ninja.build(short_name, 'phony', [x.FinalOutput() for x in + target_short_names[short_name]]) + + if all_outputs: + master_ninja.newline() + master_ninja.build('all', 'phony', list(all_outputs)) + master_ninja.default(generator_flags.get('default_target', 'all')) + + master_ninja_file.close() + + +def PerformBuild(data, configurations, params): + options = params['options'] + for config in configurations: + builddir = os.path.join(options.toplevel_dir, 'out', config) + arguments = ['ninja', '-C', builddir] + print 'Building [%s]: %s' % (config, arguments) + subprocess.check_call(arguments) + + +def CallGenerateOutputForConfig(arglist): + # Ignore the interrupt signal so that the parent process catches it and + # kills all multiprocessing children. + signal.signal(signal.SIGINT, signal.SIG_IGN) + + (target_list, target_dicts, data, params, config_name) = arglist + GenerateOutputForConfig(target_list, target_dicts, data, params, config_name) + + +def GenerateOutput(target_list, target_dicts, data, params): + # Update target_dicts for iOS device builds. + target_dicts = gyp.xcode_emulation.CloneConfigurationForDeviceAndEmulator( + target_dicts) + + user_config = params.get('generator_flags', {}).get('config', None) + if gyp.common.GetFlavor(params) == 'win': + target_list, target_dicts = MSVSUtil.ShardTargets(target_list, target_dicts) + target_list, target_dicts = MSVSUtil.InsertLargePdbShims( + target_list, target_dicts, generator_default_variables) + + if user_config: + GenerateOutputForConfig(target_list, target_dicts, data, params, + user_config) + else: + config_names = target_dicts[target_list[0]]['configurations'].keys() + if params['parallel']: + try: + pool = multiprocessing.Pool(len(config_names)) + arglists = [] + for config_name in config_names: + arglists.append( + (target_list, target_dicts, data, params, config_name)) + pool.map(CallGenerateOutputForConfig, arglists) + except KeyboardInterrupt, e: + pool.terminate() + raise e + else: + for config_name in config_names: + GenerateOutputForConfig(target_list, target_dicts, data, params, + config_name) diff --git a/deps/gyp/pylib/gyp/generator/ninja_test.py b/deps/gyp/pylib/gyp/generator/ninja_test.py new file mode 100644 index 000000000..52661bcdf --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/ninja_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" Unit tests for the ninja.py file. """ + +import gyp.generator.ninja as ninja +import unittest +import StringIO +import sys +import TestCommon + + +class TestPrefixesAndSuffixes(unittest.TestCase): + def test_BinaryNamesWindows(self): + writer = ninja.NinjaWriter('foo', 'wee', '.', '.', 'build.ninja', '.', + 'build.ninja', 'win') + spec = { 'target_name': 'wee' } + self.assertTrue(writer.ComputeOutputFileName(spec, 'executable'). + endswith('.exe')) + self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library'). + endswith('.dll')) + self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library'). + endswith('.lib')) + + def test_BinaryNamesLinux(self): + writer = ninja.NinjaWriter('foo', 'wee', '.', '.', 'build.ninja', '.', + 'build.ninja', 'linux') + spec = { 'target_name': 'wee' } + self.assertTrue('.' not in writer.ComputeOutputFileName(spec, + 'executable')) + self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library'). + startswith('lib')) + self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library'). + startswith('lib')) + self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library'). + endswith('.so')) + self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library'). + endswith('.a')) + +if __name__ == '__main__': + unittest.main() diff --git a/deps/gyp/pylib/gyp/generator/xcode.py b/deps/gyp/pylib/gyp/generator/xcode.py new file mode 100644 index 000000000..783dafa0b --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/xcode.py @@ -0,0 +1,1246 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import filecmp +import gyp.common +import gyp.xcodeproj_file +import gyp.xcode_ninja +import errno +import os +import sys +import posixpath +import re +import shutil +import subprocess +import tempfile + + +# Project files generated by this module will use _intermediate_var as a +# custom Xcode setting whose value is a DerivedSources-like directory that's +# project-specific and configuration-specific. The normal choice, +# DERIVED_FILE_DIR, is target-specific, which is thought to be too restrictive +# as it is likely that multiple targets within a single project file will want +# to access the same set of generated files. The other option, +# PROJECT_DERIVED_FILE_DIR, is unsuitable because while it is project-specific, +# it is not configuration-specific. INTERMEDIATE_DIR is defined as +# $(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION). +_intermediate_var = 'INTERMEDIATE_DIR' + +# SHARED_INTERMEDIATE_DIR is the same, except that it is shared among all +# targets that share the same BUILT_PRODUCTS_DIR. +_shared_intermediate_var = 'SHARED_INTERMEDIATE_DIR' + +# ONLY_ACTIVE_ARCH means that only the active architecture should be build for +# Debugging purposes to shorten the build time +_only_active_arch = 'ONLY_ACTIVE_ARCH' + +_library_search_paths_var = 'LIBRARY_SEARCH_PATHS' + +generator_default_variables = { + 'EXECUTABLE_PREFIX': '', + 'EXECUTABLE_SUFFIX': '', + 'STATIC_LIB_PREFIX': 'lib', + 'SHARED_LIB_PREFIX': 'lib', + 'STATIC_LIB_SUFFIX': '.a', + 'SHARED_LIB_SUFFIX': '.dylib', + # INTERMEDIATE_DIR is a place for targets to build up intermediate products. + # It is specific to each build environment. It is only guaranteed to exist + # and be constant within the context of a project, corresponding to a single + # input file. Some build environments may allow their intermediate directory + # to be shared on a wider scale, but this is not guaranteed. + 'INTERMEDIATE_DIR': '$(%s)' % _intermediate_var, + 'OS': 'mac', + 'PRODUCT_DIR': '$(BUILT_PRODUCTS_DIR)', + 'LIB_DIR': '$(BUILT_PRODUCTS_DIR)', + 'RULE_INPUT_ROOT': '$(INPUT_FILE_BASE)', + 'RULE_INPUT_EXT': '$(INPUT_FILE_SUFFIX)', + 'RULE_INPUT_NAME': '$(INPUT_FILE_NAME)', + 'RULE_INPUT_PATH': '$(INPUT_FILE_PATH)', + 'RULE_INPUT_DIRNAME': '$(INPUT_FILE_DIRNAME)', + 'SHARED_INTERMEDIATE_DIR': '$(%s)' % _shared_intermediate_var, + 'CONFIGURATION_NAME': '$(CONFIGURATION)', +} + +# The Xcode-specific sections that hold paths. +generator_additional_path_sections = [ + 'mac_bundle_resources', + 'mac_framework_headers', + 'mac_framework_private_headers', + # 'mac_framework_dirs', input already handles _dirs endings. +] + +# The Xcode-specific keys that exist on targets and aren't moved down to +# configurations. +generator_additional_non_configuration_keys = [ + 'mac_bundle', + 'mac_bundle_resources', + 'mac_framework_headers', + 'mac_framework_private_headers', + 'mac_xctest_bundle', + 'xcode_create_dependents_test_runner', +] + +# We want to let any rules apply to files that are resources also. +generator_extra_sources_for_rules = [ + 'mac_bundle_resources', + 'mac_framework_headers', + 'mac_framework_private_headers', +] + +# Xcode's standard set of library directories, which don't need to be duplicated +# in LIBRARY_SEARCH_PATHS. This list is not exhaustive, but that's okay. +xcode_standard_library_dirs = frozenset([ + '$(SDKROOT)/usr/lib', + '$(SDKROOT)/usr/local/lib', +]) + +def CreateXCConfigurationList(configuration_names): + xccl = gyp.xcodeproj_file.XCConfigurationList({'buildConfigurations': []}) + if len(configuration_names) == 0: + configuration_names = ['Default'] + for configuration_name in configuration_names: + xcbc = gyp.xcodeproj_file.XCBuildConfiguration({ + 'name': configuration_name}) + xccl.AppendProperty('buildConfigurations', xcbc) + xccl.SetProperty('defaultConfigurationName', configuration_names[0]) + return xccl + + +class XcodeProject(object): + def __init__(self, gyp_path, path, build_file_dict): + self.gyp_path = gyp_path + self.path = path + self.project = gyp.xcodeproj_file.PBXProject(path=path) + projectDirPath = gyp.common.RelativePath( + os.path.dirname(os.path.abspath(self.gyp_path)), + os.path.dirname(path) or '.') + self.project.SetProperty('projectDirPath', projectDirPath) + self.project_file = \ + gyp.xcodeproj_file.XCProjectFile({'rootObject': self.project}) + self.build_file_dict = build_file_dict + + # TODO(mark): add destructor that cleans up self.path if created_dir is + # True and things didn't complete successfully. Or do something even + # better with "try"? + self.created_dir = False + try: + os.makedirs(self.path) + self.created_dir = True + except OSError, e: + if e.errno != errno.EEXIST: + raise + + def Finalize1(self, xcode_targets, serialize_all_tests): + # Collect a list of all of the build configuration names used by the + # various targets in the file. It is very heavily advised to keep each + # target in an entire project (even across multiple project files) using + # the same set of configuration names. + configurations = [] + for xct in self.project.GetProperty('targets'): + xccl = xct.GetProperty('buildConfigurationList') + xcbcs = xccl.GetProperty('buildConfigurations') + for xcbc in xcbcs: + name = xcbc.GetProperty('name') + if name not in configurations: + configurations.append(name) + + # Replace the XCConfigurationList attached to the PBXProject object with + # a new one specifying all of the configuration names used by the various + # targets. + try: + xccl = CreateXCConfigurationList(configurations) + self.project.SetProperty('buildConfigurationList', xccl) + except: + sys.stderr.write("Problem with gyp file %s\n" % self.gyp_path) + raise + + # The need for this setting is explained above where _intermediate_var is + # defined. The comments below about wanting to avoid project-wide build + # settings apply here too, but this needs to be set on a project-wide basis + # so that files relative to the _intermediate_var setting can be displayed + # properly in the Xcode UI. + # + # Note that for configuration-relative files such as anything relative to + # _intermediate_var, for the purposes of UI tree view display, Xcode will + # only resolve the configuration name once, when the project file is + # opened. If the active build configuration is changed, the project file + # must be closed and reopened if it is desired for the tree view to update. + # This is filed as Apple radar 6588391. + xccl.SetBuildSetting(_intermediate_var, + '$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)') + xccl.SetBuildSetting(_shared_intermediate_var, + '$(SYMROOT)/DerivedSources/$(CONFIGURATION)') + + xccl.ConfigurationNamed('Debug').SetBuildSetting(_only_active_arch, 'YES') + + # Set user-specified project-wide build settings and config files. This + # is intended to be used very sparingly. Really, almost everything should + # go into target-specific build settings sections. The project-wide + # settings are only intended to be used in cases where Xcode attempts to + # resolve variable references in a project context as opposed to a target + # context, such as when resolving sourceTree references while building up + # the tree tree view for UI display. + # Any values set globally are applied to all configurations, then any + # per-configuration values are applied. + for xck, xcv in self.build_file_dict.get('xcode_settings', {}).iteritems(): + xccl.SetBuildSetting(xck, xcv) + if 'xcode_config_file' in self.build_file_dict: + config_ref = self.project.AddOrGetFileInRootGroup( + self.build_file_dict['xcode_config_file']) + xccl.SetBaseConfiguration(config_ref) + build_file_configurations = self.build_file_dict.get('configurations', {}) + if build_file_configurations: + for config_name in configurations: + build_file_configuration_named = \ + build_file_configurations.get(config_name, {}) + if build_file_configuration_named: + xcc = xccl.ConfigurationNamed(config_name) + for xck, xcv in build_file_configuration_named.get('xcode_settings', + {}).iteritems(): + xcc.SetBuildSetting(xck, xcv) + if 'xcode_config_file' in build_file_configuration_named: + config_ref = self.project.AddOrGetFileInRootGroup( + build_file_configurations[config_name]['xcode_config_file']) + xcc.SetBaseConfiguration(config_ref) + + # Sort the targets based on how they appeared in the input. + # TODO(mark): Like a lot of other things here, this assumes internal + # knowledge of PBXProject - in this case, of its "targets" property. + + # ordinary_targets are ordinary targets that are already in the project + # file. run_test_targets are the targets that run unittests and should be + # used for the Run All Tests target. support_targets are the action/rule + # targets used by GYP file targets, just kept for the assert check. + ordinary_targets = [] + run_test_targets = [] + support_targets = [] + + # targets is full list of targets in the project. + targets = [] + + # does the it define it's own "all"? + has_custom_all = False + + # targets_for_all is the list of ordinary_targets that should be listed + # in this project's "All" target. It includes each non_runtest_target + # that does not have suppress_wildcard set. + targets_for_all = [] + + for target in self.build_file_dict['targets']: + target_name = target['target_name'] + toolset = target['toolset'] + qualified_target = gyp.common.QualifiedTarget(self.gyp_path, target_name, + toolset) + xcode_target = xcode_targets[qualified_target] + # Make sure that the target being added to the sorted list is already in + # the unsorted list. + assert xcode_target in self.project._properties['targets'] + targets.append(xcode_target) + ordinary_targets.append(xcode_target) + if xcode_target.support_target: + support_targets.append(xcode_target.support_target) + targets.append(xcode_target.support_target) + + if not int(target.get('suppress_wildcard', False)): + targets_for_all.append(xcode_target) + + if target_name.lower() == 'all': + has_custom_all = True; + + # If this target has a 'run_as' attribute, add its target to the + # targets, and add it to the test targets. + if target.get('run_as'): + # Make a target to run something. It should have one + # dependency, the parent xcode target. + xccl = CreateXCConfigurationList(configurations) + run_target = gyp.xcodeproj_file.PBXAggregateTarget({ + 'name': 'Run ' + target_name, + 'productName': xcode_target.GetProperty('productName'), + 'buildConfigurationList': xccl, + }, + parent=self.project) + run_target.AddDependency(xcode_target) + + command = target['run_as'] + script = '' + if command.get('working_directory'): + script = script + 'cd "%s"\n' % \ + gyp.xcodeproj_file.ConvertVariablesToShellSyntax( + command.get('working_directory')) + + if command.get('environment'): + script = script + "\n".join( + ['export %s="%s"' % + (key, gyp.xcodeproj_file.ConvertVariablesToShellSyntax(val)) + for (key, val) in command.get('environment').iteritems()]) + "\n" + + # Some test end up using sockets, files on disk, etc. and can get + # confused if more then one test runs at a time. The generator + # flag 'xcode_serialize_all_test_runs' controls the forcing of all + # tests serially. It defaults to True. To get serial runs this + # little bit of python does the same as the linux flock utility to + # make sure only one runs at a time. + command_prefix = '' + if serialize_all_tests: + command_prefix = \ +"""python -c "import fcntl, subprocess, sys +file = open('$TMPDIR/GYP_serialize_test_runs', 'a') +fcntl.flock(file.fileno(), fcntl.LOCK_EX) +sys.exit(subprocess.call(sys.argv[1:]))" """ + + # If we were unable to exec for some reason, we want to exit + # with an error, and fixup variable references to be shell + # syntax instead of xcode syntax. + script = script + 'exec ' + command_prefix + '%s\nexit 1\n' % \ + gyp.xcodeproj_file.ConvertVariablesToShellSyntax( + gyp.common.EncodePOSIXShellList(command.get('action'))) + + ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({ + 'shellScript': script, + 'showEnvVarsInLog': 0, + }) + run_target.AppendProperty('buildPhases', ssbp) + + # Add the run target to the project file. + targets.append(run_target) + run_test_targets.append(run_target) + xcode_target.test_runner = run_target + + + # Make sure that the list of targets being replaced is the same length as + # the one replacing it, but allow for the added test runner targets. + assert len(self.project._properties['targets']) == \ + len(ordinary_targets) + len(support_targets) + + self.project._properties['targets'] = targets + + # Get rid of unnecessary levels of depth in groups like the Source group. + self.project.RootGroupsTakeOverOnlyChildren(True) + + # Sort the groups nicely. Do this after sorting the targets, because the + # Products group is sorted based on the order of the targets. + self.project.SortGroups() + + # Create an "All" target if there's more than one target in this project + # file and the project didn't define its own "All" target. Put a generated + # "All" target first so that people opening up the project for the first + # time will build everything by default. + if len(targets_for_all) > 1 and not has_custom_all: + xccl = CreateXCConfigurationList(configurations) + all_target = gyp.xcodeproj_file.PBXAggregateTarget( + { + 'buildConfigurationList': xccl, + 'name': 'All', + }, + parent=self.project) + + for target in targets_for_all: + all_target.AddDependency(target) + + # TODO(mark): This is evil because it relies on internal knowledge of + # PBXProject._properties. It's important to get the "All" target first, + # though. + self.project._properties['targets'].insert(0, all_target) + + # The same, but for run_test_targets. + if len(run_test_targets) > 1: + xccl = CreateXCConfigurationList(configurations) + run_all_tests_target = gyp.xcodeproj_file.PBXAggregateTarget( + { + 'buildConfigurationList': xccl, + 'name': 'Run All Tests', + }, + parent=self.project) + for run_test_target in run_test_targets: + run_all_tests_target.AddDependency(run_test_target) + + # Insert after the "All" target, which must exist if there is more than + # one run_test_target. + self.project._properties['targets'].insert(1, run_all_tests_target) + + def Finalize2(self, xcode_targets, xcode_target_to_target_dict): + # Finalize2 needs to happen in a separate step because the process of + # updating references to other projects depends on the ordering of targets + # within remote project files. Finalize1 is responsible for sorting duty, + # and once all project files are sorted, Finalize2 can come in and update + # these references. + + # To support making a "test runner" target that will run all the tests + # that are direct dependents of any given target, we look for + # xcode_create_dependents_test_runner being set on an Aggregate target, + # and generate a second target that will run the tests runners found under + # the marked target. + for bf_tgt in self.build_file_dict['targets']: + if int(bf_tgt.get('xcode_create_dependents_test_runner', 0)): + tgt_name = bf_tgt['target_name'] + toolset = bf_tgt['toolset'] + qualified_target = gyp.common.QualifiedTarget(self.gyp_path, + tgt_name, toolset) + xcode_target = xcode_targets[qualified_target] + if isinstance(xcode_target, gyp.xcodeproj_file.PBXAggregateTarget): + # Collect all the run test targets. + all_run_tests = [] + pbxtds = xcode_target.GetProperty('dependencies') + for pbxtd in pbxtds: + pbxcip = pbxtd.GetProperty('targetProxy') + dependency_xct = pbxcip.GetProperty('remoteGlobalIDString') + if hasattr(dependency_xct, 'test_runner'): + all_run_tests.append(dependency_xct.test_runner) + + # Directly depend on all the runners as they depend on the target + # that builds them. + if len(all_run_tests) > 0: + run_all_target = gyp.xcodeproj_file.PBXAggregateTarget({ + 'name': 'Run %s Tests' % tgt_name, + 'productName': tgt_name, + }, + parent=self.project) + for run_test_target in all_run_tests: + run_all_target.AddDependency(run_test_target) + + # Insert the test runner after the related target. + idx = self.project._properties['targets'].index(xcode_target) + self.project._properties['targets'].insert(idx + 1, run_all_target) + + # Update all references to other projects, to make sure that the lists of + # remote products are complete. Otherwise, Xcode will fill them in when + # it opens the project file, which will result in unnecessary diffs. + # TODO(mark): This is evil because it relies on internal knowledge of + # PBXProject._other_pbxprojects. + for other_pbxproject in self.project._other_pbxprojects.keys(): + self.project.AddOrGetProjectReference(other_pbxproject) + + self.project.SortRemoteProductReferences() + + # Give everything an ID. + self.project_file.ComputeIDs() + + # Make sure that no two objects in the project file have the same ID. If + # multiple objects wind up with the same ID, upon loading the file, Xcode + # will only recognize one object (the last one in the file?) and the + # results are unpredictable. + self.project_file.EnsureNoIDCollisions() + + def Write(self): + # Write the project file to a temporary location first. Xcode watches for + # changes to the project file and presents a UI sheet offering to reload + # the project when it does change. However, in some cases, especially when + # multiple projects are open or when Xcode is busy, things don't work so + # seamlessly. Sometimes, Xcode is able to detect that a project file has + # changed but can't unload it because something else is referencing it. + # To mitigate this problem, and to avoid even having Xcode present the UI + # sheet when an open project is rewritten for inconsequential changes, the + # project file is written to a temporary file in the xcodeproj directory + # first. The new temporary file is then compared to the existing project + # file, if any. If they differ, the new file replaces the old; otherwise, + # the new project file is simply deleted. Xcode properly detects a file + # being renamed over an open project file as a change and so it remains + # able to present the "project file changed" sheet under this system. + # Writing to a temporary file first also avoids the possible problem of + # Xcode rereading an incomplete project file. + (output_fd, new_pbxproj_path) = \ + tempfile.mkstemp(suffix='.tmp', prefix='project.pbxproj.gyp.', + dir=self.path) + + try: + output_file = os.fdopen(output_fd, 'wb') + + self.project_file.Print(output_file) + output_file.close() + + pbxproj_path = os.path.join(self.path, 'project.pbxproj') + + same = False + try: + same = filecmp.cmp(pbxproj_path, new_pbxproj_path, False) + except OSError, e: + if e.errno != errno.ENOENT: + raise + + if same: + # The new file is identical to the old one, just get rid of the new + # one. + os.unlink(new_pbxproj_path) + else: + # The new file is different from the old one, or there is no old one. + # Rename the new file to the permanent name. + # + # tempfile.mkstemp uses an overly restrictive mode, resulting in a + # file that can only be read by the owner, regardless of the umask. + # There's no reason to not respect the umask here, which means that + # an extra hoop is required to fetch it and reset the new file's mode. + # + # No way to get the umask without setting a new one? Set a safe one + # and then set it back to the old value. + umask = os.umask(077) + os.umask(umask) + + os.chmod(new_pbxproj_path, 0666 & ~umask) + os.rename(new_pbxproj_path, pbxproj_path) + + except Exception: + # Don't leave turds behind. In fact, if this code was responsible for + # creating the xcodeproj directory, get rid of that too. + os.unlink(new_pbxproj_path) + if self.created_dir: + shutil.rmtree(self.path, True) + raise + + +def AddSourceToTarget(source, type, pbxp, xct): + # TODO(mark): Perhaps source_extensions and library_extensions can be made a + # little bit fancier. + source_extensions = ['c', 'cc', 'cpp', 'cxx', 'm', 'mm', 's'] + + # .o is conceptually more of a "source" than a "library," but Xcode thinks + # of "sources" as things to compile and "libraries" (or "frameworks") as + # things to link with. Adding an object file to an Xcode target's frameworks + # phase works properly. + library_extensions = ['a', 'dylib', 'framework', 'o'] + + basename = posixpath.basename(source) + (root, ext) = posixpath.splitext(basename) + if ext: + ext = ext[1:].lower() + + if ext in source_extensions and type != 'none': + xct.SourcesPhase().AddFile(source) + elif ext in library_extensions and type != 'none': + xct.FrameworksPhase().AddFile(source) + else: + # Files that aren't added to a sources or frameworks build phase can still + # go into the project file, just not as part of a build phase. + pbxp.AddOrGetFileInRootGroup(source) + + +def AddResourceToTarget(resource, pbxp, xct): + # TODO(mark): Combine with AddSourceToTarget above? Or just inline this call + # where it's used. + xct.ResourcesPhase().AddFile(resource) + + +def AddHeaderToTarget(header, pbxp, xct, is_public): + # TODO(mark): Combine with AddSourceToTarget above? Or just inline this call + # where it's used. + settings = '{ATTRIBUTES = (%s, ); }' % ('Private', 'Public')[is_public] + xct.HeadersPhase().AddFile(header, settings) + + +_xcode_variable_re = re.compile('(\$\((.*?)\))') +def ExpandXcodeVariables(string, expansions): + """Expands Xcode-style $(VARIABLES) in string per the expansions dict. + + In some rare cases, it is appropriate to expand Xcode variables when a + project file is generated. For any substring $(VAR) in string, if VAR is a + key in the expansions dict, $(VAR) will be replaced with expansions[VAR]. + Any $(VAR) substring in string for which VAR is not a key in the expansions + dict will remain in the returned string. + """ + + matches = _xcode_variable_re.findall(string) + if matches == None: + return string + + matches.reverse() + for match in matches: + (to_replace, variable) = match + if not variable in expansions: + continue + + replacement = expansions[variable] + string = re.sub(re.escape(to_replace), replacement, string) + + return string + + +_xcode_define_re = re.compile(r'([\\\"\' ])') +def EscapeXcodeDefine(s): + """We must escape the defines that we give to XCode so that it knows not to + split on spaces and to respect backslash and quote literals. However, we + must not quote the define, or Xcode will incorrectly intepret variables + especially $(inherited).""" + return re.sub(_xcode_define_re, r'\\\1', s) + + +def PerformBuild(data, configurations, params): + options = params['options'] + + for build_file, build_file_dict in data.iteritems(): + (build_file_root, build_file_ext) = os.path.splitext(build_file) + if build_file_ext != '.gyp': + continue + xcodeproj_path = build_file_root + options.suffix + '.xcodeproj' + if options.generator_output: + xcodeproj_path = os.path.join(options.generator_output, xcodeproj_path) + + for config in configurations: + arguments = ['xcodebuild', '-project', xcodeproj_path] + arguments += ['-configuration', config] + print "Building [%s]: %s" % (config, arguments) + subprocess.check_call(arguments) + + +def GenerateOutput(target_list, target_dicts, data, params): + # Optionally configure each spec to use ninja as the external builder. + ninja_wrapper = params.get('flavor') == 'ninja' + if ninja_wrapper: + (target_list, target_dicts, data) = \ + gyp.xcode_ninja.CreateWrapper(target_list, target_dicts, data, params) + + options = params['options'] + generator_flags = params.get('generator_flags', {}) + parallel_builds = generator_flags.get('xcode_parallel_builds', True) + serialize_all_tests = \ + generator_flags.get('xcode_serialize_all_test_runs', True) + project_version = generator_flags.get('xcode_project_version', None) + skip_excluded_files = \ + not generator_flags.get('xcode_list_excluded_files', True) + xcode_projects = {} + for build_file, build_file_dict in data.iteritems(): + (build_file_root, build_file_ext) = os.path.splitext(build_file) + if build_file_ext != '.gyp': + continue + xcodeproj_path = build_file_root + options.suffix + '.xcodeproj' + if options.generator_output: + xcodeproj_path = os.path.join(options.generator_output, xcodeproj_path) + xcp = XcodeProject(build_file, xcodeproj_path, build_file_dict) + xcode_projects[build_file] = xcp + pbxp = xcp.project + + if parallel_builds: + pbxp.SetProperty('attributes', + { + 'BuildIndependentTargetsInParallel': 'YES', + 'LastUpgradeCheck': '0500' + } + ) + if project_version: + xcp.project_file.SetXcodeVersion(project_version) + + # Add gyp/gypi files to project + if not generator_flags.get('standalone'): + main_group = pbxp.GetProperty('mainGroup') + build_group = gyp.xcodeproj_file.PBXGroup({'name': 'Build'}) + main_group.AppendChild(build_group) + for included_file in build_file_dict['included_files']: + build_group.AddOrGetFileByPath(included_file, False) + + xcode_targets = {} + xcode_target_to_target_dict = {} + for qualified_target in target_list: + [build_file, target_name, toolset] = \ + gyp.common.ParseQualifiedTarget(qualified_target) + + spec = target_dicts[qualified_target] + if spec['toolset'] != 'target': + raise Exception( + 'Multiple toolsets not supported in xcode build (target %s)' % + qualified_target) + configuration_names = [spec['default_configuration']] + for configuration_name in sorted(spec['configurations'].keys()): + if configuration_name not in configuration_names: + configuration_names.append(configuration_name) + xcp = xcode_projects[build_file] + pbxp = xcp.project + + # Set up the configurations for the target according to the list of names + # supplied. + xccl = CreateXCConfigurationList(configuration_names) + + # Create an XCTarget subclass object for the target. The type with + # "+bundle" appended will be used if the target has "mac_bundle" set. + # loadable_modules not in a mac_bundle are mapped to + # com.googlecode.gyp.xcode.bundle, a pseudo-type that xcode.py interprets + # to create a single-file mh_bundle. + _types = { + 'executable': 'com.apple.product-type.tool', + 'loadable_module': 'com.googlecode.gyp.xcode.bundle', + 'shared_library': 'com.apple.product-type.library.dynamic', + 'static_library': 'com.apple.product-type.library.static', + 'executable+bundle': 'com.apple.product-type.application', + 'loadable_module+bundle': 'com.apple.product-type.bundle', + 'loadable_module+xctest': 'com.apple.product-type.bundle.unit-test', + 'shared_library+bundle': 'com.apple.product-type.framework', + } + + target_properties = { + 'buildConfigurationList': xccl, + 'name': target_name, + } + + type = spec['type'] + is_xctest = int(spec.get('mac_xctest_bundle', 0)) + is_bundle = int(spec.get('mac_bundle', 0)) or is_xctest + if type != 'none': + type_bundle_key = type + if is_xctest: + type_bundle_key += '+xctest' + assert type == 'loadable_module', ( + 'mac_xctest_bundle targets must have type loadable_module ' + '(target %s)' % target_name) + elif is_bundle: + type_bundle_key += '+bundle' + + xctarget_type = gyp.xcodeproj_file.PBXNativeTarget + try: + target_properties['productType'] = _types[type_bundle_key] + except KeyError, e: + gyp.common.ExceptionAppend(e, "-- unknown product type while " + "writing target %s" % target_name) + raise + else: + xctarget_type = gyp.xcodeproj_file.PBXAggregateTarget + assert not is_bundle, ( + 'mac_bundle targets cannot have type none (target "%s")' % + target_name) + assert not is_xctest, ( + 'mac_xctest_bundle targets cannot have type none (target "%s")' % + target_name) + + target_product_name = spec.get('product_name') + if target_product_name is not None: + target_properties['productName'] = target_product_name + + xct = xctarget_type(target_properties, parent=pbxp, + force_outdir=spec.get('product_dir'), + force_prefix=spec.get('product_prefix'), + force_extension=spec.get('product_extension')) + pbxp.AppendProperty('targets', xct) + xcode_targets[qualified_target] = xct + xcode_target_to_target_dict[xct] = spec + + spec_actions = spec.get('actions', []) + spec_rules = spec.get('rules', []) + + # Xcode has some "issues" with checking dependencies for the "Compile + # sources" step with any source files/headers generated by actions/rules. + # To work around this, if a target is building anything directly (not + # type "none"), then a second target is used to run the GYP actions/rules + # and is made a dependency of this target. This way the work is done + # before the dependency checks for what should be recompiled. + support_xct = None + # The Xcode "issues" don't affect xcode-ninja builds, since the dependency + # logic all happens in ninja. Don't bother creating the extra targets in + # that case. + if type != 'none' and (spec_actions or spec_rules) and not ninja_wrapper: + support_xccl = CreateXCConfigurationList(configuration_names); + support_target_suffix = generator_flags.get( + 'support_target_suffix', ' Support') + support_target_properties = { + 'buildConfigurationList': support_xccl, + 'name': target_name + support_target_suffix, + } + if target_product_name: + support_target_properties['productName'] = \ + target_product_name + ' Support' + support_xct = \ + gyp.xcodeproj_file.PBXAggregateTarget(support_target_properties, + parent=pbxp) + pbxp.AppendProperty('targets', support_xct) + xct.AddDependency(support_xct) + # Hang the support target off the main target so it can be tested/found + # by the generator during Finalize. + xct.support_target = support_xct + + prebuild_index = 0 + + # Add custom shell script phases for "actions" sections. + for action in spec_actions: + # There's no need to write anything into the script to ensure that the + # output directories already exist, because Xcode will look at the + # declared outputs and automatically ensure that they exist for us. + + # Do we have a message to print when this action runs? + message = action.get('message') + if message: + message = 'echo note: ' + gyp.common.EncodePOSIXShellArgument(message) + else: + message = '' + + # Turn the list into a string that can be passed to a shell. + action_string = gyp.common.EncodePOSIXShellList(action['action']) + + # Convert Xcode-type variable references to sh-compatible environment + # variable references. + message_sh = gyp.xcodeproj_file.ConvertVariablesToShellSyntax(message) + action_string_sh = gyp.xcodeproj_file.ConvertVariablesToShellSyntax( + action_string) + + script = '' + # Include the optional message + if message_sh: + script += message_sh + '\n' + # Be sure the script runs in exec, and that if exec fails, the script + # exits signalling an error. + script += 'exec ' + action_string_sh + '\nexit 1\n' + ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({ + 'inputPaths': action['inputs'], + 'name': 'Action "' + action['action_name'] + '"', + 'outputPaths': action['outputs'], + 'shellScript': script, + 'showEnvVarsInLog': 0, + }) + + if support_xct: + support_xct.AppendProperty('buildPhases', ssbp) + else: + # TODO(mark): this assumes too much knowledge of the internals of + # xcodeproj_file; some of these smarts should move into xcodeproj_file + # itself. + xct._properties['buildPhases'].insert(prebuild_index, ssbp) + prebuild_index = prebuild_index + 1 + + # TODO(mark): Should verify that at most one of these is specified. + if int(action.get('process_outputs_as_sources', False)): + for output in action['outputs']: + AddSourceToTarget(output, type, pbxp, xct) + + if int(action.get('process_outputs_as_mac_bundle_resources', False)): + for output in action['outputs']: + AddResourceToTarget(output, pbxp, xct) + + # tgt_mac_bundle_resources holds the list of bundle resources so + # the rule processing can check against it. + if is_bundle: + tgt_mac_bundle_resources = spec.get('mac_bundle_resources', []) + else: + tgt_mac_bundle_resources = [] + + # Add custom shell script phases driving "make" for "rules" sections. + # + # Xcode's built-in rule support is almost powerful enough to use directly, + # but there are a few significant deficiencies that render them unusable. + # There are workarounds for some of its inadequacies, but in aggregate, + # the workarounds added complexity to the generator, and some workarounds + # actually require input files to be crafted more carefully than I'd like. + # Consequently, until Xcode rules are made more capable, "rules" input + # sections will be handled in Xcode output by shell script build phases + # performed prior to the compilation phase. + # + # The following problems with Xcode rules were found. The numbers are + # Apple radar IDs. I hope that these shortcomings are addressed, I really + # liked having the rules handled directly in Xcode during the period that + # I was prototyping this. + # + # 6588600 Xcode compiles custom script rule outputs too soon, compilation + # fails. This occurs when rule outputs from distinct inputs are + # interdependent. The only workaround is to put rules and their + # inputs in a separate target from the one that compiles the rule + # outputs. This requires input file cooperation and it means that + # process_outputs_as_sources is unusable. + # 6584932 Need to declare that custom rule outputs should be excluded from + # compilation. A possible workaround is to lie to Xcode about a + # rule's output, giving it a dummy file it doesn't know how to + # compile. The rule action script would need to touch the dummy. + # 6584839 I need a way to declare additional inputs to a custom rule. + # A possible workaround is a shell script phase prior to + # compilation that touches a rule's primary input files if any + # would-be additional inputs are newer than the output. Modifying + # the source tree - even just modification times - feels dirty. + # 6564240 Xcode "custom script" build rules always dump all environment + # variables. This is a low-prioroty problem and is not a + # show-stopper. + rules_by_ext = {} + for rule in spec_rules: + rules_by_ext[rule['extension']] = rule + + # First, some definitions: + # + # A "rule source" is a file that was listed in a target's "sources" + # list and will have a rule applied to it on the basis of matching the + # rule's "extensions" attribute. Rule sources are direct inputs to + # rules. + # + # Rule definitions may specify additional inputs in their "inputs" + # attribute. These additional inputs are used for dependency tracking + # purposes. + # + # A "concrete output" is a rule output with input-dependent variables + # resolved. For example, given a rule with: + # 'extension': 'ext', 'outputs': ['$(INPUT_FILE_BASE).cc'], + # if the target's "sources" list contained "one.ext" and "two.ext", + # the "concrete output" for rule input "two.ext" would be "two.cc". If + # a rule specifies multiple outputs, each input file that the rule is + # applied to will have the same number of concrete outputs. + # + # If any concrete outputs are outdated or missing relative to their + # corresponding rule_source or to any specified additional input, the + # rule action must be performed to generate the concrete outputs. + + # concrete_outputs_by_rule_source will have an item at the same index + # as the rule['rule_sources'] that it corresponds to. Each item is a + # list of all of the concrete outputs for the rule_source. + concrete_outputs_by_rule_source = [] + + # concrete_outputs_all is a flat list of all concrete outputs that this + # rule is able to produce, given the known set of input files + # (rule_sources) that apply to it. + concrete_outputs_all = [] + + # messages & actions are keyed by the same indices as rule['rule_sources'] + # and concrete_outputs_by_rule_source. They contain the message and + # action to perform after resolving input-dependent variables. The + # message is optional, in which case None is stored for each rule source. + messages = [] + actions = [] + + for rule_source in rule.get('rule_sources', []): + rule_source_dirname, rule_source_basename = \ + posixpath.split(rule_source) + (rule_source_root, rule_source_ext) = \ + posixpath.splitext(rule_source_basename) + + # These are the same variable names that Xcode uses for its own native + # rule support. Because Xcode's rule engine is not being used, they + # need to be expanded as they are written to the makefile. + rule_input_dict = { + 'INPUT_FILE_BASE': rule_source_root, + 'INPUT_FILE_SUFFIX': rule_source_ext, + 'INPUT_FILE_NAME': rule_source_basename, + 'INPUT_FILE_PATH': rule_source, + 'INPUT_FILE_DIRNAME': rule_source_dirname, + } + + concrete_outputs_for_this_rule_source = [] + for output in rule.get('outputs', []): + # Fortunately, Xcode and make both use $(VAR) format for their + # variables, so the expansion is the only transformation necessary. + # Any remaning $(VAR)-type variables in the string can be given + # directly to make, which will pick up the correct settings from + # what Xcode puts into the environment. + concrete_output = ExpandXcodeVariables(output, rule_input_dict) + concrete_outputs_for_this_rule_source.append(concrete_output) + + # Add all concrete outputs to the project. + pbxp.AddOrGetFileInRootGroup(concrete_output) + + concrete_outputs_by_rule_source.append( \ + concrete_outputs_for_this_rule_source) + concrete_outputs_all.extend(concrete_outputs_for_this_rule_source) + + # TODO(mark): Should verify that at most one of these is specified. + if int(rule.get('process_outputs_as_sources', False)): + for output in concrete_outputs_for_this_rule_source: + AddSourceToTarget(output, type, pbxp, xct) + + # If the file came from the mac_bundle_resources list or if the rule + # is marked to process outputs as bundle resource, do so. + was_mac_bundle_resource = rule_source in tgt_mac_bundle_resources + if was_mac_bundle_resource or \ + int(rule.get('process_outputs_as_mac_bundle_resources', False)): + for output in concrete_outputs_for_this_rule_source: + AddResourceToTarget(output, pbxp, xct) + + # Do we have a message to print when this rule runs? + message = rule.get('message') + if message: + message = gyp.common.EncodePOSIXShellArgument(message) + message = ExpandXcodeVariables(message, rule_input_dict) + messages.append(message) + + # Turn the list into a string that can be passed to a shell. + action_string = gyp.common.EncodePOSIXShellList(rule['action']) + + action = ExpandXcodeVariables(action_string, rule_input_dict) + actions.append(action) + + if len(concrete_outputs_all) > 0: + # TODO(mark): There's a possibilty for collision here. Consider + # target "t" rule "A_r" and target "t_A" rule "r". + makefile_name = '%s.make' % re.sub( + '[^a-zA-Z0-9_]', '_' , '%s_%s' % (target_name, rule['rule_name'])) + makefile_path = os.path.join(xcode_projects[build_file].path, + makefile_name) + # TODO(mark): try/close? Write to a temporary file and swap it only + # if it's got changes? + makefile = open(makefile_path, 'wb') + + # make will build the first target in the makefile by default. By + # convention, it's called "all". List all (or at least one) + # concrete output for each rule source as a prerequisite of the "all" + # target. + makefile.write('all: \\\n') + for concrete_output_index in \ + xrange(0, len(concrete_outputs_by_rule_source)): + # Only list the first (index [0]) concrete output of each input + # in the "all" target. Otherwise, a parallel make (-j > 1) would + # attempt to process each input multiple times simultaneously. + # Otherwise, "all" could just contain the entire list of + # concrete_outputs_all. + concrete_output = \ + concrete_outputs_by_rule_source[concrete_output_index][0] + if concrete_output_index == len(concrete_outputs_by_rule_source) - 1: + eol = '' + else: + eol = ' \\' + makefile.write(' %s%s\n' % (concrete_output, eol)) + + for (rule_source, concrete_outputs, message, action) in \ + zip(rule['rule_sources'], concrete_outputs_by_rule_source, + messages, actions): + makefile.write('\n') + + # Add a rule that declares it can build each concrete output of a + # rule source. Collect the names of the directories that are + # required. + concrete_output_dirs = [] + for concrete_output_index in xrange(0, len(concrete_outputs)): + concrete_output = concrete_outputs[concrete_output_index] + if concrete_output_index == 0: + bol = '' + else: + bol = ' ' + makefile.write('%s%s \\\n' % (bol, concrete_output)) + + concrete_output_dir = posixpath.dirname(concrete_output) + if (concrete_output_dir and + concrete_output_dir not in concrete_output_dirs): + concrete_output_dirs.append(concrete_output_dir) + + makefile.write(' : \\\n') + + # The prerequisites for this rule are the rule source itself and + # the set of additional rule inputs, if any. + prerequisites = [rule_source] + prerequisites.extend(rule.get('inputs', [])) + for prerequisite_index in xrange(0, len(prerequisites)): + prerequisite = prerequisites[prerequisite_index] + if prerequisite_index == len(prerequisites) - 1: + eol = '' + else: + eol = ' \\' + makefile.write(' %s%s\n' % (prerequisite, eol)) + + # Make sure that output directories exist before executing the rule + # action. + if len(concrete_output_dirs) > 0: + makefile.write('\t@mkdir -p "%s"\n' % + '" "'.join(concrete_output_dirs)) + + # The rule message and action have already had the necessary variable + # substitutions performed. + if message: + # Mark it with note: so Xcode picks it up in build output. + makefile.write('\t@echo note: %s\n' % message) + makefile.write('\t%s\n' % action) + + makefile.close() + + # It might be nice to ensure that needed output directories exist + # here rather than in each target in the Makefile, but that wouldn't + # work if there ever was a concrete output that had an input-dependent + # variable anywhere other than in the leaf position. + + # Don't declare any inputPaths or outputPaths. If they're present, + # Xcode will provide a slight optimization by only running the script + # phase if any output is missing or outdated relative to any input. + # Unfortunately, it will also assume that all outputs are touched by + # the script, and if the outputs serve as files in a compilation + # phase, they will be unconditionally rebuilt. Since make might not + # rebuild everything that could be declared here as an output, this + # extra compilation activity is unnecessary. With inputPaths and + # outputPaths not supplied, make will always be called, but it knows + # enough to not do anything when everything is up-to-date. + + # To help speed things up, pass -j COUNT to make so it does some work + # in parallel. Don't use ncpus because Xcode will build ncpus targets + # in parallel and if each target happens to have a rules step, there + # would be ncpus^2 things going. With a machine that has 2 quad-core + # Xeons, a build can quickly run out of processes based on + # scheduling/other tasks, and randomly failing builds are no good. + script = \ +"""JOB_COUNT="$(/usr/sbin/sysctl -n hw.ncpu)" +if [ "${JOB_COUNT}" -gt 4 ]; then + JOB_COUNT=4 +fi +exec xcrun make -f "${PROJECT_FILE_PATH}/%s" -j "${JOB_COUNT}" +exit 1 +""" % makefile_name + ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({ + 'name': 'Rule "' + rule['rule_name'] + '"', + 'shellScript': script, + 'showEnvVarsInLog': 0, + }) + + if support_xct: + support_xct.AppendProperty('buildPhases', ssbp) + else: + # TODO(mark): this assumes too much knowledge of the internals of + # xcodeproj_file; some of these smarts should move into xcodeproj_file + # itself. + xct._properties['buildPhases'].insert(prebuild_index, ssbp) + prebuild_index = prebuild_index + 1 + + # Extra rule inputs also go into the project file. Concrete outputs were + # already added when they were computed. + groups = ['inputs', 'inputs_excluded'] + if skip_excluded_files: + groups = [x for x in groups if not x.endswith('_excluded')] + for group in groups: + for item in rule.get(group, []): + pbxp.AddOrGetFileInRootGroup(item) + + # Add "sources". + for source in spec.get('sources', []): + (source_root, source_extension) = posixpath.splitext(source) + if source_extension[1:] not in rules_by_ext: + # AddSourceToTarget will add the file to a root group if it's not + # already there. + AddSourceToTarget(source, type, pbxp, xct) + else: + pbxp.AddOrGetFileInRootGroup(source) + + # Add "mac_bundle_resources" and "mac_framework_private_headers" if + # it's a bundle of any type. + if is_bundle: + for resource in tgt_mac_bundle_resources: + (resource_root, resource_extension) = posixpath.splitext(resource) + if resource_extension[1:] not in rules_by_ext: + AddResourceToTarget(resource, pbxp, xct) + else: + pbxp.AddOrGetFileInRootGroup(resource) + + for header in spec.get('mac_framework_private_headers', []): + AddHeaderToTarget(header, pbxp, xct, False) + + # Add "mac_framework_headers". These can be valid for both frameworks + # and static libraries. + if is_bundle or type == 'static_library': + for header in spec.get('mac_framework_headers', []): + AddHeaderToTarget(header, pbxp, xct, True) + + # Add "copies". + pbxcp_dict = {} + for copy_group in spec.get('copies', []): + dest = copy_group['destination'] + if dest[0] not in ('/', '$'): + # Relative paths are relative to $(SRCROOT). + dest = '$(SRCROOT)/' + dest + + # Coalesce multiple "copies" sections in the same target with the same + # "destination" property into the same PBXCopyFilesBuildPhase, otherwise + # they'll wind up with ID collisions. + pbxcp = pbxcp_dict.get(dest, None) + if pbxcp is None: + pbxcp = gyp.xcodeproj_file.PBXCopyFilesBuildPhase({ + 'name': 'Copy to ' + copy_group['destination'] + }, + parent=xct) + pbxcp.SetDestination(dest) + + # TODO(mark): The usual comment about this knowing too much about + # gyp.xcodeproj_file internals applies. + xct._properties['buildPhases'].insert(prebuild_index, pbxcp) + + pbxcp_dict[dest] = pbxcp + + for file in copy_group['files']: + pbxcp.AddFile(file) + + # Excluded files can also go into the project file. + if not skip_excluded_files: + for key in ['sources', 'mac_bundle_resources', 'mac_framework_headers', + 'mac_framework_private_headers']: + excluded_key = key + '_excluded' + for item in spec.get(excluded_key, []): + pbxp.AddOrGetFileInRootGroup(item) + + # So can "inputs" and "outputs" sections of "actions" groups. + groups = ['inputs', 'inputs_excluded', 'outputs', 'outputs_excluded'] + if skip_excluded_files: + groups = [x for x in groups if not x.endswith('_excluded')] + for action in spec.get('actions', []): + for group in groups: + for item in action.get(group, []): + # Exclude anything in BUILT_PRODUCTS_DIR. They're products, not + # sources. + if not item.startswith('$(BUILT_PRODUCTS_DIR)/'): + pbxp.AddOrGetFileInRootGroup(item) + + for postbuild in spec.get('postbuilds', []): + action_string_sh = gyp.common.EncodePOSIXShellList(postbuild['action']) + script = 'exec ' + action_string_sh + '\nexit 1\n' + + # Make the postbuild step depend on the output of ld or ar from this + # target. Apparently putting the script step after the link step isn't + # sufficient to ensure proper ordering in all cases. With an input + # declared but no outputs, the script step should run every time, as + # desired. + ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({ + 'inputPaths': ['$(BUILT_PRODUCTS_DIR)/$(EXECUTABLE_PATH)'], + 'name': 'Postbuild "' + postbuild['postbuild_name'] + '"', + 'shellScript': script, + 'showEnvVarsInLog': 0, + }) + xct.AppendProperty('buildPhases', ssbp) + + # Add dependencies before libraries, because adding a dependency may imply + # adding a library. It's preferable to keep dependencies listed first + # during a link phase so that they can override symbols that would + # otherwise be provided by libraries, which will usually include system + # libraries. On some systems, ld is finicky and even requires the + # libraries to be ordered in such a way that unresolved symbols in + # earlier-listed libraries may only be resolved by later-listed libraries. + # The Mac linker doesn't work that way, but other platforms do, and so + # their linker invocations need to be constructed in this way. There's + # no compelling reason for Xcode's linker invocations to differ. + + if 'dependencies' in spec: + for dependency in spec['dependencies']: + xct.AddDependency(xcode_targets[dependency]) + # The support project also gets the dependencies (in case they are + # needed for the actions/rules to work). + if support_xct: + support_xct.AddDependency(xcode_targets[dependency]) + + if 'libraries' in spec: + for library in spec['libraries']: + xct.FrameworksPhase().AddFile(library) + # Add the library's directory to LIBRARY_SEARCH_PATHS if necessary. + # I wish Xcode handled this automatically. + library_dir = posixpath.dirname(library) + if library_dir not in xcode_standard_library_dirs and ( + not xct.HasBuildSetting(_library_search_paths_var) or + library_dir not in xct.GetBuildSetting(_library_search_paths_var)): + xct.AppendBuildSetting(_library_search_paths_var, library_dir) + + for configuration_name in configuration_names: + configuration = spec['configurations'][configuration_name] + xcbc = xct.ConfigurationNamed(configuration_name) + for include_dir in configuration.get('mac_framework_dirs', []): + xcbc.AppendBuildSetting('FRAMEWORK_SEARCH_PATHS', include_dir) + for include_dir in configuration.get('include_dirs', []): + xcbc.AppendBuildSetting('HEADER_SEARCH_PATHS', include_dir) + for library_dir in configuration.get('library_dirs', []): + if library_dir not in xcode_standard_library_dirs and ( + not xcbc.HasBuildSetting(_library_search_paths_var) or + library_dir not in xcbc.GetBuildSetting(_library_search_paths_var)): + xcbc.AppendBuildSetting(_library_search_paths_var, library_dir) + + if 'defines' in configuration: + for define in configuration['defines']: + set_define = EscapeXcodeDefine(define) + xcbc.AppendBuildSetting('GCC_PREPROCESSOR_DEFINITIONS', set_define) + if 'xcode_settings' in configuration: + for xck, xcv in configuration['xcode_settings'].iteritems(): + xcbc.SetBuildSetting(xck, xcv) + if 'xcode_config_file' in configuration: + config_ref = pbxp.AddOrGetFileInRootGroup( + configuration['xcode_config_file']) + xcbc.SetBaseConfiguration(config_ref) + + build_files = [] + for build_file, build_file_dict in data.iteritems(): + if build_file.endswith('.gyp'): + build_files.append(build_file) + + for build_file in build_files: + xcode_projects[build_file].Finalize1(xcode_targets, serialize_all_tests) + + for build_file in build_files: + xcode_projects[build_file].Finalize2(xcode_targets, + xcode_target_to_target_dict) + + for build_file in build_files: + xcode_projects[build_file].Write() diff --git a/deps/gyp/pylib/gyp/generator/xcode_test.py b/deps/gyp/pylib/gyp/generator/xcode_test.py new file mode 100644 index 000000000..260324a43 --- /dev/null +++ b/deps/gyp/pylib/gyp/generator/xcode_test.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +# Copyright (c) 2013 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" Unit tests for the xcode.py file. """ + +import gyp.generator.xcode as xcode +import unittest +import sys + + +class TestEscapeXcodeDefine(unittest.TestCase): + if sys.platform == 'darwin': + def test_InheritedRemainsUnescaped(self): + self.assertEqual(xcode.EscapeXcodeDefine('$(inherited)'), '$(inherited)') + + def test_Escaping(self): + self.assertEqual(xcode.EscapeXcodeDefine('a b"c\\'), 'a\\ b\\"c\\\\') + +if __name__ == '__main__': + unittest.main() diff --git a/deps/gyp/pylib/gyp/input.py b/deps/gyp/pylib/gyp/input.py new file mode 100644 index 000000000..dc143d9df --- /dev/null +++ b/deps/gyp/pylib/gyp/input.py @@ -0,0 +1,2860 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from compiler.ast import Const +from compiler.ast import Dict +from compiler.ast import Discard +from compiler.ast import List +from compiler.ast import Module +from compiler.ast import Node +from compiler.ast import Stmt +import compiler +import gyp.common +import gyp.simple_copy +import multiprocessing +import optparse +import os.path +import re +import shlex +import signal +import subprocess +import sys +import threading +import time +import traceback +from gyp.common import GypError +from gyp.common import OrderedSet + + +# A list of types that are treated as linkable. +linkable_types = ['executable', 'shared_library', 'loadable_module'] + +# A list of sections that contain links to other targets. +dependency_sections = ['dependencies', 'export_dependent_settings'] + +# base_path_sections is a list of sections defined by GYP that contain +# pathnames. The generators can provide more keys, the two lists are merged +# into path_sections, but you should call IsPathSection instead of using either +# list directly. +base_path_sections = [ + 'destination', + 'files', + 'include_dirs', + 'inputs', + 'libraries', + 'outputs', + 'sources', +] +path_sections = set() + +def IsPathSection(section): + # If section ends in one of the '=+?!' characters, it's applied to a section + # without the trailing characters. '/' is notably absent from this list, + # because there's no way for a regular expression to be treated as a path. + while section[-1:] in '=+?!': + section = section[:-1] + + if section in path_sections: + return True + + # Sections mathing the regexp '_(dir|file|path)s?$' are also + # considered PathSections. Using manual string matching since that + # is much faster than the regexp and this can be called hundreds of + # thousands of times so micro performance matters. + if "_" in section: + tail = section[-6:] + if tail[-1] == 's': + tail = tail[:-1] + if tail[-5:] in ('_file', '_path'): + return True + return tail[-4:] == '_dir' + + return False + +# base_non_configuration_keys is a list of key names that belong in the target +# itself and should not be propagated into its configurations. It is merged +# with a list that can come from the generator to +# create non_configuration_keys. +base_non_configuration_keys = [ + # Sections that must exist inside targets and not configurations. + 'actions', + 'configurations', + 'copies', + 'default_configuration', + 'dependencies', + 'dependencies_original', + 'libraries', + 'postbuilds', + 'product_dir', + 'product_extension', + 'product_name', + 'product_prefix', + 'rules', + 'run_as', + 'sources', + 'standalone_static_library', + 'suppress_wildcard', + 'target_name', + 'toolset', + 'toolsets', + 'type', + + # Sections that can be found inside targets or configurations, but that + # should not be propagated from targets into their configurations. + 'variables', +] +non_configuration_keys = [] + +# Keys that do not belong inside a configuration dictionary. +invalid_configuration_keys = [ + 'actions', + 'all_dependent_settings', + 'configurations', + 'dependencies', + 'direct_dependent_settings', + 'libraries', + 'link_settings', + 'sources', + 'standalone_static_library', + 'target_name', + 'type', +] + +# Controls whether or not the generator supports multiple toolsets. +multiple_toolsets = False + +# Paths for converting filelist paths to output paths: { +# toplevel, +# qualified_output_dir, +# } +generator_filelist_paths = None + +def GetIncludedBuildFiles(build_file_path, aux_data, included=None): + """Return a list of all build files included into build_file_path. + + The returned list will contain build_file_path as well as all other files + that it included, either directly or indirectly. Note that the list may + contain files that were included into a conditional section that evaluated + to false and was not merged into build_file_path's dict. + + aux_data is a dict containing a key for each build file or included build + file. Those keys provide access to dicts whose "included" keys contain + lists of all other files included by the build file. + + included should be left at its default None value by external callers. It + is used for recursion. + + The returned list will not contain any duplicate entries. Each build file + in the list will be relative to the current directory. + """ + + if included == None: + included = [] + + if build_file_path in included: + return included + + included.append(build_file_path) + + for included_build_file in aux_data[build_file_path].get('included', []): + GetIncludedBuildFiles(included_build_file, aux_data, included) + + return included + + +def CheckedEval(file_contents): + """Return the eval of a gyp file. + + The gyp file is restricted to dictionaries and lists only, and + repeated keys are not allowed. + + Note that this is slower than eval() is. + """ + + ast = compiler.parse(file_contents) + assert isinstance(ast, Module) + c1 = ast.getChildren() + assert c1[0] is None + assert isinstance(c1[1], Stmt) + c2 = c1[1].getChildren() + assert isinstance(c2[0], Discard) + c3 = c2[0].getChildren() + assert len(c3) == 1 + return CheckNode(c3[0], []) + + +def CheckNode(node, keypath): + if isinstance(node, Dict): + c = node.getChildren() + dict = {} + for n in range(0, len(c), 2): + assert isinstance(c[n], Const) + key = c[n].getChildren()[0] + if key in dict: + raise GypError("Key '" + key + "' repeated at level " + + repr(len(keypath) + 1) + " with key path '" + + '.'.join(keypath) + "'") + kp = list(keypath) # Make a copy of the list for descending this node. + kp.append(key) + dict[key] = CheckNode(c[n + 1], kp) + return dict + elif isinstance(node, List): + c = node.getChildren() + children = [] + for index, child in enumerate(c): + kp = list(keypath) # Copy list. + kp.append(repr(index)) + children.append(CheckNode(child, kp)) + return children + elif isinstance(node, Const): + return node.getChildren()[0] + else: + raise TypeError, "Unknown AST node at key path '" + '.'.join(keypath) + \ + "': " + repr(node) + + +def LoadOneBuildFile(build_file_path, data, aux_data, includes, + is_target, check): + if build_file_path in data: + return data[build_file_path] + + if os.path.exists(build_file_path): + build_file_contents = open(build_file_path).read() + else: + raise GypError("%s not found (cwd: %s)" % (build_file_path, os.getcwd())) + + build_file_data = None + try: + if check: + build_file_data = CheckedEval(build_file_contents) + else: + build_file_data = eval(build_file_contents, {'__builtins__': None}, + None) + except SyntaxError, e: + e.filename = build_file_path + raise + except Exception, e: + gyp.common.ExceptionAppend(e, 'while reading ' + build_file_path) + raise + + if type(build_file_data) is not dict: + raise GypError("%s does not evaluate to a dictionary." % build_file_path) + + data[build_file_path] = build_file_data + aux_data[build_file_path] = {} + + # Scan for includes and merge them in. + if ('skip_includes' not in build_file_data or + not build_file_data['skip_includes']): + try: + if is_target: + LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data, + aux_data, includes, check) + else: + LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data, + aux_data, None, check) + except Exception, e: + gyp.common.ExceptionAppend(e, + 'while reading includes of ' + build_file_path) + raise + + return build_file_data + + +def LoadBuildFileIncludesIntoDict(subdict, subdict_path, data, aux_data, + includes, check): + includes_list = [] + if includes != None: + includes_list.extend(includes) + if 'includes' in subdict: + for include in subdict['includes']: + # "include" is specified relative to subdict_path, so compute the real + # path to include by appending the provided "include" to the directory + # in which subdict_path resides. + relative_include = \ + os.path.normpath(os.path.join(os.path.dirname(subdict_path), include)) + includes_list.append(relative_include) + # Unhook the includes list, it's no longer needed. + del subdict['includes'] + + # Merge in the included files. + for include in includes_list: + if not 'included' in aux_data[subdict_path]: + aux_data[subdict_path]['included'] = [] + aux_data[subdict_path]['included'].append(include) + + gyp.DebugOutput(gyp.DEBUG_INCLUDES, "Loading Included File: '%s'", include) + + MergeDicts(subdict, + LoadOneBuildFile(include, data, aux_data, None, False, check), + subdict_path, include) + + # Recurse into subdictionaries. + for k, v in subdict.iteritems(): + if type(v) is dict: + LoadBuildFileIncludesIntoDict(v, subdict_path, data, aux_data, + None, check) + elif type(v) is list: + LoadBuildFileIncludesIntoList(v, subdict_path, data, aux_data, + check) + + +# This recurses into lists so that it can look for dicts. +def LoadBuildFileIncludesIntoList(sublist, sublist_path, data, aux_data, check): + for item in sublist: + if type(item) is dict: + LoadBuildFileIncludesIntoDict(item, sublist_path, data, aux_data, + None, check) + elif type(item) is list: + LoadBuildFileIncludesIntoList(item, sublist_path, data, aux_data, check) + +# Processes toolsets in all the targets. This recurses into condition entries +# since they can contain toolsets as well. +def ProcessToolsetsInDict(data): + if 'targets' in data: + target_list = data['targets'] + new_target_list = [] + for target in target_list: + # If this target already has an explicit 'toolset', and no 'toolsets' + # list, don't modify it further. + if 'toolset' in target and 'toolsets' not in target: + new_target_list.append(target) + continue + if multiple_toolsets: + toolsets = target.get('toolsets', ['target']) + else: + toolsets = ['target'] + # Make sure this 'toolsets' definition is only processed once. + if 'toolsets' in target: + del target['toolsets'] + if len(toolsets) > 0: + # Optimization: only do copies if more than one toolset is specified. + for build in toolsets[1:]: + new_target = gyp.simple_copy.deepcopy(target) + new_target['toolset'] = build + new_target_list.append(new_target) + target['toolset'] = toolsets[0] + new_target_list.append(target) + data['targets'] = new_target_list + if 'conditions' in data: + for condition in data['conditions']: + if type(condition) is list: + for condition_dict in condition[1:]: + ProcessToolsetsInDict(condition_dict) + + +# TODO(mark): I don't love this name. It just means that it's going to load +# a build file that contains targets and is expected to provide a targets dict +# that contains the targets... +def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes, + depth, check, load_dependencies): + # If depth is set, predefine the DEPTH variable to be a relative path from + # this build file's directory to the directory identified by depth. + if depth: + # TODO(dglazkov) The backslash/forward-slash replacement at the end is a + # temporary measure. This should really be addressed by keeping all paths + # in POSIX until actual project generation. + d = gyp.common.RelativePath(depth, os.path.dirname(build_file_path)) + if d == '': + variables['DEPTH'] = '.' + else: + variables['DEPTH'] = d.replace('\\', '/') + + if build_file_path in data['target_build_files']: + # Already loaded. + return False + data['target_build_files'].add(build_file_path) + + gyp.DebugOutput(gyp.DEBUG_INCLUDES, + "Loading Target Build File '%s'", build_file_path) + + build_file_data = LoadOneBuildFile(build_file_path, data, aux_data, + includes, True, check) + + # Store DEPTH for later use in generators. + build_file_data['_DEPTH'] = depth + + # Set up the included_files key indicating which .gyp files contributed to + # this target dict. + if 'included_files' in build_file_data: + raise GypError(build_file_path + ' must not contain included_files key') + + included = GetIncludedBuildFiles(build_file_path, aux_data) + build_file_data['included_files'] = [] + for included_file in included: + # included_file is relative to the current directory, but it needs to + # be made relative to build_file_path's directory. + included_relative = \ + gyp.common.RelativePath(included_file, + os.path.dirname(build_file_path)) + build_file_data['included_files'].append(included_relative) + + # Do a first round of toolsets expansion so that conditions can be defined + # per toolset. + ProcessToolsetsInDict(build_file_data) + + # Apply "pre"/"early" variable expansions and condition evaluations. + ProcessVariablesAndConditionsInDict( + build_file_data, PHASE_EARLY, variables, build_file_path) + + # Since some toolsets might have been defined conditionally, perform + # a second round of toolsets expansion now. + ProcessToolsetsInDict(build_file_data) + + # Look at each project's target_defaults dict, and merge settings into + # targets. + if 'target_defaults' in build_file_data: + if 'targets' not in build_file_data: + raise GypError("Unable to find targets in build file %s" % + build_file_path) + + index = 0 + while index < len(build_file_data['targets']): + # This procedure needs to give the impression that target_defaults is + # used as defaults, and the individual targets inherit from that. + # The individual targets need to be merged into the defaults. Make + # a deep copy of the defaults for each target, merge the target dict + # as found in the input file into that copy, and then hook up the + # copy with the target-specific data merged into it as the replacement + # target dict. + old_target_dict = build_file_data['targets'][index] + new_target_dict = gyp.simple_copy.deepcopy( + build_file_data['target_defaults']) + MergeDicts(new_target_dict, old_target_dict, + build_file_path, build_file_path) + build_file_data['targets'][index] = new_target_dict + index += 1 + + # No longer needed. + del build_file_data['target_defaults'] + + # Look for dependencies. This means that dependency resolution occurs + # after "pre" conditionals and variable expansion, but before "post" - + # in other words, you can't put a "dependencies" section inside a "post" + # conditional within a target. + + dependencies = [] + if 'targets' in build_file_data: + for target_dict in build_file_data['targets']: + if 'dependencies' not in target_dict: + continue + for dependency in target_dict['dependencies']: + dependencies.append( + gyp.common.ResolveTarget(build_file_path, dependency, None)[0]) + + if load_dependencies: + for dependency in dependencies: + try: + LoadTargetBuildFile(dependency, data, aux_data, variables, + includes, depth, check, load_dependencies) + except Exception, e: + gyp.common.ExceptionAppend( + e, 'while loading dependencies of %s' % build_file_path) + raise + else: + return (build_file_path, dependencies) + + +def CallLoadTargetBuildFile(global_flags, + build_file_path, data, + aux_data, variables, + includes, depth, check, + generator_input_info): + """Wrapper around LoadTargetBuildFile for parallel processing. + + This wrapper is used when LoadTargetBuildFile is executed in + a worker process. + """ + + try: + signal.signal(signal.SIGINT, signal.SIG_IGN) + + # Apply globals so that the worker process behaves the same. + for key, value in global_flags.iteritems(): + globals()[key] = value + + # Save the keys so we can return data that changed. + data_keys = set(data) + aux_data_keys = set(aux_data) + + SetGeneratorGlobals(generator_input_info) + result = LoadTargetBuildFile(build_file_path, data, + aux_data, variables, + includes, depth, check, False) + if not result: + return result + + (build_file_path, dependencies) = result + + data_out = {} + for key in data: + if key == 'target_build_files': + continue + if key not in data_keys: + data_out[key] = data[key] + aux_data_out = {} + for key in aux_data: + if key not in aux_data_keys: + aux_data_out[key] = aux_data[key] + + # This gets serialized and sent back to the main process via a pipe. + # It's handled in LoadTargetBuildFileCallback. + return (build_file_path, + data_out, + aux_data_out, + dependencies) + except GypError, e: + sys.stderr.write("gyp: %s\n" % e) + return None + except Exception, e: + print >>sys.stderr, 'Exception:', e + print >>sys.stderr, traceback.format_exc() + return None + + +class ParallelProcessingError(Exception): + pass + + +class ParallelState(object): + """Class to keep track of state when processing input files in parallel. + + If build files are loaded in parallel, use this to keep track of + state during farming out and processing parallel jobs. It's stored + in a global so that the callback function can have access to it. + """ + + def __init__(self): + # The multiprocessing pool. + self.pool = None + # The condition variable used to protect this object and notify + # the main loop when there might be more data to process. + self.condition = None + # The "data" dict that was passed to LoadTargetBuildFileParallel + self.data = None + # The "aux_data" dict that was passed to LoadTargetBuildFileParallel + self.aux_data = None + # The number of parallel calls outstanding; decremented when a response + # was received. + self.pending = 0 + # The set of all build files that have been scheduled, so we don't + # schedule the same one twice. + self.scheduled = set() + # A list of dependency build file paths that haven't been scheduled yet. + self.dependencies = [] + # Flag to indicate if there was an error in a child process. + self.error = False + + def LoadTargetBuildFileCallback(self, result): + """Handle the results of running LoadTargetBuildFile in another process. + """ + self.condition.acquire() + if not result: + self.error = True + self.condition.notify() + self.condition.release() + return + (build_file_path0, data0, aux_data0, dependencies0) = result + self.data['target_build_files'].add(build_file_path0) + for key in data0: + self.data[key] = data0[key] + for key in aux_data0: + self.aux_data[key] = aux_data0[key] + for new_dependency in dependencies0: + if new_dependency not in self.scheduled: + self.scheduled.add(new_dependency) + self.dependencies.append(new_dependency) + self.pending -= 1 + self.condition.notify() + self.condition.release() + + +def LoadTargetBuildFilesParallel(build_files, data, aux_data, + variables, includes, depth, check, + generator_input_info): + parallel_state = ParallelState() + parallel_state.condition = threading.Condition() + # Make copies of the build_files argument that we can modify while working. + parallel_state.dependencies = list(build_files) + parallel_state.scheduled = set(build_files) + parallel_state.pending = 0 + parallel_state.data = data + parallel_state.aux_data = aux_data + + try: + parallel_state.condition.acquire() + while parallel_state.dependencies or parallel_state.pending: + if parallel_state.error: + break + if not parallel_state.dependencies: + parallel_state.condition.wait() + continue + + dependency = parallel_state.dependencies.pop() + + parallel_state.pending += 1 + data_in = {} + data_in['target_build_files'] = data['target_build_files'] + aux_data_in = {} + global_flags = { + 'path_sections': globals()['path_sections'], + 'non_configuration_keys': globals()['non_configuration_keys'], + 'multiple_toolsets': globals()['multiple_toolsets']} + + if not parallel_state.pool: + parallel_state.pool = multiprocessing.Pool(8) + parallel_state.pool.apply_async( + CallLoadTargetBuildFile, + args = (global_flags, dependency, + data_in, aux_data_in, + variables, includes, depth, check, generator_input_info), + callback = parallel_state.LoadTargetBuildFileCallback) + except KeyboardInterrupt, e: + parallel_state.pool.terminate() + raise e + + parallel_state.condition.release() + + parallel_state.pool.close() + parallel_state.pool.join() + parallel_state.pool = None + + if parallel_state.error: + sys.exit(1) + +# Look for the bracket that matches the first bracket seen in a +# string, and return the start and end as a tuple. For example, if +# the input is something like "<(foo <(bar)) blah", then it would +# return (1, 13), indicating the entire string except for the leading +# "<" and trailing " blah". +LBRACKETS= set('{[(') +BRACKETS = {'}': '{', ']': '[', ')': '('} +def FindEnclosingBracketGroup(input_str): + stack = [] + start = -1 + for index, char in enumerate(input_str): + if char in LBRACKETS: + stack.append(char) + if start == -1: + start = index + elif char in BRACKETS: + if not stack: + return (-1, -1) + if stack.pop() != BRACKETS[char]: + return (-1, -1) + if not stack: + return (start, index + 1) + return (-1, -1) + + +def IsStrCanonicalInt(string): + """Returns True if |string| is in its canonical integer form. + + The canonical form is such that str(int(string)) == string. + """ + if type(string) is str: + # This function is called a lot so for maximum performance, avoid + # involving regexps which would otherwise make the code much + # shorter. Regexps would need twice the time of this function. + if string: + if string == "0": + return True + if string[0] == "-": + string = string[1:] + if not string: + return False + if '1' <= string[0] <= '9': + return string.isdigit() + + return False + + +# This matches things like "<(asdf)", "(?P<(?:(?:!?@?)|\|)?)' + '(?P[-a-zA-Z0-9_.]+)?' + '\((?P\s*\[?)' + '(?P.*?)(\]?)\))') + +# This matches the same as early_variable_re, but with '>' instead of '<'. +late_variable_re = re.compile( + '(?P(?P>(?:(?:!?@?)|\|)?)' + '(?P[-a-zA-Z0-9_.]+)?' + '\((?P\s*\[?)' + '(?P.*?)(\]?)\))') + +# This matches the same as early_variable_re, but with '^' instead of '<'. +latelate_variable_re = re.compile( + '(?P(?P[\^](?:(?:!?@?)|\|)?)' + '(?P[-a-zA-Z0-9_.]+)?' + '\((?P\s*\[?)' + '(?P.*?)(\]?)\))') + +# Global cache of results from running commands so they don't have to be run +# more then once. +cached_command_results = {} + + +def FixupPlatformCommand(cmd): + if sys.platform == 'win32': + if type(cmd) is list: + cmd = [re.sub('^cat ', 'type ', cmd[0])] + cmd[1:] + else: + cmd = re.sub('^cat ', 'type ', cmd) + return cmd + + +PHASE_EARLY = 0 +PHASE_LATE = 1 +PHASE_LATELATE = 2 + + +def ExpandVariables(input, phase, variables, build_file): + # Look for the pattern that gets expanded into variables + if phase == PHASE_EARLY: + variable_re = early_variable_re + expansion_symbol = '<' + elif phase == PHASE_LATE: + variable_re = late_variable_re + expansion_symbol = '>' + elif phase == PHASE_LATELATE: + variable_re = latelate_variable_re + expansion_symbol = '^' + else: + assert False + + input_str = str(input) + if IsStrCanonicalInt(input_str): + return int(input_str) + + # Do a quick scan to determine if an expensive regex search is warranted. + if expansion_symbol not in input_str: + return input_str + + # Get the entire list of matches as a list of MatchObject instances. + # (using findall here would return strings instead of MatchObjects). + matches = list(variable_re.finditer(input_str)) + if not matches: + return input_str + + output = input_str + # Reverse the list of matches so that replacements are done right-to-left. + # That ensures that earlier replacements won't mess up the string in a + # way that causes later calls to find the earlier substituted text instead + # of what's intended for replacement. + matches.reverse() + for match_group in matches: + match = match_group.groupdict() + gyp.DebugOutput(gyp.DEBUG_VARIABLES, "Matches: %r", match) + # match['replace'] is the substring to look for, match['type'] + # is the character code for the replacement type (< > ! <| >| <@ + # >@ !@), match['is_array'] contains a '[' for command + # arrays, and match['content'] is the name of the variable (< >) + # or command to run (!). match['command_string'] is an optional + # command string. Currently, only 'pymod_do_main' is supported. + + # run_command is true if a ! variant is used. + run_command = '!' in match['type'] + command_string = match['command_string'] + + # file_list is true if a | variant is used. + file_list = '|' in match['type'] + + # Capture these now so we can adjust them later. + replace_start = match_group.start('replace') + replace_end = match_group.end('replace') + + # Find the ending paren, and re-evaluate the contained string. + (c_start, c_end) = FindEnclosingBracketGroup(input_str[replace_start:]) + + # Adjust the replacement range to match the entire command + # found by FindEnclosingBracketGroup (since the variable_re + # probably doesn't match the entire command if it contained + # nested variables). + replace_end = replace_start + c_end + + # Find the "real" replacement, matching the appropriate closing + # paren, and adjust the replacement start and end. + replacement = input_str[replace_start:replace_end] + + # Figure out what the contents of the variable parens are. + contents_start = replace_start + c_start + 1 + contents_end = replace_end - 1 + contents = input_str[contents_start:contents_end] + + # Do filter substitution now for <|(). + # Admittedly, this is different than the evaluation order in other + # contexts. However, since filtration has no chance to run on <|(), + # this seems like the only obvious way to give them access to filters. + if file_list: + processed_variables = gyp.simple_copy.deepcopy(variables) + ProcessListFiltersInDict(contents, processed_variables) + # Recurse to expand variables in the contents + contents = ExpandVariables(contents, phase, + processed_variables, build_file) + else: + # Recurse to expand variables in the contents + contents = ExpandVariables(contents, phase, variables, build_file) + + # Strip off leading/trailing whitespace so that variable matches are + # simpler below (and because they are rarely needed). + contents = contents.strip() + + # expand_to_list is true if an @ variant is used. In that case, + # the expansion should result in a list. Note that the caller + # is to be expecting a list in return, and not all callers do + # because not all are working in list context. Also, for list + # expansions, there can be no other text besides the variable + # expansion in the input string. + expand_to_list = '@' in match['type'] and input_str == replacement + + if run_command or file_list: + # Find the build file's directory, so commands can be run or file lists + # generated relative to it. + build_file_dir = os.path.dirname(build_file) + if build_file_dir == '' and not file_list: + # If build_file is just a leaf filename indicating a file in the + # current directory, build_file_dir might be an empty string. Set + # it to None to signal to subprocess.Popen that it should run the + # command in the current directory. + build_file_dir = None + + # Support <|(listfile.txt ...) which generates a file + # containing items from a gyp list, generated at gyp time. + # This works around actions/rules which have more inputs than will + # fit on the command line. + if file_list: + if type(contents) is list: + contents_list = contents + else: + contents_list = contents.split(' ') + replacement = contents_list[0] + if os.path.isabs(replacement): + raise GypError('| cannot handle absolute paths, got "%s"' % replacement) + + if not generator_filelist_paths: + path = os.path.join(build_file_dir, replacement) + else: + if os.path.isabs(build_file_dir): + toplevel = generator_filelist_paths['toplevel'] + rel_build_file_dir = gyp.common.RelativePath(build_file_dir, toplevel) + else: + rel_build_file_dir = build_file_dir + qualified_out_dir = generator_filelist_paths['qualified_out_dir'] + path = os.path.join(qualified_out_dir, rel_build_file_dir, replacement) + gyp.common.EnsureDirExists(path) + + replacement = gyp.common.RelativePath(path, build_file_dir) + f = gyp.common.WriteOnDiff(path) + for i in contents_list[1:]: + f.write('%s\n' % i) + f.close() + + elif run_command: + use_shell = True + if match['is_array']: + contents = eval(contents) + use_shell = False + + # Check for a cached value to avoid executing commands, or generating + # file lists more than once. The cache key contains the command to be + # run as well as the directory to run it from, to account for commands + # that depend on their current directory. + # TODO(http://code.google.com/p/gyp/issues/detail?id=111): In theory, + # someone could author a set of GYP files where each time the command + # is invoked it produces different output by design. When the need + # arises, the syntax should be extended to support no caching off a + # command's output so it is run every time. + cache_key = (str(contents), build_file_dir) + cached_value = cached_command_results.get(cache_key, None) + if cached_value is None: + gyp.DebugOutput(gyp.DEBUG_VARIABLES, + "Executing command '%s' in directory '%s'", + contents, build_file_dir) + + replacement = '' + + if command_string == 'pymod_do_main': + # (sources/) etc. to resolve to + # and empty list if undefined. This allows actions to: + # 'action!': [ + # '>@(_sources!)', + # ], + # 'action/': [ + # '>@(_sources/)', + # ], + replacement = [] + else: + raise GypError('Undefined variable ' + contents + + ' in ' + build_file) + else: + replacement = variables[contents] + + if type(replacement) is list: + for item in replacement: + if not contents[-1] == '/' and type(item) not in (str, int): + raise GypError('Variable ' + contents + + ' must expand to a string or list of strings; ' + + 'list contains a ' + + item.__class__.__name__) + # Run through the list and handle variable expansions in it. Since + # the list is guaranteed not to contain dicts, this won't do anything + # with conditions sections. + ProcessVariablesAndConditionsInList(replacement, phase, variables, + build_file) + elif type(replacement) not in (str, int): + raise GypError('Variable ' + contents + + ' must expand to a string or list of strings; ' + + 'found a ' + replacement.__class__.__name__) + + if expand_to_list: + # Expanding in list context. It's guaranteed that there's only one + # replacement to do in |input_str| and that it's this replacement. See + # above. + if type(replacement) is list: + # If it's already a list, make a copy. + output = replacement[:] + else: + # Split it the same way sh would split arguments. + output = shlex.split(str(replacement)) + else: + # Expanding in string context. + encoded_replacement = '' + if type(replacement) is list: + # When expanding a list into string context, turn the list items + # into a string in a way that will work with a subprocess call. + # + # TODO(mark): This isn't completely correct. This should + # call a generator-provided function that observes the + # proper list-to-argument quoting rules on a specific + # platform instead of just calling the POSIX encoding + # routine. + encoded_replacement = gyp.common.EncodePOSIXShellList(replacement) + else: + encoded_replacement = replacement + + output = output[:replace_start] + str(encoded_replacement) + \ + output[replace_end:] + # Prepare for the next match iteration. + input_str = output + + # Look for more matches now that we've replaced some, to deal with + # expanding local variables (variables defined in the same + # variables block as this one). + gyp.DebugOutput(gyp.DEBUG_VARIABLES, "Found output %r, recursing.", output) + if type(output) is list: + if output and type(output[0]) is list: + # Leave output alone if it's a list of lists. + # We don't want such lists to be stringified. + pass + else: + new_output = [] + for item in output: + new_output.append( + ExpandVariables(item, phase, variables, build_file)) + output = new_output + else: + output = ExpandVariables(output, phase, variables, build_file) + + # Convert all strings that are canonically-represented integers into integers. + if type(output) is list: + for index in xrange(0, len(output)): + if IsStrCanonicalInt(output[index]): + output[index] = int(output[index]) + elif IsStrCanonicalInt(output): + output = int(output) + + return output + +# The same condition is often evaluated over and over again so it +# makes sense to cache as much as possible between evaluations. +cached_conditions_asts = {} + +def EvalCondition(condition, conditions_key, phase, variables, build_file): + """Returns the dict that should be used or None if the result was + that nothing should be used.""" + if type(condition) is not list: + raise GypError(conditions_key + ' must be a list') + if len(condition) != 2 and len(condition) != 3: + # It's possible that condition[0] won't work in which case this + # attempt will raise its own IndexError. That's probably fine. + raise GypError(conditions_key + ' ' + condition[0] + + ' must be length 2 or 3, not ' + str(len(condition))) + + [cond_expr, true_dict] = condition[0:2] + false_dict = None + if len(condition) == 3: + false_dict = condition[2] + + # Do expansions on the condition itself. Since the conditon can naturally + # contain variable references without needing to resort to GYP expansion + # syntax, this is of dubious value for variables, but someone might want to + # use a command expansion directly inside a condition. + cond_expr_expanded = ExpandVariables(cond_expr, phase, variables, + build_file) + if type(cond_expr_expanded) not in (str, int): + raise ValueError, \ + 'Variable expansion in this context permits str and int ' + \ + 'only, found ' + cond_expr_expanded.__class__.__name__ + + try: + if cond_expr_expanded in cached_conditions_asts: + ast_code = cached_conditions_asts[cond_expr_expanded] + else: + ast_code = compile(cond_expr_expanded, '', 'eval') + cached_conditions_asts[cond_expr_expanded] = ast_code + if eval(ast_code, {'__builtins__': None}, variables): + return true_dict + return false_dict + except SyntaxError, e: + syntax_error = SyntaxError('%s while evaluating condition \'%s\' in %s ' + 'at character %d.' % + (str(e.args[0]), e.text, build_file, e.offset), + e.filename, e.lineno, e.offset, e.text) + raise syntax_error + except NameError, e: + gyp.common.ExceptionAppend(e, 'while evaluating condition \'%s\' in %s' % + (cond_expr_expanded, build_file)) + raise GypError(e) + + +def ProcessConditionsInDict(the_dict, phase, variables, build_file): + # Process a 'conditions' or 'target_conditions' section in the_dict, + # depending on phase. + # early -> conditions + # late -> target_conditions + # latelate -> no conditions + # + # Each item in a conditions list consists of cond_expr, a string expression + # evaluated as the condition, and true_dict, a dict that will be merged into + # the_dict if cond_expr evaluates to true. Optionally, a third item, + # false_dict, may be present. false_dict is merged into the_dict if + # cond_expr evaluates to false. + # + # Any dict merged into the_dict will be recursively processed for nested + # conditionals and other expansions, also according to phase, immediately + # prior to being merged. + + if phase == PHASE_EARLY: + conditions_key = 'conditions' + elif phase == PHASE_LATE: + conditions_key = 'target_conditions' + elif phase == PHASE_LATELATE: + return + else: + assert False + + if not conditions_key in the_dict: + return + + conditions_list = the_dict[conditions_key] + # Unhook the conditions list, it's no longer needed. + del the_dict[conditions_key] + + for condition in conditions_list: + merge_dict = EvalCondition(condition, conditions_key, phase, variables, + build_file) + + if merge_dict != None: + # Expand variables and nested conditinals in the merge_dict before + # merging it. + ProcessVariablesAndConditionsInDict(merge_dict, phase, + variables, build_file) + + MergeDicts(the_dict, merge_dict, build_file, build_file) + + +def LoadAutomaticVariablesFromDict(variables, the_dict): + # Any keys with plain string values in the_dict become automatic variables. + # The variable name is the key name with a "_" character prepended. + for key, value in the_dict.iteritems(): + if type(value) in (str, int, list): + variables['_' + key] = value + + +def LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key): + # Any keys in the_dict's "variables" dict, if it has one, becomes a + # variable. The variable name is the key name in the "variables" dict. + # Variables that end with the % character are set only if they are unset in + # the variables dict. the_dict_key is the name of the key that accesses + # the_dict in the_dict's parent dict. If the_dict's parent is not a dict + # (it could be a list or it could be parentless because it is a root dict), + # the_dict_key will be None. + for key, value in the_dict.get('variables', {}).iteritems(): + if type(value) not in (str, int, list): + continue + + if key.endswith('%'): + variable_name = key[:-1] + if variable_name in variables: + # If the variable is already set, don't set it. + continue + if the_dict_key is 'variables' and variable_name in the_dict: + # If the variable is set without a % in the_dict, and the_dict is a + # variables dict (making |variables| a varaibles sub-dict of a + # variables dict), use the_dict's definition. + value = the_dict[variable_name] + else: + variable_name = key + + variables[variable_name] = value + + +def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in, + build_file, the_dict_key=None): + """Handle all variable and command expansion and conditional evaluation. + + This function is the public entry point for all variable expansions and + conditional evaluations. The variables_in dictionary will not be modified + by this function. + """ + + # Make a copy of the variables_in dict that can be modified during the + # loading of automatics and the loading of the variables dict. + variables = variables_in.copy() + LoadAutomaticVariablesFromDict(variables, the_dict) + + if 'variables' in the_dict: + # Make sure all the local variables are added to the variables + # list before we process them so that you can reference one + # variable from another. They will be fully expanded by recursion + # in ExpandVariables. + for key, value in the_dict['variables'].iteritems(): + variables[key] = value + + # Handle the associated variables dict first, so that any variable + # references within can be resolved prior to using them as variables. + # Pass a copy of the variables dict to avoid having it be tainted. + # Otherwise, it would have extra automatics added for everything that + # should just be an ordinary variable in this scope. + ProcessVariablesAndConditionsInDict(the_dict['variables'], phase, + variables, build_file, 'variables') + + LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key) + + for key, value in the_dict.iteritems(): + # Skip "variables", which was already processed if present. + if key != 'variables' and type(value) is str: + expanded = ExpandVariables(value, phase, variables, build_file) + if type(expanded) not in (str, int): + raise ValueError, \ + 'Variable expansion in this context permits str and int ' + \ + 'only, found ' + expanded.__class__.__name__ + ' for ' + key + the_dict[key] = expanded + + # Variable expansion may have resulted in changes to automatics. Reload. + # TODO(mark): Optimization: only reload if no changes were made. + variables = variables_in.copy() + LoadAutomaticVariablesFromDict(variables, the_dict) + LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key) + + # Process conditions in this dict. This is done after variable expansion + # so that conditions may take advantage of expanded variables. For example, + # if the_dict contains: + # {'type': '<(library_type)', + # 'conditions': [['_type=="static_library"', { ... }]]}, + # _type, as used in the condition, will only be set to the value of + # library_type if variable expansion is performed before condition + # processing. However, condition processing should occur prior to recursion + # so that variables (both automatic and "variables" dict type) may be + # adjusted by conditions sections, merged into the_dict, and have the + # intended impact on contained dicts. + # + # This arrangement means that a "conditions" section containing a "variables" + # section will only have those variables effective in subdicts, not in + # the_dict. The workaround is to put a "conditions" section within a + # "variables" section. For example: + # {'conditions': [['os=="mac"', {'variables': {'define': 'IS_MAC'}}]], + # 'defines': ['<(define)'], + # 'my_subdict': {'defines': ['<(define)']}}, + # will not result in "IS_MAC" being appended to the "defines" list in the + # current scope but would result in it being appended to the "defines" list + # within "my_subdict". By comparison: + # {'variables': {'conditions': [['os=="mac"', {'define': 'IS_MAC'}]]}, + # 'defines': ['<(define)'], + # 'my_subdict': {'defines': ['<(define)']}}, + # will append "IS_MAC" to both "defines" lists. + + # Evaluate conditions sections, allowing variable expansions within them + # as well as nested conditionals. This will process a 'conditions' or + # 'target_conditions' section, perform appropriate merging and recursive + # conditional and variable processing, and then remove the conditions section + # from the_dict if it is present. + ProcessConditionsInDict(the_dict, phase, variables, build_file) + + # Conditional processing may have resulted in changes to automatics or the + # variables dict. Reload. + variables = variables_in.copy() + LoadAutomaticVariablesFromDict(variables, the_dict) + LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key) + + # Recurse into child dicts, or process child lists which may result in + # further recursion into descendant dicts. + for key, value in the_dict.iteritems(): + # Skip "variables" and string values, which were already processed if + # present. + if key == 'variables' or type(value) is str: + continue + if type(value) is dict: + # Pass a copy of the variables dict so that subdicts can't influence + # parents. + ProcessVariablesAndConditionsInDict(value, phase, variables, + build_file, key) + elif type(value) is list: + # The list itself can't influence the variables dict, and + # ProcessVariablesAndConditionsInList will make copies of the variables + # dict if it needs to pass it to something that can influence it. No + # copy is necessary here. + ProcessVariablesAndConditionsInList(value, phase, variables, + build_file) + elif type(value) is not int: + raise TypeError, 'Unknown type ' + value.__class__.__name__ + \ + ' for ' + key + + +def ProcessVariablesAndConditionsInList(the_list, phase, variables, + build_file): + # Iterate using an index so that new values can be assigned into the_list. + index = 0 + while index < len(the_list): + item = the_list[index] + if type(item) is dict: + # Make a copy of the variables dict so that it won't influence anything + # outside of its own scope. + ProcessVariablesAndConditionsInDict(item, phase, variables, build_file) + elif type(item) is list: + ProcessVariablesAndConditionsInList(item, phase, variables, build_file) + elif type(item) is str: + expanded = ExpandVariables(item, phase, variables, build_file) + if type(expanded) in (str, int): + the_list[index] = expanded + elif type(expanded) is list: + the_list[index:index+1] = expanded + index += len(expanded) + + # index now identifies the next item to examine. Continue right now + # without falling into the index increment below. + continue + else: + raise ValueError, \ + 'Variable expansion in this context permits strings and ' + \ + 'lists only, found ' + expanded.__class__.__name__ + ' at ' + \ + index + elif type(item) is not int: + raise TypeError, 'Unknown type ' + item.__class__.__name__ + \ + ' at index ' + index + index = index + 1 + + +def BuildTargetsDict(data): + """Builds a dict mapping fully-qualified target names to their target dicts. + + |data| is a dict mapping loaded build files by pathname relative to the + current directory. Values in |data| are build file contents. For each + |data| value with a "targets" key, the value of the "targets" key is taken + as a list containing target dicts. Each target's fully-qualified name is + constructed from the pathname of the build file (|data| key) and its + "target_name" property. These fully-qualified names are used as the keys + in the returned dict. These keys provide access to the target dicts, + the dicts in the "targets" lists. + """ + + targets = {} + for build_file in data['target_build_files']: + for target in data[build_file].get('targets', []): + target_name = gyp.common.QualifiedTarget(build_file, + target['target_name'], + target['toolset']) + if target_name in targets: + raise GypError('Duplicate target definitions for ' + target_name) + targets[target_name] = target + + return targets + + +def QualifyDependencies(targets): + """Make dependency links fully-qualified relative to the current directory. + + |targets| is a dict mapping fully-qualified target names to their target + dicts. For each target in this dict, keys known to contain dependency + links are examined, and any dependencies referenced will be rewritten + so that they are fully-qualified and relative to the current directory. + All rewritten dependencies are suitable for use as keys to |targets| or a + similar dict. + """ + + all_dependency_sections = [dep + op + for dep in dependency_sections + for op in ('', '!', '/')] + + for target, target_dict in targets.iteritems(): + target_build_file = gyp.common.BuildFile(target) + toolset = target_dict['toolset'] + for dependency_key in all_dependency_sections: + dependencies = target_dict.get(dependency_key, []) + for index in xrange(0, len(dependencies)): + dep_file, dep_target, dep_toolset = gyp.common.ResolveTarget( + target_build_file, dependencies[index], toolset) + if not multiple_toolsets: + # Ignore toolset specification in the dependency if it is specified. + dep_toolset = toolset + dependency = gyp.common.QualifiedTarget(dep_file, + dep_target, + dep_toolset) + dependencies[index] = dependency + + # Make sure anything appearing in a list other than "dependencies" also + # appears in the "dependencies" list. + if dependency_key != 'dependencies' and \ + dependency not in target_dict['dependencies']: + raise GypError('Found ' + dependency + ' in ' + dependency_key + + ' of ' + target + ', but not in dependencies') + + +def ExpandWildcardDependencies(targets, data): + """Expands dependencies specified as build_file:*. + + For each target in |targets|, examines sections containing links to other + targets. If any such section contains a link of the form build_file:*, it + is taken as a wildcard link, and is expanded to list each target in + build_file. The |data| dict provides access to build file dicts. + + Any target that does not wish to be included by wildcard can provide an + optional "suppress_wildcard" key in its target dict. When present and + true, a wildcard dependency link will not include such targets. + + All dependency names, including the keys to |targets| and the values in each + dependency list, must be qualified when this function is called. + """ + + for target, target_dict in targets.iteritems(): + toolset = target_dict['toolset'] + target_build_file = gyp.common.BuildFile(target) + for dependency_key in dependency_sections: + dependencies = target_dict.get(dependency_key, []) + + # Loop this way instead of "for dependency in" or "for index in xrange" + # because the dependencies list will be modified within the loop body. + index = 0 + while index < len(dependencies): + (dependency_build_file, dependency_target, dependency_toolset) = \ + gyp.common.ParseQualifiedTarget(dependencies[index]) + if dependency_target != '*' and dependency_toolset != '*': + # Not a wildcard. Keep it moving. + index = index + 1 + continue + + if dependency_build_file == target_build_file: + # It's an error for a target to depend on all other targets in + # the same file, because a target cannot depend on itself. + raise GypError('Found wildcard in ' + dependency_key + ' of ' + + target + ' referring to same build file') + + # Take the wildcard out and adjust the index so that the next + # dependency in the list will be processed the next time through the + # loop. + del dependencies[index] + index = index - 1 + + # Loop through the targets in the other build file, adding them to + # this target's list of dependencies in place of the removed + # wildcard. + dependency_target_dicts = data[dependency_build_file]['targets'] + for dependency_target_dict in dependency_target_dicts: + if int(dependency_target_dict.get('suppress_wildcard', False)): + continue + dependency_target_name = dependency_target_dict['target_name'] + if (dependency_target != '*' and + dependency_target != dependency_target_name): + continue + dependency_target_toolset = dependency_target_dict['toolset'] + if (dependency_toolset != '*' and + dependency_toolset != dependency_target_toolset): + continue + dependency = gyp.common.QualifiedTarget(dependency_build_file, + dependency_target_name, + dependency_target_toolset) + index = index + 1 + dependencies.insert(index, dependency) + + index = index + 1 + + +def Unify(l): + """Removes duplicate elements from l, keeping the first element.""" + seen = {} + return [seen.setdefault(e, e) for e in l if e not in seen] + + +def RemoveDuplicateDependencies(targets): + """Makes sure every dependency appears only once in all targets's dependency + lists.""" + for target_name, target_dict in targets.iteritems(): + for dependency_key in dependency_sections: + dependencies = target_dict.get(dependency_key, []) + if dependencies: + target_dict[dependency_key] = Unify(dependencies) + + +def Filter(l, item): + """Removes item from l.""" + res = {} + return [res.setdefault(e, e) for e in l if e != item] + + +def RemoveSelfDependencies(targets): + """Remove self dependencies from targets that have the prune_self_dependency + variable set.""" + for target_name, target_dict in targets.iteritems(): + for dependency_key in dependency_sections: + dependencies = target_dict.get(dependency_key, []) + if dependencies: + for t in dependencies: + if t == target_name: + if targets[t].get('variables', {}).get('prune_self_dependency', 0): + target_dict[dependency_key] = Filter(dependencies, target_name) + + +def RemoveLinkDependenciesFromNoneTargets(targets): + """Remove dependencies having the 'link_dependency' attribute from the 'none' + targets.""" + for target_name, target_dict in targets.iteritems(): + for dependency_key in dependency_sections: + dependencies = target_dict.get(dependency_key, []) + if dependencies: + for t in dependencies: + if target_dict.get('type', None) == 'none': + if targets[t].get('variables', {}).get('link_dependency', 0): + target_dict[dependency_key] = \ + Filter(target_dict[dependency_key], t) + + +class DependencyGraphNode(object): + """ + + Attributes: + ref: A reference to an object that this DependencyGraphNode represents. + dependencies: List of DependencyGraphNodes on which this one depends. + dependents: List of DependencyGraphNodes that depend on this one. + """ + + class CircularException(GypError): + pass + + def __init__(self, ref): + self.ref = ref + self.dependencies = [] + self.dependents = [] + + def __repr__(self): + return '' % self.ref + + def FlattenToList(self): + # flat_list is the sorted list of dependencies - actually, the list items + # are the "ref" attributes of DependencyGraphNodes. Every target will + # appear in flat_list after all of its dependencies, and before all of its + # dependents. + flat_list = OrderedSet() + + # in_degree_zeros is the list of DependencyGraphNodes that have no + # dependencies not in flat_list. Initially, it is a copy of the children + # of this node, because when the graph was built, nodes with no + # dependencies were made implicit dependents of the root node. + in_degree_zeros = set(self.dependents[:]) + + while in_degree_zeros: + # Nodes in in_degree_zeros have no dependencies not in flat_list, so they + # can be appended to flat_list. Take these nodes out of in_degree_zeros + # as work progresses, so that the next node to process from the list can + # always be accessed at a consistent position. + node = in_degree_zeros.pop() + flat_list.add(node.ref) + + # Look at dependents of the node just added to flat_list. Some of them + # may now belong in in_degree_zeros. + for node_dependent in node.dependents: + is_in_degree_zero = True + # TODO: We want to check through the + # node_dependent.dependencies list but if it's long and we + # always start at the beginning, then we get O(n^2) behaviour. + for node_dependent_dependency in node_dependent.dependencies: + if not node_dependent_dependency.ref in flat_list: + # The dependent one or more dependencies not in flat_list. There + # will be more chances to add it to flat_list when examining + # it again as a dependent of those other dependencies, provided + # that there are no cycles. + is_in_degree_zero = False + break + + if is_in_degree_zero: + # All of the dependent's dependencies are already in flat_list. Add + # it to in_degree_zeros where it will be processed in a future + # iteration of the outer loop. + in_degree_zeros.add(node_dependent) + + return list(flat_list) + + def FindCycles(self, path=None): + """ + Returns a list of cycles in the graph, where each cycle is its own list. + """ + if path is None: + path = [self] + + results = [] + for node in self.dependents: + if node in path: + cycle = [node] + for part in path: + cycle.append(part) + if part == node: + break + results.append(tuple(cycle)) + else: + results.extend(node.FindCycles([node] + path)) + + return list(set(results)) + + def DirectDependencies(self, dependencies=None): + """Returns a list of just direct dependencies.""" + if dependencies == None: + dependencies = [] + + for dependency in self.dependencies: + # Check for None, corresponding to the root node. + if dependency.ref != None and dependency.ref not in dependencies: + dependencies.append(dependency.ref) + + return dependencies + + def _AddImportedDependencies(self, targets, dependencies=None): + """Given a list of direct dependencies, adds indirect dependencies that + other dependencies have declared to export their settings. + + This method does not operate on self. Rather, it operates on the list + of dependencies in the |dependencies| argument. For each dependency in + that list, if any declares that it exports the settings of one of its + own dependencies, those dependencies whose settings are "passed through" + are added to the list. As new items are added to the list, they too will + be processed, so it is possible to import settings through multiple levels + of dependencies. + + This method is not terribly useful on its own, it depends on being + "primed" with a list of direct dependencies such as one provided by + DirectDependencies. DirectAndImportedDependencies is intended to be the + public entry point. + """ + + if dependencies == None: + dependencies = [] + + index = 0 + while index < len(dependencies): + dependency = dependencies[index] + dependency_dict = targets[dependency] + # Add any dependencies whose settings should be imported to the list + # if not already present. Newly-added items will be checked for + # their own imports when the list iteration reaches them. + # Rather than simply appending new items, insert them after the + # dependency that exported them. This is done to more closely match + # the depth-first method used by DeepDependencies. + add_index = 1 + for imported_dependency in \ + dependency_dict.get('export_dependent_settings', []): + if imported_dependency not in dependencies: + dependencies.insert(index + add_index, imported_dependency) + add_index = add_index + 1 + index = index + 1 + + return dependencies + + def DirectAndImportedDependencies(self, targets, dependencies=None): + """Returns a list of a target's direct dependencies and all indirect + dependencies that a dependency has advertised settings should be exported + through the dependency for. + """ + + dependencies = self.DirectDependencies(dependencies) + return self._AddImportedDependencies(targets, dependencies) + + def DeepDependencies(self, dependencies=None): + """Returns an OrderedSet of all of a target's dependencies, recursively.""" + if dependencies is None: + # Using a list to get ordered output and a set to do fast "is it + # already added" checks. + dependencies = OrderedSet() + + for dependency in self.dependencies: + # Check for None, corresponding to the root node. + if dependency.ref is None: + continue + if dependency.ref not in dependencies: + dependencies.add(dependency.ref) + dependency.DeepDependencies(dependencies) + + return dependencies + + def _LinkDependenciesInternal(self, targets, include_shared_libraries, + dependencies=None, initial=True): + """Returns an OrderedSet of dependency targets that are linked + into this target. + + This function has a split personality, depending on the setting of + |initial|. Outside callers should always leave |initial| at its default + setting. + + When adding a target to the list of dependencies, this function will + recurse into itself with |initial| set to False, to collect dependencies + that are linked into the linkable target for which the list is being built. + + If |include_shared_libraries| is False, the resulting dependencies will not + include shared_library targets that are linked into this target. + """ + if dependencies is None: + # Using a list to get ordered output and a set to do fast "is it + # already added" checks. + dependencies = OrderedSet() + + # Check for None, corresponding to the root node. + if self.ref is None: + return dependencies + + # It's kind of sucky that |targets| has to be passed into this function, + # but that's presently the easiest way to access the target dicts so that + # this function can find target types. + + if 'target_name' not in targets[self.ref]: + raise GypError("Missing 'target_name' field in target.") + + if 'type' not in targets[self.ref]: + raise GypError("Missing 'type' field in target %s" % + targets[self.ref]['target_name']) + + target_type = targets[self.ref]['type'] + + is_linkable = target_type in linkable_types + + if initial and not is_linkable: + # If this is the first target being examined and it's not linkable, + # return an empty list of link dependencies, because the link + # dependencies are intended to apply to the target itself (initial is + # True) and this target won't be linked. + return dependencies + + # Don't traverse 'none' targets if explicitly excluded. + if (target_type == 'none' and + not targets[self.ref].get('dependencies_traverse', True)): + dependencies.add(self.ref) + return dependencies + + # Executables and loadable modules are already fully and finally linked. + # Nothing else can be a link dependency of them, there can only be + # dependencies in the sense that a dependent target might run an + # executable or load the loadable_module. + if not initial and target_type in ('executable', 'loadable_module'): + return dependencies + + # Shared libraries are already fully linked. They should only be included + # in |dependencies| when adjusting static library dependencies (in order to + # link against the shared_library's import lib), but should not be included + # in |dependencies| when propagating link_settings. + # The |include_shared_libraries| flag controls which of these two cases we + # are handling. + if (not initial and target_type == 'shared_library' and + not include_shared_libraries): + return dependencies + + # The target is linkable, add it to the list of link dependencies. + if self.ref not in dependencies: + dependencies.add(self.ref) + if initial or not is_linkable: + # If this is a subsequent target and it's linkable, don't look any + # further for linkable dependencies, as they'll already be linked into + # this target linkable. Always look at dependencies of the initial + # target, and always look at dependencies of non-linkables. + for dependency in self.dependencies: + dependency._LinkDependenciesInternal(targets, + include_shared_libraries, + dependencies, False) + + return dependencies + + def DependenciesForLinkSettings(self, targets): + """ + Returns a list of dependency targets whose link_settings should be merged + into this target. + """ + + # TODO(sbaig) Currently, chrome depends on the bug that shared libraries' + # link_settings are propagated. So for now, we will allow it, unless the + # 'allow_sharedlib_linksettings_propagation' flag is explicitly set to + # False. Once chrome is fixed, we can remove this flag. + include_shared_libraries = \ + targets[self.ref].get('allow_sharedlib_linksettings_propagation', True) + return self._LinkDependenciesInternal(targets, include_shared_libraries) + + def DependenciesToLinkAgainst(self, targets): + """ + Returns a list of dependency targets that are linked into this target. + """ + return self._LinkDependenciesInternal(targets, True) + + +def BuildDependencyList(targets): + # Create a DependencyGraphNode for each target. Put it into a dict for easy + # access. + dependency_nodes = {} + for target, spec in targets.iteritems(): + if target not in dependency_nodes: + dependency_nodes[target] = DependencyGraphNode(target) + + # Set up the dependency links. Targets that have no dependencies are treated + # as dependent on root_node. + root_node = DependencyGraphNode(None) + for target, spec in targets.iteritems(): + target_node = dependency_nodes[target] + target_build_file = gyp.common.BuildFile(target) + dependencies = spec.get('dependencies') + if not dependencies: + target_node.dependencies = [root_node] + root_node.dependents.append(target_node) + else: + for dependency in dependencies: + dependency_node = dependency_nodes.get(dependency) + if not dependency_node: + raise GypError("Dependency '%s' not found while " + "trying to load target %s" % (dependency, target)) + target_node.dependencies.append(dependency_node) + dependency_node.dependents.append(target_node) + + flat_list = root_node.FlattenToList() + + # If there's anything left unvisited, there must be a circular dependency + # (cycle). If you need to figure out what's wrong, look for elements of + # targets that are not in flat_list. + if len(flat_list) != len(targets): + raise DependencyGraphNode.CircularException( + 'Some targets not reachable, cycle in dependency graph detected: ' + + ' '.join(set(flat_list) ^ set(targets))) + + return [dependency_nodes, flat_list] + + +def VerifyNoGYPFileCircularDependencies(targets): + # Create a DependencyGraphNode for each gyp file containing a target. Put + # it into a dict for easy access. + dependency_nodes = {} + for target in targets.iterkeys(): + build_file = gyp.common.BuildFile(target) + if not build_file in dependency_nodes: + dependency_nodes[build_file] = DependencyGraphNode(build_file) + + # Set up the dependency links. + for target, spec in targets.iteritems(): + build_file = gyp.common.BuildFile(target) + build_file_node = dependency_nodes[build_file] + target_dependencies = spec.get('dependencies', []) + for dependency in target_dependencies: + try: + dependency_build_file = gyp.common.BuildFile(dependency) + except GypError, e: + gyp.common.ExceptionAppend( + e, 'while computing dependencies of .gyp file %s' % build_file) + raise + + if dependency_build_file == build_file: + # A .gyp file is allowed to refer back to itself. + continue + dependency_node = dependency_nodes.get(dependency_build_file) + if not dependency_node: + raise GypError("Dependancy '%s' not found" % dependency_build_file) + if dependency_node not in build_file_node.dependencies: + build_file_node.dependencies.append(dependency_node) + dependency_node.dependents.append(build_file_node) + + + # Files that have no dependencies are treated as dependent on root_node. + root_node = DependencyGraphNode(None) + for build_file_node in dependency_nodes.itervalues(): + if len(build_file_node.dependencies) == 0: + build_file_node.dependencies.append(root_node) + root_node.dependents.append(build_file_node) + + flat_list = root_node.FlattenToList() + + # If there's anything left unvisited, there must be a circular dependency + # (cycle). + if len(flat_list) != len(dependency_nodes): + bad_files = [] + for file in dependency_nodes.iterkeys(): + if not file in flat_list: + bad_files.append(file) + common_path_prefix = os.path.commonprefix(dependency_nodes) + cycles = [] + for cycle in root_node.FindCycles(): + simplified_paths = [] + for node in cycle: + assert(node.ref.startswith(common_path_prefix)) + simplified_paths.append(node.ref[len(common_path_prefix):]) + cycles.append('Cycle: %s' % ' -> '.join(simplified_paths)) + raise DependencyGraphNode.CircularException, \ + 'Cycles in .gyp file dependency graph detected:\n' + '\n'.join(cycles) + + +def DoDependentSettings(key, flat_list, targets, dependency_nodes): + # key should be one of all_dependent_settings, direct_dependent_settings, + # or link_settings. + + for target in flat_list: + target_dict = targets[target] + build_file = gyp.common.BuildFile(target) + + if key == 'all_dependent_settings': + dependencies = dependency_nodes[target].DeepDependencies() + elif key == 'direct_dependent_settings': + dependencies = \ + dependency_nodes[target].DirectAndImportedDependencies(targets) + elif key == 'link_settings': + dependencies = \ + dependency_nodes[target].DependenciesForLinkSettings(targets) + else: + raise GypError("DoDependentSettings doesn't know how to determine " + 'dependencies for ' + key) + + for dependency in dependencies: + dependency_dict = targets[dependency] + if not key in dependency_dict: + continue + dependency_build_file = gyp.common.BuildFile(dependency) + MergeDicts(target_dict, dependency_dict[key], + build_file, dependency_build_file) + + +def AdjustStaticLibraryDependencies(flat_list, targets, dependency_nodes, + sort_dependencies): + # Recompute target "dependencies" properties. For each static library + # target, remove "dependencies" entries referring to other static libraries, + # unless the dependency has the "hard_dependency" attribute set. For each + # linkable target, add a "dependencies" entry referring to all of the + # target's computed list of link dependencies (including static libraries + # if no such entry is already present. + for target in flat_list: + target_dict = targets[target] + target_type = target_dict['type'] + + if target_type == 'static_library': + if not 'dependencies' in target_dict: + continue + + target_dict['dependencies_original'] = target_dict.get( + 'dependencies', [])[:] + + # A static library should not depend on another static library unless + # the dependency relationship is "hard," which should only be done when + # a dependent relies on some side effect other than just the build + # product, like a rule or action output. Further, if a target has a + # non-hard dependency, but that dependency exports a hard dependency, + # the non-hard dependency can safely be removed, but the exported hard + # dependency must be added to the target to keep the same dependency + # ordering. + dependencies = \ + dependency_nodes[target].DirectAndImportedDependencies(targets) + index = 0 + while index < len(dependencies): + dependency = dependencies[index] + dependency_dict = targets[dependency] + + # Remove every non-hard static library dependency and remove every + # non-static library dependency that isn't a direct dependency. + if (dependency_dict['type'] == 'static_library' and \ + not dependency_dict.get('hard_dependency', False)) or \ + (dependency_dict['type'] != 'static_library' and \ + not dependency in target_dict['dependencies']): + # Take the dependency out of the list, and don't increment index + # because the next dependency to analyze will shift into the index + # formerly occupied by the one being removed. + del dependencies[index] + else: + index = index + 1 + + # Update the dependencies. If the dependencies list is empty, it's not + # needed, so unhook it. + if len(dependencies) > 0: + target_dict['dependencies'] = dependencies + else: + del target_dict['dependencies'] + + elif target_type in linkable_types: + # Get a list of dependency targets that should be linked into this + # target. Add them to the dependencies list if they're not already + # present. + + link_dependencies = \ + dependency_nodes[target].DependenciesToLinkAgainst(targets) + for dependency in link_dependencies: + if dependency == target: + continue + if not 'dependencies' in target_dict: + target_dict['dependencies'] = [] + if not dependency in target_dict['dependencies']: + target_dict['dependencies'].append(dependency) + # Sort the dependencies list in the order from dependents to dependencies. + # e.g. If A and B depend on C and C depends on D, sort them in A, B, C, D. + # Note: flat_list is already sorted in the order from dependencies to + # dependents. + if sort_dependencies and 'dependencies' in target_dict: + target_dict['dependencies'] = [dep for dep in reversed(flat_list) + if dep in target_dict['dependencies']] + + +# Initialize this here to speed up MakePathRelative. +exception_re = re.compile(r'''["']?[-/$<>^]''') + + +def MakePathRelative(to_file, fro_file, item): + # If item is a relative path, it's relative to the build file dict that it's + # coming from. Fix it up to make it relative to the build file dict that + # it's going into. + # Exception: any |item| that begins with these special characters is + # returned without modification. + # / Used when a path is already absolute (shortcut optimization; + # such paths would be returned as absolute anyway) + # $ Used for build environment variables + # - Used for some build environment flags (such as -lapr-1 in a + # "libraries" section) + # < Used for our own variable and command expansions (see ExpandVariables) + # > Used for our own variable and command expansions (see ExpandVariables) + # ^ Used for our own variable and command expansions (see ExpandVariables) + # + # "/' Used when a value is quoted. If these are present, then we + # check the second character instead. + # + if to_file == fro_file or exception_re.match(item): + return item + else: + # TODO(dglazkov) The backslash/forward-slash replacement at the end is a + # temporary measure. This should really be addressed by keeping all paths + # in POSIX until actual project generation. + ret = os.path.normpath(os.path.join( + gyp.common.RelativePath(os.path.dirname(fro_file), + os.path.dirname(to_file)), + item)).replace('\\', '/') + if item[-1] == '/': + ret += '/' + return ret + +def MergeLists(to, fro, to_file, fro_file, is_paths=False, append=True): + # Python documentation recommends objects which do not support hash + # set this value to None. Python library objects follow this rule. + is_hashable = lambda val: val.__hash__ + + # If x is hashable, returns whether x is in s. Else returns whether x is in l. + def is_in_set_or_list(x, s, l): + if is_hashable(x): + return x in s + return x in l + + prepend_index = 0 + + # Make membership testing of hashables in |to| (in particular, strings) + # faster. + hashable_to_set = set(x for x in to if is_hashable(x)) + for item in fro: + singleton = False + if type(item) in (str, int): + # The cheap and easy case. + if is_paths: + to_item = MakePathRelative(to_file, fro_file, item) + else: + to_item = item + + if not (type(item) is str and item.startswith('-')): + # Any string that doesn't begin with a "-" is a singleton - it can + # only appear once in a list, to be enforced by the list merge append + # or prepend. + singleton = True + elif type(item) is dict: + # Make a copy of the dictionary, continuing to look for paths to fix. + # The other intelligent aspects of merge processing won't apply because + # item is being merged into an empty dict. + to_item = {} + MergeDicts(to_item, item, to_file, fro_file) + elif type(item) is list: + # Recurse, making a copy of the list. If the list contains any + # descendant dicts, path fixing will occur. Note that here, custom + # values for is_paths and append are dropped; those are only to be + # applied to |to| and |fro|, not sublists of |fro|. append shouldn't + # matter anyway because the new |to_item| list is empty. + to_item = [] + MergeLists(to_item, item, to_file, fro_file) + else: + raise TypeError, \ + 'Attempt to merge list item of unsupported type ' + \ + item.__class__.__name__ + + if append: + # If appending a singleton that's already in the list, don't append. + # This ensures that the earliest occurrence of the item will stay put. + if not singleton or not is_in_set_or_list(to_item, hashable_to_set, to): + to.append(to_item) + if is_hashable(to_item): + hashable_to_set.add(to_item) + else: + # If prepending a singleton that's already in the list, remove the + # existing instance and proceed with the prepend. This ensures that the + # item appears at the earliest possible position in the list. + while singleton and to_item in to: + to.remove(to_item) + + # Don't just insert everything at index 0. That would prepend the new + # items to the list in reverse order, which would be an unwelcome + # surprise. + to.insert(prepend_index, to_item) + if is_hashable(to_item): + hashable_to_set.add(to_item) + prepend_index = prepend_index + 1 + + +def MergeDicts(to, fro, to_file, fro_file): + # I wanted to name the parameter "from" but it's a Python keyword... + for k, v in fro.iteritems(): + # It would be nice to do "if not k in to: to[k] = v" but that wouldn't give + # copy semantics. Something else may want to merge from the |fro| dict + # later, and having the same dict ref pointed to twice in the tree isn't + # what anyone wants considering that the dicts may subsequently be + # modified. + if k in to: + bad_merge = False + if type(v) in (str, int): + if type(to[k]) not in (str, int): + bad_merge = True + elif type(v) is not type(to[k]): + bad_merge = True + + if bad_merge: + raise TypeError, \ + 'Attempt to merge dict value of type ' + v.__class__.__name__ + \ + ' into incompatible type ' + to[k].__class__.__name__ + \ + ' for key ' + k + if type(v) in (str, int): + # Overwrite the existing value, if any. Cheap and easy. + is_path = IsPathSection(k) + if is_path: + to[k] = MakePathRelative(to_file, fro_file, v) + else: + to[k] = v + elif type(v) is dict: + # Recurse, guaranteeing copies will be made of objects that require it. + if not k in to: + to[k] = {} + MergeDicts(to[k], v, to_file, fro_file) + elif type(v) is list: + # Lists in dicts can be merged with different policies, depending on + # how the key in the "from" dict (k, the from-key) is written. + # + # If the from-key has ...the to-list will have this action + # this character appended:... applied when receiving the from-list: + # = replace + # + prepend + # ? set, only if to-list does not yet exist + # (none) append + # + # This logic is list-specific, but since it relies on the associated + # dict key, it's checked in this dict-oriented function. + ext = k[-1] + append = True + if ext == '=': + list_base = k[:-1] + lists_incompatible = [list_base, list_base + '?'] + to[list_base] = [] + elif ext == '+': + list_base = k[:-1] + lists_incompatible = [list_base + '=', list_base + '?'] + append = False + elif ext == '?': + list_base = k[:-1] + lists_incompatible = [list_base, list_base + '=', list_base + '+'] + else: + list_base = k + lists_incompatible = [list_base + '=', list_base + '?'] + + # Some combinations of merge policies appearing together are meaningless. + # It's stupid to replace and append simultaneously, for example. Append + # and prepend are the only policies that can coexist. + for list_incompatible in lists_incompatible: + if list_incompatible in fro: + raise GypError('Incompatible list policies ' + k + ' and ' + + list_incompatible) + + if list_base in to: + if ext == '?': + # If the key ends in "?", the list will only be merged if it doesn't + # already exist. + continue + elif type(to[list_base]) is not list: + # This may not have been checked above if merging in a list with an + # extension character. + raise TypeError, \ + 'Attempt to merge dict value of type ' + v.__class__.__name__ + \ + ' into incompatible type ' + to[list_base].__class__.__name__ + \ + ' for key ' + list_base + '(' + k + ')' + else: + to[list_base] = [] + + # Call MergeLists, which will make copies of objects that require it. + # MergeLists can recurse back into MergeDicts, although this will be + # to make copies of dicts (with paths fixed), there will be no + # subsequent dict "merging" once entering a list because lists are + # always replaced, appended to, or prepended to. + is_paths = IsPathSection(list_base) + MergeLists(to[list_base], v, to_file, fro_file, is_paths, append) + else: + raise TypeError, \ + 'Attempt to merge dict value of unsupported type ' + \ + v.__class__.__name__ + ' for key ' + k + + +def MergeConfigWithInheritance(new_configuration_dict, build_file, + target_dict, configuration, visited): + # Skip if previously visted. + if configuration in visited: + return + + # Look at this configuration. + configuration_dict = target_dict['configurations'][configuration] + + # Merge in parents. + for parent in configuration_dict.get('inherit_from', []): + MergeConfigWithInheritance(new_configuration_dict, build_file, + target_dict, parent, visited + [configuration]) + + # Merge it into the new config. + MergeDicts(new_configuration_dict, configuration_dict, + build_file, build_file) + + # Drop abstract. + if 'abstract' in new_configuration_dict: + del new_configuration_dict['abstract'] + + +def SetUpConfigurations(target, target_dict): + # key_suffixes is a list of key suffixes that might appear on key names. + # These suffixes are handled in conditional evaluations (for =, +, and ?) + # and rules/exclude processing (for ! and /). Keys with these suffixes + # should be treated the same as keys without. + key_suffixes = ['=', '+', '?', '!', '/'] + + build_file = gyp.common.BuildFile(target) + + # Provide a single configuration by default if none exists. + # TODO(mark): Signal an error if default_configurations exists but + # configurations does not. + if not 'configurations' in target_dict: + target_dict['configurations'] = {'Default': {}} + if not 'default_configuration' in target_dict: + concrete = [i for (i, config) in target_dict['configurations'].iteritems() + if not config.get('abstract')] + target_dict['default_configuration'] = sorted(concrete)[0] + + merged_configurations = {} + configs = target_dict['configurations'] + for (configuration, old_configuration_dict) in configs.iteritems(): + # Skip abstract configurations (saves work only). + if old_configuration_dict.get('abstract'): + continue + # Configurations inherit (most) settings from the enclosing target scope. + # Get the inheritance relationship right by making a copy of the target + # dict. + new_configuration_dict = {} + for (key, target_val) in target_dict.iteritems(): + key_ext = key[-1:] + if key_ext in key_suffixes: + key_base = key[:-1] + else: + key_base = key + if not key_base in non_configuration_keys: + new_configuration_dict[key] = gyp.simple_copy.deepcopy(target_val) + + # Merge in configuration (with all its parents first). + MergeConfigWithInheritance(new_configuration_dict, build_file, + target_dict, configuration, []) + + merged_configurations[configuration] = new_configuration_dict + + # Put the new configurations back into the target dict as a configuration. + for configuration in merged_configurations.keys(): + target_dict['configurations'][configuration] = ( + merged_configurations[configuration]) + + # Now drop all the abstract ones. + for configuration in target_dict['configurations'].keys(): + old_configuration_dict = target_dict['configurations'][configuration] + if old_configuration_dict.get('abstract'): + del target_dict['configurations'][configuration] + + # Now that all of the target's configurations have been built, go through + # the target dict's keys and remove everything that's been moved into a + # "configurations" section. + delete_keys = [] + for key in target_dict: + key_ext = key[-1:] + if key_ext in key_suffixes: + key_base = key[:-1] + else: + key_base = key + if not key_base in non_configuration_keys: + delete_keys.append(key) + for key in delete_keys: + del target_dict[key] + + # Check the configurations to see if they contain invalid keys. + for configuration in target_dict['configurations'].keys(): + configuration_dict = target_dict['configurations'][configuration] + for key in configuration_dict.keys(): + if key in invalid_configuration_keys: + raise GypError('%s not allowed in the %s configuration, found in ' + 'target %s' % (key, configuration, target)) + + + +def ProcessListFiltersInDict(name, the_dict): + """Process regular expression and exclusion-based filters on lists. + + An exclusion list is in a dict key named with a trailing "!", like + "sources!". Every item in such a list is removed from the associated + main list, which in this example, would be "sources". Removed items are + placed into a "sources_excluded" list in the dict. + + Regular expression (regex) filters are contained in dict keys named with a + trailing "/", such as "sources/" to operate on the "sources" list. Regex + filters in a dict take the form: + 'sources/': [ ['exclude', '_(linux|mac|win)\\.cc$'], + ['include', '_mac\\.cc$'] ], + The first filter says to exclude all files ending in _linux.cc, _mac.cc, and + _win.cc. The second filter then includes all files ending in _mac.cc that + are now or were once in the "sources" list. Items matching an "exclude" + filter are subject to the same processing as would occur if they were listed + by name in an exclusion list (ending in "!"). Items matching an "include" + filter are brought back into the main list if previously excluded by an + exclusion list or exclusion regex filter. Subsequent matching "exclude" + patterns can still cause items to be excluded after matching an "include". + """ + + # Look through the dictionary for any lists whose keys end in "!" or "/". + # These are lists that will be treated as exclude lists and regular + # expression-based exclude/include lists. Collect the lists that are + # needed first, looking for the lists that they operate on, and assemble + # then into |lists|. This is done in a separate loop up front, because + # the _included and _excluded keys need to be added to the_dict, and that + # can't be done while iterating through it. + + lists = [] + del_lists = [] + for key, value in the_dict.iteritems(): + operation = key[-1] + if operation != '!' and operation != '/': + continue + + if type(value) is not list: + raise ValueError, name + ' key ' + key + ' must be list, not ' + \ + value.__class__.__name__ + + list_key = key[:-1] + if list_key not in the_dict: + # This happens when there's a list like "sources!" but no corresponding + # "sources" list. Since there's nothing for it to operate on, queue up + # the "sources!" list for deletion now. + del_lists.append(key) + continue + + if type(the_dict[list_key]) is not list: + value = the_dict[list_key] + raise ValueError, name + ' key ' + list_key + \ + ' must be list, not ' + \ + value.__class__.__name__ + ' when applying ' + \ + {'!': 'exclusion', '/': 'regex'}[operation] + + if not list_key in lists: + lists.append(list_key) + + # Delete the lists that are known to be unneeded at this point. + for del_list in del_lists: + del the_dict[del_list] + + for list_key in lists: + the_list = the_dict[list_key] + + # Initialize the list_actions list, which is parallel to the_list. Each + # item in list_actions identifies whether the corresponding item in + # the_list should be excluded, unconditionally preserved (included), or + # whether no exclusion or inclusion has been applied. Items for which + # no exclusion or inclusion has been applied (yet) have value -1, items + # excluded have value 0, and items included have value 1. Includes and + # excludes override previous actions. All items in list_actions are + # initialized to -1 because no excludes or includes have been processed + # yet. + list_actions = list((-1,) * len(the_list)) + + exclude_key = list_key + '!' + if exclude_key in the_dict: + for exclude_item in the_dict[exclude_key]: + for index in xrange(0, len(the_list)): + if exclude_item == the_list[index]: + # This item matches the exclude_item, so set its action to 0 + # (exclude). + list_actions[index] = 0 + + # The "whatever!" list is no longer needed, dump it. + del the_dict[exclude_key] + + regex_key = list_key + '/' + if regex_key in the_dict: + for regex_item in the_dict[regex_key]: + [action, pattern] = regex_item + pattern_re = re.compile(pattern) + + if action == 'exclude': + # This item matches an exclude regex, so set its value to 0 (exclude). + action_value = 0 + elif action == 'include': + # This item matches an include regex, so set its value to 1 (include). + action_value = 1 + else: + # This is an action that doesn't make any sense. + raise ValueError, 'Unrecognized action ' + action + ' in ' + name + \ + ' key ' + regex_key + + for index in xrange(0, len(the_list)): + list_item = the_list[index] + if list_actions[index] == action_value: + # Even if the regex matches, nothing will change so continue (regex + # searches are expensive). + continue + if pattern_re.search(list_item): + # Regular expression match. + list_actions[index] = action_value + + # The "whatever/" list is no longer needed, dump it. + del the_dict[regex_key] + + # Add excluded items to the excluded list. + # + # Note that exclude_key ("sources!") is different from excluded_key + # ("sources_excluded"). The exclude_key list is input and it was already + # processed and deleted; the excluded_key list is output and it's about + # to be created. + excluded_key = list_key + '_excluded' + if excluded_key in the_dict: + raise GypError(name + ' key ' + excluded_key + + ' must not be present prior ' + ' to applying exclusion/regex filters for ' + list_key) + + excluded_list = [] + + # Go backwards through the list_actions list so that as items are deleted, + # the indices of items that haven't been seen yet don't shift. That means + # that things need to be prepended to excluded_list to maintain them in the + # same order that they existed in the_list. + for index in xrange(len(list_actions) - 1, -1, -1): + if list_actions[index] == 0: + # Dump anything with action 0 (exclude). Keep anything with action 1 + # (include) or -1 (no include or exclude seen for the item). + excluded_list.insert(0, the_list[index]) + del the_list[index] + + # If anything was excluded, put the excluded list into the_dict at + # excluded_key. + if len(excluded_list) > 0: + the_dict[excluded_key] = excluded_list + + # Now recurse into subdicts and lists that may contain dicts. + for key, value in the_dict.iteritems(): + if type(value) is dict: + ProcessListFiltersInDict(key, value) + elif type(value) is list: + ProcessListFiltersInList(key, value) + + +def ProcessListFiltersInList(name, the_list): + for item in the_list: + if type(item) is dict: + ProcessListFiltersInDict(name, item) + elif type(item) is list: + ProcessListFiltersInList(name, item) + + +def ValidateTargetType(target, target_dict): + """Ensures the 'type' field on the target is one of the known types. + + Arguments: + target: string, name of target. + target_dict: dict, target spec. + + Raises an exception on error. + """ + VALID_TARGET_TYPES = ('executable', 'loadable_module', + 'static_library', 'shared_library', + 'none') + target_type = target_dict.get('type', None) + if target_type not in VALID_TARGET_TYPES: + raise GypError("Target %s has an invalid target type '%s'. " + "Must be one of %s." % + (target, target_type, '/'.join(VALID_TARGET_TYPES))) + if (target_dict.get('standalone_static_library', 0) and + not target_type == 'static_library'): + raise GypError('Target %s has type %s but standalone_static_library flag is' + ' only valid for static_library type.' % (target, + target_type)) + + +def ValidateSourcesInTarget(target, target_dict, build_file): + # TODO: Check if MSVC allows this for loadable_module targets. + if target_dict.get('type', None) not in ('static_library', 'shared_library'): + return + sources = target_dict.get('sources', []) + basenames = {} + for source in sources: + name, ext = os.path.splitext(source) + is_compiled_file = ext in [ + '.c', '.cc', '.cpp', '.cxx', '.m', '.mm', '.s', '.S'] + if not is_compiled_file: + continue + basename = os.path.basename(name) # Don't include extension. + basenames.setdefault(basename, []).append(source) + + error = '' + for basename, files in basenames.iteritems(): + if len(files) > 1: + error += ' %s: %s\n' % (basename, ' '.join(files)) + + if error: + print('static library %s has several files with the same basename:\n' % + target + error + 'Some build systems, e.g. MSVC08, ' + 'cannot handle that.') + raise GypError('Duplicate basenames in sources section, see list above') + + +def ValidateRulesInTarget(target, target_dict, extra_sources_for_rules): + """Ensures that the rules sections in target_dict are valid and consistent, + and determines which sources they apply to. + + Arguments: + target: string, name of target. + target_dict: dict, target spec containing "rules" and "sources" lists. + extra_sources_for_rules: a list of keys to scan for rule matches in + addition to 'sources'. + """ + + # Dicts to map between values found in rules' 'rule_name' and 'extension' + # keys and the rule dicts themselves. + rule_names = {} + rule_extensions = {} + + rules = target_dict.get('rules', []) + for rule in rules: + # Make sure that there's no conflict among rule names and extensions. + rule_name = rule['rule_name'] + if rule_name in rule_names: + raise GypError('rule %s exists in duplicate, target %s' % + (rule_name, target)) + rule_names[rule_name] = rule + + rule_extension = rule['extension'] + if rule_extension.startswith('.'): + rule_extension = rule_extension[1:] + if rule_extension in rule_extensions: + raise GypError(('extension %s associated with multiple rules, ' + + 'target %s rules %s and %s') % + (rule_extension, target, + rule_extensions[rule_extension]['rule_name'], + rule_name)) + rule_extensions[rule_extension] = rule + + # Make sure rule_sources isn't already there. It's going to be + # created below if needed. + if 'rule_sources' in rule: + raise GypError( + 'rule_sources must not exist in input, target %s rule %s' % + (target, rule_name)) + + rule_sources = [] + source_keys = ['sources'] + source_keys.extend(extra_sources_for_rules) + for source_key in source_keys: + for source in target_dict.get(source_key, []): + (source_root, source_extension) = os.path.splitext(source) + if source_extension.startswith('.'): + source_extension = source_extension[1:] + if source_extension == rule_extension: + rule_sources.append(source) + + if len(rule_sources) > 0: + rule['rule_sources'] = rule_sources + + +def ValidateRunAsInTarget(target, target_dict, build_file): + target_name = target_dict.get('target_name') + run_as = target_dict.get('run_as') + if not run_as: + return + if type(run_as) is not dict: + raise GypError("The 'run_as' in target %s from file %s should be a " + "dictionary." % + (target_name, build_file)) + action = run_as.get('action') + if not action: + raise GypError("The 'run_as' in target %s from file %s must have an " + "'action' section." % + (target_name, build_file)) + if type(action) is not list: + raise GypError("The 'action' for 'run_as' in target %s from file %s " + "must be a list." % + (target_name, build_file)) + working_directory = run_as.get('working_directory') + if working_directory and type(working_directory) is not str: + raise GypError("The 'working_directory' for 'run_as' in target %s " + "in file %s should be a string." % + (target_name, build_file)) + environment = run_as.get('environment') + if environment and type(environment) is not dict: + raise GypError("The 'environment' for 'run_as' in target %s " + "in file %s should be a dictionary." % + (target_name, build_file)) + + +def ValidateActionsInTarget(target, target_dict, build_file): + '''Validates the inputs to the actions in a target.''' + target_name = target_dict.get('target_name') + actions = target_dict.get('actions', []) + for action in actions: + action_name = action.get('action_name') + if not action_name: + raise GypError("Anonymous action in target %s. " + "An action must have an 'action_name' field." % + target_name) + inputs = action.get('inputs', None) + if inputs is None: + raise GypError('Action in target %s has no inputs.' % target_name) + action_command = action.get('action') + if action_command and not action_command[0]: + raise GypError("Empty action as command in target %s." % target_name) + + +def TurnIntIntoStrInDict(the_dict): + """Given dict the_dict, recursively converts all integers into strings. + """ + # Use items instead of iteritems because there's no need to try to look at + # reinserted keys and their associated values. + for k, v in the_dict.items(): + if type(v) is int: + v = str(v) + the_dict[k] = v + elif type(v) is dict: + TurnIntIntoStrInDict(v) + elif type(v) is list: + TurnIntIntoStrInList(v) + + if type(k) is int: + del the_dict[k] + the_dict[str(k)] = v + + +def TurnIntIntoStrInList(the_list): + """Given list the_list, recursively converts all integers into strings. + """ + for index in xrange(0, len(the_list)): + item = the_list[index] + if type(item) is int: + the_list[index] = str(item) + elif type(item) is dict: + TurnIntIntoStrInDict(item) + elif type(item) is list: + TurnIntIntoStrInList(item) + + +def PruneUnwantedTargets(targets, flat_list, dependency_nodes, root_targets, + data): + """Return only the targets that are deep dependencies of |root_targets|.""" + qualified_root_targets = [] + for target in root_targets: + target = target.strip() + qualified_targets = gyp.common.FindQualifiedTargets(target, flat_list) + if not qualified_targets: + raise GypError("Could not find target %s" % target) + qualified_root_targets.extend(qualified_targets) + + wanted_targets = {} + for target in qualified_root_targets: + wanted_targets[target] = targets[target] + for dependency in dependency_nodes[target].DeepDependencies(): + wanted_targets[dependency] = targets[dependency] + + wanted_flat_list = [t for t in flat_list if t in wanted_targets] + + # Prune unwanted targets from each build_file's data dict. + for build_file in data['target_build_files']: + if not 'targets' in data[build_file]: + continue + new_targets = [] + for target in data[build_file]['targets']: + qualified_name = gyp.common.QualifiedTarget(build_file, + target['target_name'], + target['toolset']) + if qualified_name in wanted_targets: + new_targets.append(target) + data[build_file]['targets'] = new_targets + + return wanted_targets, wanted_flat_list + + +def VerifyNoCollidingTargets(targets): + """Verify that no two targets in the same directory share the same name. + + Arguments: + targets: A list of targets in the form 'path/to/file.gyp:target_name'. + """ + # Keep a dict going from 'subdirectory:target_name' to 'foo.gyp'. + used = {} + for target in targets: + # Separate out 'path/to/file.gyp, 'target_name' from + # 'path/to/file.gyp:target_name'. + path, name = target.rsplit(':', 1) + # Separate out 'path/to', 'file.gyp' from 'path/to/file.gyp'. + subdir, gyp = os.path.split(path) + # Use '.' for the current directory '', so that the error messages make + # more sense. + if not subdir: + subdir = '.' + # Prepare a key like 'path/to:target_name'. + key = subdir + ':' + name + if key in used: + # Complain if this target is already used. + raise GypError('Duplicate target name "%s" in directory "%s" used both ' + 'in "%s" and "%s".' % (name, subdir, gyp, used[key])) + used[key] = gyp + + +def SetGeneratorGlobals(generator_input_info): + # Set up path_sections and non_configuration_keys with the default data plus + # the generator-specific data. + global path_sections + path_sections = set(base_path_sections) + path_sections.update(generator_input_info['path_sections']) + + global non_configuration_keys + non_configuration_keys = base_non_configuration_keys[:] + non_configuration_keys.extend(generator_input_info['non_configuration_keys']) + + global multiple_toolsets + multiple_toolsets = generator_input_info[ + 'generator_supports_multiple_toolsets'] + + global generator_filelist_paths + generator_filelist_paths = generator_input_info['generator_filelist_paths'] + + +def Load(build_files, variables, includes, depth, generator_input_info, check, + circular_check, parallel, root_targets): + SetGeneratorGlobals(generator_input_info) + # A generator can have other lists (in addition to sources) be processed + # for rules. + extra_sources_for_rules = generator_input_info['extra_sources_for_rules'] + + # Load build files. This loads every target-containing build file into + # the |data| dictionary such that the keys to |data| are build file names, + # and the values are the entire build file contents after "early" or "pre" + # processing has been done and includes have been resolved. + # NOTE: data contains both "target" files (.gyp) and "includes" (.gypi), as + # well as meta-data (e.g. 'included_files' key). 'target_build_files' keeps + # track of the keys corresponding to "target" files. + data = {'target_build_files': set()} + aux_data = {} + # Normalize paths everywhere. This is important because paths will be + # used as keys to the data dict and for references between input files. + build_files = set(map(os.path.normpath, build_files)) + if parallel: + LoadTargetBuildFilesParallel(build_files, data, aux_data, + variables, includes, depth, check, + generator_input_info) + else: + for build_file in build_files: + try: + LoadTargetBuildFile(build_file, data, aux_data, + variables, includes, depth, check, True) + except Exception, e: + gyp.common.ExceptionAppend(e, 'while trying to load %s' % build_file) + raise + + # Build a dict to access each target's subdict by qualified name. + targets = BuildTargetsDict(data) + + # Fully qualify all dependency links. + QualifyDependencies(targets) + + # Remove self-dependencies from targets that have 'prune_self_dependencies' + # set to 1. + RemoveSelfDependencies(targets) + + # Expand dependencies specified as build_file:*. + ExpandWildcardDependencies(targets, data) + + # Remove all dependencies marked as 'link_dependency' from the targets of + # type 'none'. + RemoveLinkDependenciesFromNoneTargets(targets) + + # Apply exclude (!) and regex (/) list filters only for dependency_sections. + for target_name, target_dict in targets.iteritems(): + tmp_dict = {} + for key_base in dependency_sections: + for op in ('', '!', '/'): + key = key_base + op + if key in target_dict: + tmp_dict[key] = target_dict[key] + del target_dict[key] + ProcessListFiltersInDict(target_name, tmp_dict) + # Write the results back to |target_dict|. + for key in tmp_dict: + target_dict[key] = tmp_dict[key] + + # Make sure every dependency appears at most once. + RemoveDuplicateDependencies(targets) + + if circular_check: + # Make sure that any targets in a.gyp don't contain dependencies in other + # .gyp files that further depend on a.gyp. + VerifyNoGYPFileCircularDependencies(targets) + + [dependency_nodes, flat_list] = BuildDependencyList(targets) + + if root_targets: + # Remove, from |targets| and |flat_list|, the targets that are not deep + # dependencies of the targets specified in |root_targets|. + targets, flat_list = PruneUnwantedTargets( + targets, flat_list, dependency_nodes, root_targets, data) + + # Check that no two targets in the same directory have the same name. + VerifyNoCollidingTargets(flat_list) + + # Handle dependent settings of various types. + for settings_type in ['all_dependent_settings', + 'direct_dependent_settings', + 'link_settings']: + DoDependentSettings(settings_type, flat_list, targets, dependency_nodes) + + # Take out the dependent settings now that they've been published to all + # of the targets that require them. + for target in flat_list: + if settings_type in targets[target]: + del targets[target][settings_type] + + # Make sure static libraries don't declare dependencies on other static + # libraries, but that linkables depend on all unlinked static libraries + # that they need so that their link steps will be correct. + gii = generator_input_info + if gii['generator_wants_static_library_dependencies_adjusted']: + AdjustStaticLibraryDependencies(flat_list, targets, dependency_nodes, + gii['generator_wants_sorted_dependencies']) + + # Apply "post"/"late"/"target" variable expansions and condition evaluations. + for target in flat_list: + target_dict = targets[target] + build_file = gyp.common.BuildFile(target) + ProcessVariablesAndConditionsInDict( + target_dict, PHASE_LATE, variables, build_file) + + # Move everything that can go into a "configurations" section into one. + for target in flat_list: + target_dict = targets[target] + SetUpConfigurations(target, target_dict) + + # Apply exclude (!) and regex (/) list filters. + for target in flat_list: + target_dict = targets[target] + ProcessListFiltersInDict(target, target_dict) + + # Apply "latelate" variable expansions and condition evaluations. + for target in flat_list: + target_dict = targets[target] + build_file = gyp.common.BuildFile(target) + ProcessVariablesAndConditionsInDict( + target_dict, PHASE_LATELATE, variables, build_file) + + # Make sure that the rules make sense, and build up rule_sources lists as + # needed. Not all generators will need to use the rule_sources lists, but + # some may, and it seems best to build the list in a common spot. + # Also validate actions and run_as elements in targets. + for target in flat_list: + target_dict = targets[target] + build_file = gyp.common.BuildFile(target) + ValidateTargetType(target, target_dict) + # TODO(thakis): Get vpx_scale/arm/scalesystemdependent.c to be renamed to + # scalesystemdependent_arm_additions.c or similar. + if 'arm' not in variables.get('target_arch', ''): + ValidateSourcesInTarget(target, target_dict, build_file) + ValidateRulesInTarget(target, target_dict, extra_sources_for_rules) + ValidateRunAsInTarget(target, target_dict, build_file) + ValidateActionsInTarget(target, target_dict, build_file) + + # Generators might not expect ints. Turn them into strs. + TurnIntIntoStrInDict(data) + + # TODO(mark): Return |data| for now because the generator needs a list of + # build files that came in. In the future, maybe it should just accept + # a list, and not the whole data dict. + return [flat_list, targets, data] diff --git a/deps/gyp/pylib/gyp/input_test.py b/deps/gyp/pylib/gyp/input_test.py new file mode 100755 index 000000000..cdbf6b2fa --- /dev/null +++ b/deps/gyp/pylib/gyp/input_test.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python + +# Copyright 2013 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Unit tests for the input.py file.""" + +import gyp.input +import unittest +import sys + + +class TestFindCycles(unittest.TestCase): + def setUp(self): + self.nodes = {} + for x in ('a', 'b', 'c', 'd', 'e'): + self.nodes[x] = gyp.input.DependencyGraphNode(x) + + def _create_dependency(self, dependent, dependency): + dependent.dependencies.append(dependency) + dependency.dependents.append(dependent) + + def test_no_cycle_empty_graph(self): + for label, node in self.nodes.iteritems(): + self.assertEquals([], node.FindCycles()) + + def test_no_cycle_line(self): + self._create_dependency(self.nodes['a'], self.nodes['b']) + self._create_dependency(self.nodes['b'], self.nodes['c']) + self._create_dependency(self.nodes['c'], self.nodes['d']) + + for label, node in self.nodes.iteritems(): + self.assertEquals([], node.FindCycles()) + + def test_no_cycle_dag(self): + self._create_dependency(self.nodes['a'], self.nodes['b']) + self._create_dependency(self.nodes['a'], self.nodes['c']) + self._create_dependency(self.nodes['b'], self.nodes['c']) + + for label, node in self.nodes.iteritems(): + self.assertEquals([], node.FindCycles()) + + def test_cycle_self_reference(self): + self._create_dependency(self.nodes['a'], self.nodes['a']) + + self.assertEquals([(self.nodes['a'], self.nodes['a'])], + self.nodes['a'].FindCycles()) + + def test_cycle_two_nodes(self): + self._create_dependency(self.nodes['a'], self.nodes['b']) + self._create_dependency(self.nodes['b'], self.nodes['a']) + + self.assertEquals([(self.nodes['a'], self.nodes['b'], self.nodes['a'])], + self.nodes['a'].FindCycles()) + self.assertEquals([(self.nodes['b'], self.nodes['a'], self.nodes['b'])], + self.nodes['b'].FindCycles()) + + def test_two_cycles(self): + self._create_dependency(self.nodes['a'], self.nodes['b']) + self._create_dependency(self.nodes['b'], self.nodes['a']) + + self._create_dependency(self.nodes['b'], self.nodes['c']) + self._create_dependency(self.nodes['c'], self.nodes['b']) + + cycles = self.nodes['a'].FindCycles() + self.assertTrue( + (self.nodes['a'], self.nodes['b'], self.nodes['a']) in cycles) + self.assertTrue( + (self.nodes['b'], self.nodes['c'], self.nodes['b']) in cycles) + self.assertEquals(2, len(cycles)) + + def test_big_cycle(self): + self._create_dependency(self.nodes['a'], self.nodes['b']) + self._create_dependency(self.nodes['b'], self.nodes['c']) + self._create_dependency(self.nodes['c'], self.nodes['d']) + self._create_dependency(self.nodes['d'], self.nodes['e']) + self._create_dependency(self.nodes['e'], self.nodes['a']) + + self.assertEquals([(self.nodes['a'], + self.nodes['b'], + self.nodes['c'], + self.nodes['d'], + self.nodes['e'], + self.nodes['a'])], + self.nodes['a'].FindCycles()) + + +if __name__ == '__main__': + unittest.main() diff --git a/deps/gyp/pylib/gyp/mac_tool.py b/deps/gyp/pylib/gyp/mac_tool.py new file mode 100755 index 000000000..821e291e9 --- /dev/null +++ b/deps/gyp/pylib/gyp/mac_tool.py @@ -0,0 +1,514 @@ +#!/usr/bin/env python +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Utility functions to perform Xcode-style build steps. + +These functions are executed via gyp-mac-tool when using the Makefile generator. +""" + +import fcntl +import fnmatch +import glob +import json +import os +import plistlib +import re +import shutil +import string +import subprocess +import sys +import tempfile + + +def main(args): + executor = MacTool() + exit_code = executor.Dispatch(args) + if exit_code is not None: + sys.exit(exit_code) + + +class MacTool(object): + """This class performs all the Mac tooling steps. The methods can either be + executed directly, or dispatched from an argument list.""" + + def Dispatch(self, args): + """Dispatches a string command to a method.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + method = "Exec%s" % self._CommandifyName(args[0]) + return getattr(self, method)(*args[1:]) + + def _CommandifyName(self, name_string): + """Transforms a tool name like copy-info-plist to CopyInfoPlist""" + return name_string.title().replace('-', '') + + def ExecCopyBundleResource(self, source, dest): + """Copies a resource file to the bundle/Resources directory, performing any + necessary compilation on each resource.""" + extension = os.path.splitext(source)[1].lower() + if os.path.isdir(source): + # Copy tree. + # TODO(thakis): This copies file attributes like mtime, while the + # single-file branch below doesn't. This should probably be changed to + # be consistent with the single-file branch. + if os.path.exists(dest): + shutil.rmtree(dest) + shutil.copytree(source, dest) + elif extension == '.xib': + return self._CopyXIBFile(source, dest) + elif extension == '.storyboard': + return self._CopyXIBFile(source, dest) + elif extension == '.strings': + self._CopyStringsFile(source, dest) + else: + shutil.copy(source, dest) + + def _CopyXIBFile(self, source, dest): + """Compiles a XIB file with ibtool into a binary plist in the bundle.""" + + # ibtool sometimes crashes with relative paths. See crbug.com/314728. + base = os.path.dirname(os.path.realpath(__file__)) + if os.path.relpath(source): + source = os.path.join(base, source) + if os.path.relpath(dest): + dest = os.path.join(base, dest) + + args = ['xcrun', 'ibtool', '--errors', '--warnings', '--notices', + '--output-format', 'human-readable-text', '--compile', dest, source] + ibtool_section_re = re.compile(r'/\*.*\*/') + ibtool_re = re.compile(r'.*note:.*is clipping its content') + ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE) + current_section_header = None + for line in ibtoolout.stdout: + if ibtool_section_re.match(line): + current_section_header = line + elif not ibtool_re.match(line): + if current_section_header: + sys.stdout.write(current_section_header) + current_section_header = None + sys.stdout.write(line) + return ibtoolout.returncode + + def _CopyStringsFile(self, source, dest): + """Copies a .strings file using iconv to reconvert the input into UTF-16.""" + input_code = self._DetectInputEncoding(source) or "UTF-8" + + # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call + # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints + # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing + # semicolon in dictionary. + # on invalid files. Do the same kind of validation. + import CoreFoundation + s = open(source, 'rb').read() + d = CoreFoundation.CFDataCreate(None, s, len(s)) + _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None) + if error: + return + + fp = open(dest, 'wb') + fp.write(s.decode(input_code).encode('UTF-16')) + fp.close() + + def _DetectInputEncoding(self, file_name): + """Reads the first few bytes from file_name and tries to guess the text + encoding. Returns None as a guess if it can't detect it.""" + fp = open(file_name, 'rb') + try: + header = fp.read(3) + except e: + fp.close() + return None + fp.close() + if header.startswith("\xFE\xFF"): + return "UTF-16" + elif header.startswith("\xFF\xFE"): + return "UTF-16" + elif header.startswith("\xEF\xBB\xBF"): + return "UTF-8" + else: + return None + + def ExecCopyInfoPlist(self, source, dest, *keys): + """Copies the |source| Info.plist to the destination directory |dest|.""" + # Read the source Info.plist into memory. + fd = open(source, 'r') + lines = fd.read() + fd.close() + + # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild). + plist = plistlib.readPlistFromString(lines) + if keys: + plist = dict(plist.items() + json.loads(keys[0]).items()) + lines = plistlib.writePlistToString(plist) + + # Go through all the environment variables and replace them as variables in + # the file. + IDENT_RE = re.compile('[/\s]') + for key in os.environ: + if key.startswith('_'): + continue + evar = '${%s}' % key + evalue = os.environ[key] + lines = string.replace(lines, evar, evalue) + + # Xcode supports various suffices on environment variables, which are + # all undocumented. :rfc1034identifier is used in the standard project + # template these days, and :identifier was used earlier. They are used to + # convert non-url characters into things that look like valid urls -- + # except that the replacement character for :identifier, '_' isn't valid + # in a URL either -- oops, hence :rfc1034identifier was born. + evar = '${%s:identifier}' % key + evalue = IDENT_RE.sub('_', os.environ[key]) + lines = string.replace(lines, evar, evalue) + + evar = '${%s:rfc1034identifier}' % key + evalue = IDENT_RE.sub('-', os.environ[key]) + lines = string.replace(lines, evar, evalue) + + # Remove any keys with values that haven't been replaced. + lines = lines.split('\n') + for i in range(len(lines)): + if lines[i].strip().startswith("${"): + lines[i] = None + lines[i - 1] = None + lines = '\n'.join(filter(lambda x: x is not None, lines)) + + # Write out the file with variables replaced. + fd = open(dest, 'w') + fd.write(lines) + fd.close() + + # Now write out PkgInfo file now that the Info.plist file has been + # "compiled". + self._WritePkgInfo(dest) + + def _WritePkgInfo(self, info_plist): + """This writes the PkgInfo file from the data stored in Info.plist.""" + plist = plistlib.readPlist(info_plist) + if not plist: + return + + # Only create PkgInfo for executable types. + package_type = plist['CFBundlePackageType'] + if package_type != 'APPL': + return + + # The format of PkgInfo is eight characters, representing the bundle type + # and bundle signature, each four characters. If that is missing, four + # '?' characters are used instead. + signature_code = plist.get('CFBundleSignature', '????') + if len(signature_code) != 4: # Wrong length resets everything, too. + signature_code = '?' * 4 + + dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo') + fp = open(dest, 'w') + fp.write('%s%s' % (package_type, signature_code)) + fp.close() + + def ExecFlock(self, lockfile, *cmd_list): + """Emulates the most basic behavior of Linux's flock(1).""" + # Rely on exception handling to report errors. + fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666) + fcntl.flock(fd, fcntl.LOCK_EX) + return subprocess.call(cmd_list) + + def ExecFilterLibtool(self, *cmd_list): + """Calls libtool and filters out '/path/to/libtool: file: foo.o has no + symbols'.""" + libtool_re = re.compile(r'^.*libtool: file: .* has no symbols$') + libtool_re5 = re.compile( + r'^.*libtool: warning for library: ' + + r'.* the table of contents is empty ' + + r'\(no object file members in the library define global symbols\)$') + libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE) + _, err = libtoolout.communicate() + for line in err.splitlines(): + if not libtool_re.match(line) and not libtool_re5.match(line): + print >>sys.stderr, line + return libtoolout.returncode + + def ExecPackageFramework(self, framework, version): + """Takes a path to Something.framework and the Current version of that and + sets up all the symlinks.""" + # Find the name of the binary based on the part before the ".framework". + binary = os.path.basename(framework).split('.')[0] + + CURRENT = 'Current' + RESOURCES = 'Resources' + VERSIONS = 'Versions' + + if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)): + # Binary-less frameworks don't seem to contain symlinks (see e.g. + # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle). + return + + # Move into the framework directory to set the symlinks correctly. + pwd = os.getcwd() + os.chdir(framework) + + # Set up the Current version. + self._Relink(version, os.path.join(VERSIONS, CURRENT)) + + # Set up the root symlinks. + self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary) + self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES) + + # Back to where we were before! + os.chdir(pwd) + + def _Relink(self, dest, link): + """Creates a symlink to |dest| named |link|. If |link| already exists, + it is overwritten.""" + if os.path.lexists(link): + os.remove(link) + os.symlink(dest, link) + + def ExecCodeSignBundle(self, key, resource_rules, entitlements, provisioning): + """Code sign a bundle. + + This function tries to code sign an iOS bundle, following the same + algorithm as Xcode: + 1. copy ResourceRules.plist from the user or the SDK into the bundle, + 2. pick the provisioning profile that best match the bundle identifier, + and copy it into the bundle as embedded.mobileprovision, + 3. copy Entitlements.plist from user or SDK next to the bundle, + 4. code sign the bundle. + """ + resource_rules_path = self._InstallResourceRules(resource_rules) + substitutions, overrides = self._InstallProvisioningProfile( + provisioning, self._GetCFBundleIdentifier()) + entitlements_path = self._InstallEntitlements( + entitlements, substitutions, overrides) + subprocess.check_call([ + 'codesign', '--force', '--sign', key, '--resource-rules', + resource_rules_path, '--entitlements', entitlements_path, + os.path.join( + os.environ['TARGET_BUILD_DIR'], + os.environ['FULL_PRODUCT_NAME'])]) + + def _InstallResourceRules(self, resource_rules): + """Installs ResourceRules.plist from user or SDK into the bundle. + + Args: + resource_rules: string, optional, path to the ResourceRules.plist file + to use, default to "${SDKROOT}/ResourceRules.plist" + + Returns: + Path to the copy of ResourceRules.plist into the bundle. + """ + source_path = resource_rules + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['CONTENTS_FOLDER_PATH'], + 'ResourceRules.plist') + if not source_path: + source_path = os.path.join( + os.environ['SDKROOT'], 'ResourceRules.plist') + shutil.copy2(source_path, target_path) + return target_path + + def _InstallProvisioningProfile(self, profile, bundle_identifier): + """Installs embedded.mobileprovision into the bundle. + + Args: + profile: string, optional, short name of the .mobileprovision file + to use, if empty or the file is missing, the best file installed + will be used + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + + Returns: + A tuple containing two dictionary: variables substitutions and values + to overrides when generating the entitlements file. + """ + source_path, provisioning_data, team_id = self._FindProvisioningProfile( + profile, bundle_identifier) + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['CONTENTS_FOLDER_PATH'], + 'embedded.mobileprovision') + shutil.copy2(source_path, target_path) + substitutions = self._GetSubstitutions(bundle_identifier, team_id + '.') + return substitutions, provisioning_data['Entitlements'] + + def _FindProvisioningProfile(self, profile, bundle_identifier): + """Finds the .mobileprovision file to use for signing the bundle. + + Checks all the installed provisioning profiles (or if the user specified + the PROVISIONING_PROFILE variable, only consult it) and select the most + specific that correspond to the bundle identifier. + + Args: + profile: string, optional, short name of the .mobileprovision file + to use, if empty or the file is missing, the best file installed + will be used + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + + Returns: + A tuple of the path to the selected provisioning profile, the data of + the embedded plist in the provisioning profile and the team identifier + to use for code signing. + + Raises: + SystemExit: if no .mobileprovision can be used to sign the bundle. + """ + profiles_dir = os.path.join( + os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles') + if not os.path.isdir(profiles_dir): + print >>sys.stderr, ( + 'cannot find mobile provisioning for %s' % bundle_identifier) + sys.exit(1) + provisioning_profiles = None + if profile: + profile_path = os.path.join(profiles_dir, profile + '.mobileprovision') + if os.path.exists(profile_path): + provisioning_profiles = [profile_path] + if not provisioning_profiles: + provisioning_profiles = glob.glob( + os.path.join(profiles_dir, '*.mobileprovision')) + valid_provisioning_profiles = {} + for profile_path in provisioning_profiles: + profile_data = self._LoadProvisioningProfile(profile_path) + app_id_pattern = profile_data.get( + 'Entitlements', {}).get('application-identifier', '') + for team_identifier in profile_data.get('TeamIdentifier', []): + app_id = '%s.%s' % (team_identifier, bundle_identifier) + if fnmatch.fnmatch(app_id, app_id_pattern): + valid_provisioning_profiles[app_id_pattern] = ( + profile_path, profile_data, team_identifier) + if not valid_provisioning_profiles: + print >>sys.stderr, ( + 'cannot find mobile provisioning for %s' % bundle_identifier) + sys.exit(1) + # If the user has multiple provisioning profiles installed that can be + # used for ${bundle_identifier}, pick the most specific one (ie. the + # provisioning profile whose pattern is the longest). + selected_key = max(valid_provisioning_profiles, key=lambda v: len(v)) + return valid_provisioning_profiles[selected_key] + + def _LoadProvisioningProfile(self, profile_path): + """Extracts the plist embedded in a provisioning profile. + + Args: + profile_path: string, path to the .mobileprovision file + + Returns: + Content of the plist embedded in the provisioning profile as a dictionary. + """ + with tempfile.NamedTemporaryFile() as temp: + subprocess.check_call([ + 'security', 'cms', '-D', '-i', profile_path, '-o', temp.name]) + return self._LoadPlistMaybeBinary(temp.name) + + def _LoadPlistMaybeBinary(self, plist_path): + """Loads into a memory a plist possibly encoded in binary format. + + This is a wrapper around plistlib.readPlist that tries to convert the + plist to the XML format if it can't be parsed (assuming that it is in + the binary format). + + Args: + plist_path: string, path to a plist file, in XML or binary format + + Returns: + Content of the plist as a dictionary. + """ + try: + # First, try to read the file using plistlib that only supports XML, + # and if an exception is raised, convert a temporary copy to XML and + # load that copy. + return plistlib.readPlist(plist_path) + except: + pass + with tempfile.NamedTemporaryFile() as temp: + shutil.copy2(plist_path, temp.name) + subprocess.check_call(['plutil', '-convert', 'xml1', temp.name]) + return plistlib.readPlist(temp.name) + + def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix): + """Constructs a dictionary of variable substitutions for Entitlements.plist. + + Args: + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + app_identifier_prefix: string, value for AppIdentifierPrefix + + Returns: + Dictionary of substitutions to apply when generating Entitlements.plist. + """ + return { + 'CFBundleIdentifier': bundle_identifier, + 'AppIdentifierPrefix': app_identifier_prefix, + } + + def _GetCFBundleIdentifier(self): + """Extracts CFBundleIdentifier value from Info.plist in the bundle. + + Returns: + Value of CFBundleIdentifier in the Info.plist located in the bundle. + """ + info_plist_path = os.path.join( + os.environ['TARGET_BUILD_DIR'], + os.environ['INFOPLIST_PATH']) + info_plist_data = self._LoadPlistMaybeBinary(info_plist_path) + return info_plist_data['CFBundleIdentifier'] + + def _InstallEntitlements(self, entitlements, substitutions, overrides): + """Generates and install the ${BundleName}.xcent entitlements file. + + Expands variables "$(variable)" pattern in the source entitlements file, + add extra entitlements defined in the .mobileprovision file and the copy + the generated plist to "${BundlePath}.xcent". + + Args: + entitlements: string, optional, path to the Entitlements.plist template + to use, defaults to "${SDKROOT}/Entitlements.plist" + substitutions: dictionary, variable substitutions + overrides: dictionary, values to add to the entitlements + + Returns: + Path to the generated entitlements file. + """ + source_path = entitlements + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['PRODUCT_NAME'] + '.xcent') + if not source_path: + source_path = os.path.join( + os.environ['SDKROOT'], + 'Entitlements.plist') + shutil.copy2(source_path, target_path) + data = self._LoadPlistMaybeBinary(target_path) + data = self._ExpandVariables(data, substitutions) + if overrides: + for key in overrides: + if key not in data: + data[key] = overrides[key] + plistlib.writePlist(data, target_path) + return target_path + + def _ExpandVariables(self, data, substitutions): + """Expands variables "$(variable)" in data. + + Args: + data: object, can be either string, list or dictionary + substitutions: dictionary, variable substitutions to perform + + Returns: + Copy of data where each references to "$(variable)" has been replaced + by the corresponding value found in substitutions, or left intact if + the key was not found. + """ + if isinstance(data, str): + for key, value in substitutions.iteritems(): + data = data.replace('$(%s)' % key, value) + return data + if isinstance(data, list): + return [self._ExpandVariables(v, substitutions) for v in data] + if isinstance(data, dict): + return {k: self._ExpandVariables(data[k], substitutions) for k in data} + return data + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/deps/gyp/pylib/gyp/msvs_emulation.py b/deps/gyp/pylib/gyp/msvs_emulation.py new file mode 100644 index 000000000..63593a424 --- /dev/null +++ b/deps/gyp/pylib/gyp/msvs_emulation.py @@ -0,0 +1,978 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +This module helps emulate Visual Studio 2008 behavior on top of other +build systems, primarily ninja. +""" + +import os +import re +import subprocess +import sys + +import gyp.MSVSVersion + +windows_quoter_regex = re.compile(r'(\\*)"') + +def QuoteForRspFile(arg): + """Quote a command line argument so that it appears as one argument when + processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for + Windows programs).""" + # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment + # threads. This is actually the quoting rules for CommandLineToArgvW, not + # for the shell, because the shell doesn't do anything in Windows. This + # works more or less because most programs (including the compiler, etc.) + # use that function to handle command line arguments. + + # For a literal quote, CommandLineToArgvW requires 2n+1 backslashes + # preceding it, and results in n backslashes + the quote. So we substitute + # in 2* what we match, +1 more, plus the quote. + arg = windows_quoter_regex.sub(lambda mo: 2 * mo.group(1) + '\\"', arg) + + # %'s also need to be doubled otherwise they're interpreted as batch + # positional arguments. Also make sure to escape the % so that they're + # passed literally through escaping so they can be singled to just the + # original %. Otherwise, trying to pass the literal representation that + # looks like an environment variable to the shell (e.g. %PATH%) would fail. + arg = arg.replace('%', '%%') + + # These commands are used in rsp files, so no escaping for the shell (via ^) + # is necessary. + + # Finally, wrap the whole thing in quotes so that the above quote rule + # applies and whitespace isn't a word break. + return '"' + arg + '"' + + +def EncodeRspFileList(args): + """Process a list of arguments using QuoteCmdExeArgument.""" + # Note that the first argument is assumed to be the command. Don't add + # quotes around it because then built-ins like 'echo', etc. won't work. + # Take care to normpath only the path in the case of 'call ../x.bat' because + # otherwise the whole thing is incorrectly interpreted as a path and not + # normalized correctly. + if not args: return '' + if args[0].startswith('call '): + call, program = args[0].split(' ', 1) + program = call + ' ' + os.path.normpath(program) + else: + program = os.path.normpath(args[0]) + return program + ' ' + ' '.join(QuoteForRspFile(arg) for arg in args[1:]) + + +def _GenericRetrieve(root, default, path): + """Given a list of dictionary keys |path| and a tree of dicts |root|, find + value at path, or return |default| if any of the path doesn't exist.""" + if not root: + return default + if not path: + return root + return _GenericRetrieve(root.get(path[0]), default, path[1:]) + + +def _AddPrefix(element, prefix): + """Add |prefix| to |element| or each subelement if element is iterable.""" + if element is None: + return element + # Note, not Iterable because we don't want to handle strings like that. + if isinstance(element, list) or isinstance(element, tuple): + return [prefix + e for e in element] + else: + return prefix + element + + +def _DoRemapping(element, map): + """If |element| then remap it through |map|. If |element| is iterable then + each item will be remapped. Any elements not found will be removed.""" + if map is not None and element is not None: + if not callable(map): + map = map.get # Assume it's a dict, otherwise a callable to do the remap. + if isinstance(element, list) or isinstance(element, tuple): + element = filter(None, [map(elem) for elem in element]) + else: + element = map(element) + return element + + +def _AppendOrReturn(append, element): + """If |append| is None, simply return |element|. If |append| is not None, + then add |element| to it, adding each item in |element| if it's a list or + tuple.""" + if append is not None and element is not None: + if isinstance(element, list) or isinstance(element, tuple): + append.extend(element) + else: + append.append(element) + else: + return element + + +def _FindDirectXInstallation(): + """Try to find an installation location for the DirectX SDK. Check for the + standard environment variable, and if that doesn't exist, try to find + via the registry. May return None if not found in either location.""" + # Return previously calculated value, if there is one + if hasattr(_FindDirectXInstallation, 'dxsdk_dir'): + return _FindDirectXInstallation.dxsdk_dir + + dxsdk_dir = os.environ.get('DXSDK_DIR') + if not dxsdk_dir: + # Setup params to pass to and attempt to launch reg.exe. + cmd = ['reg.exe', 'query', r'HKLM\Software\Microsoft\DirectX', '/s'] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + for line in p.communicate()[0].splitlines(): + if 'InstallPath' in line: + dxsdk_dir = line.split(' ')[3] + "\\" + + # Cache return value + _FindDirectXInstallation.dxsdk_dir = dxsdk_dir + return dxsdk_dir + + +class MsvsSettings(object): + """A class that understands the gyp 'msvs_...' values (especially the + msvs_settings field). They largely correpond to the VS2008 IDE DOM. This + class helps map those settings to command line options.""" + + def __init__(self, spec, generator_flags): + self.spec = spec + self.vs_version = GetVSVersion(generator_flags) + self.dxsdk_dir = _FindDirectXInstallation() + + # Try to find an installation location for the Windows DDK by checking + # the WDK_DIR environment variable, may be None. + self.wdk_dir = os.environ.get('WDK_DIR') + + supported_fields = [ + ('msvs_configuration_attributes', dict), + ('msvs_settings', dict), + ('msvs_system_include_dirs', list), + ('msvs_disabled_warnings', list), + ('msvs_precompiled_header', str), + ('msvs_precompiled_source', str), + ('msvs_configuration_platform', str), + ('msvs_target_platform', str), + ] + configs = spec['configurations'] + for field, default in supported_fields: + setattr(self, field, {}) + for configname, config in configs.iteritems(): + getattr(self, field)[configname] = config.get(field, default()) + + self.msvs_cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.']) + + unsupported_fields = [ + 'msvs_prebuild', + 'msvs_postbuild', + ] + unsupported = [] + for field in unsupported_fields: + for config in configs.values(): + if field in config: + unsupported += ["%s not supported (target %s)." % + (field, spec['target_name'])] + if unsupported: + raise Exception('\n'.join(unsupported)) + + def GetVSMacroEnv(self, base_to_build=None, config=None): + """Get a dict of variables mapping internal VS macro names to their gyp + equivalents.""" + target_platform = 'Win32' if self.GetArch(config) == 'x86' else 'x64' + target_name = self.spec.get('product_prefix', '') + \ + self.spec.get('product_name', self.spec['target_name']) + target_dir = base_to_build + '\\' if base_to_build else '' + replacements = { + '$(OutDir)\\': target_dir, + '$(TargetDir)\\': target_dir, + '$(IntDir)': '$!INTERMEDIATE_DIR', + '$(InputPath)': '${source}', + '$(InputName)': '${root}', + '$(ProjectName)': self.spec['target_name'], + '$(TargetName)': target_name, + '$(PlatformName)': target_platform, + '$(ProjectDir)\\': '', + } + # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when + # Visual Studio is actually installed. + if self.vs_version.Path(): + replacements['$(VSInstallDir)'] = self.vs_version.Path() + replacements['$(VCInstallDir)'] = os.path.join(self.vs_version.Path(), + 'VC') + '\\' + # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be + # set. This happens when the SDK is sync'd via src-internal, rather than + # by typical end-user installation of the SDK. If it's not set, we don't + # want to leave the unexpanded variable in the path, so simply strip it. + replacements['$(DXSDK_DIR)'] = self.dxsdk_dir if self.dxsdk_dir else '' + replacements['$(WDK_DIR)'] = self.wdk_dir if self.wdk_dir else '' + return replacements + + def ConvertVSMacros(self, s, base_to_build=None, config=None): + """Convert from VS macro names to something equivalent.""" + env = self.GetVSMacroEnv(base_to_build, config=config) + return ExpandMacros(s, env) + + def AdjustLibraries(self, libraries): + """Strip -l from library if it's specified with that.""" + libs = [lib[2:] if lib.startswith('-l') else lib for lib in libraries] + return [lib + '.lib' if not lib.endswith('.lib') else lib for lib in libs] + + def _GetAndMunge(self, field, path, default, prefix, append, map): + """Retrieve a value from |field| at |path| or return |default|. If + |append| is specified, and the item is found, it will be appended to that + object instead of returned. If |map| is specified, results will be + remapped through |map| before being returned or appended.""" + result = _GenericRetrieve(field, default, path) + result = _DoRemapping(result, map) + result = _AddPrefix(result, prefix) + return _AppendOrReturn(append, result) + + class _GetWrapper(object): + def __init__(self, parent, field, base_path, append=None): + self.parent = parent + self.field = field + self.base_path = [base_path] + self.append = append + def __call__(self, name, map=None, prefix='', default=None): + return self.parent._GetAndMunge(self.field, self.base_path + [name], + default=default, prefix=prefix, append=self.append, map=map) + + def GetArch(self, config): + """Get architecture based on msvs_configuration_platform and + msvs_target_platform. Returns either 'x86' or 'x64'.""" + configuration_platform = self.msvs_configuration_platform.get(config, '') + platform = self.msvs_target_platform.get(config, '') + if not platform: # If no specific override, use the configuration's. + platform = configuration_platform + # Map from platform to architecture. + return {'Win32': 'x86', 'x64': 'x64'}.get(platform, 'x86') + + def _TargetConfig(self, config): + """Returns the target-specific configuration.""" + # There's two levels of architecture/platform specification in VS. The + # first level is globally for the configuration (this is what we consider + # "the" config at the gyp level, which will be something like 'Debug' or + # 'Release_x64'), and a second target-specific configuration, which is an + # override for the global one. |config| is remapped here to take into + # account the local target-specific overrides to the global configuration. + arch = self.GetArch(config) + if arch == 'x64' and not config.endswith('_x64'): + config += '_x64' + if arch == 'x86' and config.endswith('_x64'): + config = config.rsplit('_', 1)[0] + return config + + def _Setting(self, path, config, + default=None, prefix='', append=None, map=None): + """_GetAndMunge for msvs_settings.""" + return self._GetAndMunge( + self.msvs_settings[config], path, default, prefix, append, map) + + def _ConfigAttrib(self, path, config, + default=None, prefix='', append=None, map=None): + """_GetAndMunge for msvs_configuration_attributes.""" + return self._GetAndMunge( + self.msvs_configuration_attributes[config], + path, default, prefix, append, map) + + def AdjustIncludeDirs(self, include_dirs, config): + """Updates include_dirs to expand VS specific paths, and adds the system + include dirs used for platform SDK and similar.""" + config = self._TargetConfig(config) + includes = include_dirs + self.msvs_system_include_dirs[config] + includes.extend(self._Setting( + ('VCCLCompilerTool', 'AdditionalIncludeDirectories'), config, default=[])) + return [self.ConvertVSMacros(p, config=config) for p in includes] + + def GetComputedDefines(self, config): + """Returns the set of defines that are injected to the defines list based + on other VS settings.""" + config = self._TargetConfig(config) + defines = [] + if self._ConfigAttrib(['CharacterSet'], config) == '1': + defines.extend(('_UNICODE', 'UNICODE')) + if self._ConfigAttrib(['CharacterSet'], config) == '2': + defines.append('_MBCS') + defines.extend(self._Setting( + ('VCCLCompilerTool', 'PreprocessorDefinitions'), config, default=[])) + return defines + + def GetCompilerPdbName(self, config, expand_special): + """Get the pdb file name that should be used for compiler invocations, or + None if there's no explicit name specified.""" + config = self._TargetConfig(config) + pdbname = self._Setting( + ('VCCLCompilerTool', 'ProgramDataBaseFileName'), config) + if pdbname: + pdbname = expand_special(self.ConvertVSMacros(pdbname)) + return pdbname + + def GetMapFileName(self, config, expand_special): + """Gets the explicitly overriden map file name for a target or returns None + if it's not set.""" + config = self._TargetConfig(config) + map_file = self._Setting(('VCLinkerTool', 'MapFileName'), config) + if map_file: + map_file = expand_special(self.ConvertVSMacros(map_file, config=config)) + return map_file + + def GetOutputName(self, config, expand_special): + """Gets the explicitly overridden output name for a target or returns None + if it's not overridden.""" + config = self._TargetConfig(config) + type = self.spec['type'] + root = 'VCLibrarianTool' if type == 'static_library' else 'VCLinkerTool' + # TODO(scottmg): Handle OutputDirectory without OutputFile. + output_file = self._Setting((root, 'OutputFile'), config) + if output_file: + output_file = expand_special(self.ConvertVSMacros( + output_file, config=config)) + return output_file + + def GetPDBName(self, config, expand_special, default): + """Gets the explicitly overridden pdb name for a target or returns + default if it's not overridden, or if no pdb will be generated.""" + config = self._TargetConfig(config) + output_file = self._Setting(('VCLinkerTool', 'ProgramDatabaseFile'), config) + generate_debug_info = self._Setting( + ('VCLinkerTool', 'GenerateDebugInformation'), config) + if generate_debug_info: + if output_file: + return expand_special(self.ConvertVSMacros(output_file, config=config)) + else: + return default + else: + return None + + def GetAsmflags(self, config): + """Returns the flags that need to be added to ml invocations.""" + config = self._TargetConfig(config) + asmflags = [] + safeseh = self._Setting(('MASM', 'UseSafeExceptionHandlers'), config) + if safeseh == 'true': + asmflags.append('/safeseh') + return asmflags + + def GetCflags(self, config): + """Returns the flags that need to be added to .c and .cc compilations.""" + config = self._TargetConfig(config) + cflags = [] + cflags.extend(['/wd' + w for w in self.msvs_disabled_warnings[config]]) + cl = self._GetWrapper(self, self.msvs_settings[config], + 'VCCLCompilerTool', append=cflags) + cl('Optimization', + map={'0': 'd', '1': '1', '2': '2', '3': 'x'}, prefix='/O', default='2') + cl('InlineFunctionExpansion', prefix='/Ob') + cl('DisableSpecificWarnings', prefix='/wd') + cl('StringPooling', map={'true': '/GF'}) + cl('EnableFiberSafeOptimizations', map={'true': '/GT'}) + cl('OmitFramePointers', map={'false': '-', 'true': ''}, prefix='/Oy') + cl('EnableIntrinsicFunctions', map={'false': '-', 'true': ''}, prefix='/Oi') + cl('FavorSizeOrSpeed', map={'1': 't', '2': 's'}, prefix='/O') + cl('WholeProgramOptimization', map={'true': '/GL'}) + cl('WarningLevel', prefix='/W') + cl('WarnAsError', map={'true': '/WX'}) + cl('DebugInformationFormat', + map={'1': '7', '3': 'i', '4': 'I'}, prefix='/Z') + cl('RuntimeTypeInfo', map={'true': '/GR', 'false': '/GR-'}) + cl('EnableFunctionLevelLinking', map={'true': '/Gy', 'false': '/Gy-'}) + cl('MinimalRebuild', map={'true': '/Gm'}) + cl('BufferSecurityCheck', map={'true': '/GS', 'false': '/GS-'}) + cl('BasicRuntimeChecks', map={'1': 's', '2': 'u', '3': '1'}, prefix='/RTC') + cl('RuntimeLibrary', + map={'0': 'T', '1': 'Td', '2': 'D', '3': 'Dd'}, prefix='/M') + cl('ExceptionHandling', map={'1': 'sc','2': 'a'}, prefix='/EH') + cl('DefaultCharIsUnsigned', map={'true': '/J'}) + cl('TreatWChar_tAsBuiltInType', + map={'false': '-', 'true': ''}, prefix='/Zc:wchar_t') + cl('EnablePREfast', map={'true': '/analyze'}) + cl('AdditionalOptions', prefix='') + cl('EnableEnhancedInstructionSet', + map={'1': 'SSE', '2': 'SSE2', '3': 'AVX', '4': 'IA32'}, prefix='/arch:') + cflags.extend(['/FI' + f for f in self._Setting( + ('VCCLCompilerTool', 'ForcedIncludeFiles'), config, default=[])]) + if self.vs_version.short_name in ('2013', '2013e'): + # New flag required in 2013 to maintain previous PDB behavior. + cflags.append('/FS') + # ninja handles parallelism by itself, don't have the compiler do it too. + cflags = filter(lambda x: not x.startswith('/MP'), cflags) + return cflags + + def _GetPchFlags(self, config, extension): + """Get the flags to be added to the cflags for precompiled header support. + """ + config = self._TargetConfig(config) + # The PCH is only built once by a particular source file. Usage of PCH must + # only be for the same language (i.e. C vs. C++), so only include the pch + # flags when the language matches. + if self.msvs_precompiled_header[config]: + source_ext = os.path.splitext(self.msvs_precompiled_source[config])[1] + if _LanguageMatchesForPch(source_ext, extension): + pch = os.path.split(self.msvs_precompiled_header[config])[1] + return ['/Yu' + pch, '/FI' + pch, '/Fp${pchprefix}.' + pch + '.pch'] + return [] + + def GetCflagsC(self, config): + """Returns the flags that need to be added to .c compilations.""" + config = self._TargetConfig(config) + return self._GetPchFlags(config, '.c') + + def GetCflagsCC(self, config): + """Returns the flags that need to be added to .cc compilations.""" + config = self._TargetConfig(config) + return ['/TP'] + self._GetPchFlags(config, '.cc') + + def _GetAdditionalLibraryDirectories(self, root, config, gyp_to_build_path): + """Get and normalize the list of paths in AdditionalLibraryDirectories + setting.""" + config = self._TargetConfig(config) + libpaths = self._Setting((root, 'AdditionalLibraryDirectories'), + config, default=[]) + libpaths = [os.path.normpath( + gyp_to_build_path(self.ConvertVSMacros(p, config=config))) + for p in libpaths] + return ['/LIBPATH:"' + p + '"' for p in libpaths] + + def GetLibFlags(self, config, gyp_to_build_path): + """Returns the flags that need to be added to lib commands.""" + config = self._TargetConfig(config) + libflags = [] + lib = self._GetWrapper(self, self.msvs_settings[config], + 'VCLibrarianTool', append=libflags) + libflags.extend(self._GetAdditionalLibraryDirectories( + 'VCLibrarianTool', config, gyp_to_build_path)) + lib('LinkTimeCodeGeneration', map={'true': '/LTCG'}) + lib('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:') + lib('AdditionalOptions') + return libflags + + def GetDefFile(self, gyp_to_build_path): + """Returns the .def file from sources, if any. Otherwise returns None.""" + spec = self.spec + if spec['type'] in ('shared_library', 'loadable_module', 'executable'): + def_files = [s for s in spec.get('sources', []) if s.endswith('.def')] + if len(def_files) == 1: + return gyp_to_build_path(def_files[0]) + elif len(def_files) > 1: + raise Exception("Multiple .def files") + return None + + def _GetDefFileAsLdflags(self, ldflags, gyp_to_build_path): + """.def files get implicitly converted to a ModuleDefinitionFile for the + linker in the VS generator. Emulate that behaviour here.""" + def_file = self.GetDefFile(gyp_to_build_path) + if def_file: + ldflags.append('/DEF:"%s"' % def_file) + + def GetPGDName(self, config, expand_special): + """Gets the explicitly overridden pgd name for a target or returns None + if it's not overridden.""" + config = self._TargetConfig(config) + output_file = self._Setting( + ('VCLinkerTool', 'ProfileGuidedDatabase'), config) + if output_file: + output_file = expand_special(self.ConvertVSMacros( + output_file, config=config)) + return output_file + + def GetLdflags(self, config, gyp_to_build_path, expand_special, + manifest_base_name, output_name, is_executable, build_dir): + """Returns the flags that need to be added to link commands, and the + manifest files.""" + config = self._TargetConfig(config) + ldflags = [] + ld = self._GetWrapper(self, self.msvs_settings[config], + 'VCLinkerTool', append=ldflags) + self._GetDefFileAsLdflags(ldflags, gyp_to_build_path) + ld('GenerateDebugInformation', map={'true': '/DEBUG'}) + ld('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:') + ldflags.extend(self._GetAdditionalLibraryDirectories( + 'VCLinkerTool', config, gyp_to_build_path)) + ld('DelayLoadDLLs', prefix='/DELAYLOAD:') + ld('TreatLinkerWarningAsErrors', prefix='/WX', + map={'true': '', 'false': ':NO'}) + out = self.GetOutputName(config, expand_special) + if out: + ldflags.append('/OUT:' + out) + pdb = self.GetPDBName(config, expand_special, output_name + '.pdb') + if pdb: + ldflags.append('/PDB:' + pdb) + pgd = self.GetPGDName(config, expand_special) + if pgd: + ldflags.append('/PGD:' + pgd) + map_file = self.GetMapFileName(config, expand_special) + ld('GenerateMapFile', map={'true': '/MAP:' + map_file if map_file + else '/MAP'}) + ld('MapExports', map={'true': '/MAPINFO:EXPORTS'}) + ld('AdditionalOptions', prefix='') + + minimum_required_version = self._Setting( + ('VCLinkerTool', 'MinimumRequiredVersion'), config, default='') + if minimum_required_version: + minimum_required_version = ',' + minimum_required_version + ld('SubSystem', + map={'1': 'CONSOLE%s' % minimum_required_version, + '2': 'WINDOWS%s' % minimum_required_version}, + prefix='/SUBSYSTEM:') + + ld('TerminalServerAware', map={'1': ':NO', '2': ''}, prefix='/TSAWARE') + ld('LinkIncremental', map={'1': ':NO', '2': ''}, prefix='/INCREMENTAL') + ld('BaseAddress', prefix='/BASE:') + ld('FixedBaseAddress', map={'1': ':NO', '2': ''}, prefix='/FIXED') + ld('RandomizedBaseAddress', + map={'1': ':NO', '2': ''}, prefix='/DYNAMICBASE') + ld('DataExecutionPrevention', + map={'1': ':NO', '2': ''}, prefix='/NXCOMPAT') + ld('OptimizeReferences', map={'1': 'NOREF', '2': 'REF'}, prefix='/OPT:') + ld('ForceSymbolReferences', prefix='/INCLUDE:') + ld('EnableCOMDATFolding', map={'1': 'NOICF', '2': 'ICF'}, prefix='/OPT:') + ld('LinkTimeCodeGeneration', + map={'1': '', '2': ':PGINSTRUMENT', '3': ':PGOPTIMIZE', + '4': ':PGUPDATE'}, + prefix='/LTCG') + ld('IgnoreDefaultLibraryNames', prefix='/NODEFAULTLIB:') + ld('ResourceOnlyDLL', map={'true': '/NOENTRY'}) + ld('EntryPointSymbol', prefix='/ENTRY:') + ld('Profile', map={'true': '/PROFILE'}) + ld('LargeAddressAware', + map={'1': ':NO', '2': ''}, prefix='/LARGEADDRESSAWARE') + ld('ImageHasSafeExceptionHandlers', map={'true': '/SAFESEH'}) + # TODO(scottmg): This should sort of be somewhere else (not really a flag). + ld('AdditionalDependencies', prefix='') + + # If the base address is not specifically controlled, DYNAMICBASE should + # be on by default. + base_flags = filter(lambda x: 'DYNAMICBASE' in x or x == '/FIXED', + ldflags) + if not base_flags: + ldflags.append('/DYNAMICBASE') + + # If the NXCOMPAT flag has not been specified, default to on. Despite the + # documentation that says this only defaults to on when the subsystem is + # Vista or greater (which applies to the linker), the IDE defaults it on + # unless it's explicitly off. + if not filter(lambda x: 'NXCOMPAT' in x, ldflags): + ldflags.append('/NXCOMPAT') + + have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags) + manifest_flags, intermediate_manifest, manifest_files = \ + self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path, + is_executable and not have_def_file, build_dir) + ldflags.extend(manifest_flags) + return ldflags, intermediate_manifest, manifest_files + + def _GetLdManifestFlags(self, config, name, gyp_to_build_path, + allow_isolation, build_dir): + """Returns a 3-tuple: + - the set of flags that need to be added to the link to generate + a default manifest + - the intermediate manifest that the linker will generate that should be + used to assert it doesn't add anything to the merged one. + - the list of all the manifest files to be merged by the manifest tool and + included into the link.""" + generate_manifest = self._Setting(('VCLinkerTool', 'GenerateManifest'), + config, + default='true') + if generate_manifest != 'true': + # This means not only that the linker should not generate the intermediate + # manifest but also that the manifest tool should do nothing even when + # additional manifests are specified. + return ['/MANIFEST:NO'], [], [] + + output_name = name + '.intermediate.manifest' + flags = [ + '/MANIFEST', + '/ManifestFile:' + output_name, + ] + + # Instead of using the MANIFESTUAC flags, we generate a .manifest to + # include into the list of manifests. This allows us to avoid the need to + # do two passes during linking. The /MANIFEST flag and /ManifestFile are + # still used, and the intermediate manifest is used to assert that the + # final manifest we get from merging all the additional manifest files + # (plus the one we generate here) isn't modified by merging the + # intermediate into it. + + # Always NO, because we generate a manifest file that has what we want. + flags.append('/MANIFESTUAC:NO') + + config = self._TargetConfig(config) + enable_uac = self._Setting(('VCLinkerTool', 'EnableUAC'), config, + default='true') + manifest_files = [] + generated_manifest_outer = \ +"" \ +"%s" \ +"" + if enable_uac == 'true': + execution_level = self._Setting(('VCLinkerTool', 'UACExecutionLevel'), + config, default='0') + execution_level_map = { + '0': 'asInvoker', + '1': 'highestAvailable', + '2': 'requireAdministrator' + } + + ui_access = self._Setting(('VCLinkerTool', 'UACUIAccess'), config, + default='false') + + inner = ''' + + + + + + +''' % (execution_level_map[execution_level], ui_access) + else: + inner = '' + + generated_manifest_contents = generated_manifest_outer % inner + generated_name = name + '.generated.manifest' + # Need to join with the build_dir here as we're writing it during + # generation time, but we return the un-joined version because the build + # will occur in that directory. We only write the file if the contents + # have changed so that simply regenerating the project files doesn't + # cause a relink. + build_dir_generated_name = os.path.join(build_dir, generated_name) + gyp.common.EnsureDirExists(build_dir_generated_name) + f = gyp.common.WriteOnDiff(build_dir_generated_name) + f.write(generated_manifest_contents) + f.close() + manifest_files = [generated_name] + + if allow_isolation: + flags.append('/ALLOWISOLATION') + + manifest_files += self._GetAdditionalManifestFiles(config, + gyp_to_build_path) + return flags, output_name, manifest_files + + def _GetAdditionalManifestFiles(self, config, gyp_to_build_path): + """Gets additional manifest files that are added to the default one + generated by the linker.""" + files = self._Setting(('VCManifestTool', 'AdditionalManifestFiles'), config, + default=[]) + if isinstance(files, str): + files = files.split(';') + return [os.path.normpath( + gyp_to_build_path(self.ConvertVSMacros(f, config=config))) + for f in files] + + def IsUseLibraryDependencyInputs(self, config): + """Returns whether the target should be linked via Use Library Dependency + Inputs (using component .objs of a given .lib).""" + config = self._TargetConfig(config) + uldi = self._Setting(('VCLinkerTool', 'UseLibraryDependencyInputs'), config) + return uldi == 'true' + + def IsEmbedManifest(self, config): + """Returns whether manifest should be linked into binary.""" + config = self._TargetConfig(config) + embed = self._Setting(('VCManifestTool', 'EmbedManifest'), config, + default='true') + return embed == 'true' + + def IsLinkIncremental(self, config): + """Returns whether the target should be linked incrementally.""" + config = self._TargetConfig(config) + link_inc = self._Setting(('VCLinkerTool', 'LinkIncremental'), config) + return link_inc != '1' + + def GetRcflags(self, config, gyp_to_ninja_path): + """Returns the flags that need to be added to invocations of the resource + compiler.""" + config = self._TargetConfig(config) + rcflags = [] + rc = self._GetWrapper(self, self.msvs_settings[config], + 'VCResourceCompilerTool', append=rcflags) + rc('AdditionalIncludeDirectories', map=gyp_to_ninja_path, prefix='/I') + rcflags.append('/I' + gyp_to_ninja_path('.')) + rc('PreprocessorDefinitions', prefix='/d') + # /l arg must be in hex without leading '0x' + rc('Culture', prefix='/l', map=lambda x: hex(int(x))[2:]) + return rcflags + + def BuildCygwinBashCommandLine(self, args, path_to_base): + """Build a command line that runs args via cygwin bash. We assume that all + incoming paths are in Windows normpath'd form, so they need to be + converted to posix style for the part of the command line that's passed to + bash. We also have to do some Visual Studio macro emulation here because + various rules use magic VS names for things. Also note that rules that + contain ninja variables cannot be fixed here (for example ${source}), so + the outer generator needs to make sure that the paths that are written out + are in posix style, if the command line will be used here.""" + cygwin_dir = os.path.normpath( + os.path.join(path_to_base, self.msvs_cygwin_dirs[0])) + cd = ('cd %s' % path_to_base).replace('\\', '/') + args = [a.replace('\\', '/').replace('"', '\\"') for a in args] + args = ["'%s'" % a.replace("'", "'\\''") for a in args] + bash_cmd = ' '.join(args) + cmd = ( + 'call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir + + 'bash -c "%s ; %s"' % (cd, bash_cmd)) + return cmd + + def IsRuleRunUnderCygwin(self, rule): + """Determine if an action should be run under cygwin. If the variable is + unset, or set to 1 we use cygwin.""" + return int(rule.get('msvs_cygwin_shell', + self.spec.get('msvs_cygwin_shell', 1))) != 0 + + def _HasExplicitRuleForExtension(self, spec, extension): + """Determine if there's an explicit rule for a particular extension.""" + for rule in spec.get('rules', []): + if rule['extension'] == extension: + return True + return False + + def HasExplicitIdlRules(self, spec): + """Determine if there's an explicit rule for idl files. When there isn't we + need to generate implicit rules to build MIDL .idl files.""" + return self._HasExplicitRuleForExtension(spec, 'idl') + + def HasExplicitAsmRules(self, spec): + """Determine if there's an explicit rule for asm files. When there isn't we + need to generate implicit rules to assemble .asm files.""" + return self._HasExplicitRuleForExtension(spec, 'asm') + + def GetIdlBuildData(self, source, config): + """Determine the implicit outputs for an idl file. Returns output + directory, outputs, and variables and flags that are required.""" + config = self._TargetConfig(config) + midl_get = self._GetWrapper(self, self.msvs_settings[config], 'VCMIDLTool') + def midl(name, default=None): + return self.ConvertVSMacros(midl_get(name, default=default), + config=config) + tlb = midl('TypeLibraryName', default='${root}.tlb') + header = midl('HeaderFileName', default='${root}.h') + dlldata = midl('DLLDataFileName', default='dlldata.c') + iid = midl('InterfaceIdentifierFileName', default='${root}_i.c') + proxy = midl('ProxyFileName', default='${root}_p.c') + # Note that .tlb is not included in the outputs as it is not always + # generated depending on the content of the input idl file. + outdir = midl('OutputDirectory', default='') + output = [header, dlldata, iid, proxy] + variables = [('tlb', tlb), + ('h', header), + ('dlldata', dlldata), + ('iid', iid), + ('proxy', proxy)] + # TODO(scottmg): Are there configuration settings to set these flags? + target_platform = 'win32' if self.GetArch(config) == 'x86' else 'x64' + flags = ['/char', 'signed', '/env', target_platform, '/Oicf'] + return outdir, output, variables, flags + + +def _LanguageMatchesForPch(source_ext, pch_source_ext): + c_exts = ('.c',) + cc_exts = ('.cc', '.cxx', '.cpp') + return ((source_ext in c_exts and pch_source_ext in c_exts) or + (source_ext in cc_exts and pch_source_ext in cc_exts)) + + +class PrecompiledHeader(object): + """Helper to generate dependencies and build rules to handle generation of + precompiled headers. Interface matches the GCH handler in xcode_emulation.py. + """ + def __init__( + self, settings, config, gyp_to_build_path, gyp_to_unique_output, obj_ext): + self.settings = settings + self.config = config + pch_source = self.settings.msvs_precompiled_source[self.config] + self.pch_source = gyp_to_build_path(pch_source) + filename, _ = os.path.splitext(pch_source) + self.output_obj = gyp_to_unique_output(filename + obj_ext).lower() + + def _PchHeader(self): + """Get the header that will appear in an #include line for all source + files.""" + return os.path.split(self.settings.msvs_precompiled_header[self.config])[1] + + def GetObjDependencies(self, sources, objs, arch): + """Given a list of sources files and the corresponding object files, + returns a list of the pch files that should be depended upon. The + additional wrapping in the return value is for interface compatibility + with make.py on Mac, and xcode_emulation.py.""" + assert arch is None + if not self._PchHeader(): + return [] + pch_ext = os.path.splitext(self.pch_source)[1] + for source in sources: + if _LanguageMatchesForPch(os.path.splitext(source)[1], pch_ext): + return [(None, None, self.output_obj)] + return [] + + def GetPchBuildCommands(self, arch): + """Not used on Windows as there are no additional build steps required + (instead, existing steps are modified in GetFlagsModifications below).""" + return [] + + def GetFlagsModifications(self, input, output, implicit, command, + cflags_c, cflags_cc, expand_special): + """Get the modified cflags and implicit dependencies that should be used + for the pch compilation step.""" + if input == self.pch_source: + pch_output = ['/Yc' + self._PchHeader()] + if command == 'cxx': + return ([('cflags_cc', map(expand_special, cflags_cc + pch_output))], + self.output_obj, []) + elif command == 'cc': + return ([('cflags_c', map(expand_special, cflags_c + pch_output))], + self.output_obj, []) + return [], output, implicit + + +vs_version = None +def GetVSVersion(generator_flags): + global vs_version + if not vs_version: + vs_version = gyp.MSVSVersion.SelectVisualStudioVersion( + generator_flags.get('msvs_version', 'auto')) + return vs_version + +def _GetVsvarsSetupArgs(generator_flags, arch): + vs = GetVSVersion(generator_flags) + return vs.SetupScript() + +def ExpandMacros(string, expansions): + """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv + for the canonical way to retrieve a suitable dict.""" + if '$' in string: + for old, new in expansions.iteritems(): + assert '$(' not in new, new + string = string.replace(old, new) + return string + +def _ExtractImportantEnvironment(output_of_set): + """Extracts environment variables required for the toolchain to run from + a textual dump output by the cmd.exe 'set' command.""" + envvars_to_save = ( + 'goma_.*', # TODO(scottmg): This is ugly, but needed for goma. + 'include', + 'lib', + 'libpath', + 'path', + 'pathext', + 'systemroot', + 'temp', + 'tmp', + ) + env = {} + for line in output_of_set.splitlines(): + for envvar in envvars_to_save: + if re.match(envvar + '=', line.lower()): + var, setting = line.split('=', 1) + if envvar == 'path': + # Our own rules (for running gyp-win-tool) and other actions in + # Chromium rely on python being in the path. Add the path to this + # python here so that if it's not in the path when ninja is run + # later, python will still be found. + setting = os.path.dirname(sys.executable) + os.pathsep + setting + env[var.upper()] = setting + break + for required in ('SYSTEMROOT', 'TEMP', 'TMP'): + if required not in env: + raise Exception('Environment variable "%s" ' + 'required to be set to valid path' % required) + return env + +def _FormatAsEnvironmentBlock(envvar_dict): + """Format as an 'environment block' directly suitable for CreateProcess. + Briefly this is a list of key=value\0, terminated by an additional \0. See + CreateProcess documentation for more details.""" + block = '' + nul = '\0' + for key, value in envvar_dict.iteritems(): + block += key + '=' + value + nul + block += nul + return block + +def _ExtractCLPath(output_of_where): + """Gets the path to cl.exe based on the output of calling the environment + setup batch file, followed by the equivalent of `where`.""" + # Take the first line, as that's the first found in the PATH. + for line in output_of_where.strip().splitlines(): + if line.startswith('LOC:'): + return line[len('LOC:'):].strip() + +def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags, open_out): + """It's not sufficient to have the absolute path to the compiler, linker, + etc. on Windows, as those tools rely on .dlls being in the PATH. We also + need to support both x86 and x64 compilers within the same build (to support + msvs_target_platform hackery). Different architectures require a different + compiler binary, and different supporting environment variables (INCLUDE, + LIB, LIBPATH). So, we extract the environment here, wrap all invocations + of compiler tools (cl, link, lib, rc, midl, etc.) via win_tool.py which + sets up the environment, and then we do not prefix the compiler with + an absolute path, instead preferring something like "cl.exe" in the rule + which will then run whichever the environment setup has put in the path. + When the following procedure to generate environment files does not + meet your requirement (e.g. for custom toolchains), you can pass + "-G ninja_use_custom_environment_files" to the gyp to suppress file + generation and use custom environment files prepared by yourself.""" + archs = ('x86', 'x64') + if generator_flags.get('ninja_use_custom_environment_files', 0): + cl_paths = {} + for arch in archs: + cl_paths[arch] = 'cl.exe' + return cl_paths + vs = GetVSVersion(generator_flags) + cl_paths = {} + for arch in archs: + # Extract environment variables for subprocesses. + args = vs.SetupScript(arch) + args.extend(('&&', 'set')) + popen = subprocess.Popen( + args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + variables, _ = popen.communicate() + env = _ExtractImportantEnvironment(variables) + env_block = _FormatAsEnvironmentBlock(env) + f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb') + f.write(env_block) + f.close() + + # Find cl.exe location for this architecture. + args = vs.SetupScript(arch) + args.extend(('&&', + 'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i')) + popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE) + output, _ = popen.communicate() + cl_paths[arch] = _ExtractCLPath(output) + return cl_paths + +def VerifyMissingSources(sources, build_dir, generator_flags, gyp_to_ninja): + """Emulate behavior of msvs_error_on_missing_sources present in the msvs + generator: Check that all regular source files, i.e. not created at run time, + exist on disk. Missing files cause needless recompilation when building via + VS, and we want this check to match for people/bots that build using ninja, + so they're not surprised when the VS build fails.""" + if int(generator_flags.get('msvs_error_on_missing_sources', 0)): + no_specials = filter(lambda x: '$' not in x, sources) + relative = [os.path.join(build_dir, gyp_to_ninja(s)) for s in no_specials] + missing = filter(lambda x: not os.path.exists(x), relative) + if missing: + # They'll look like out\Release\..\..\stuff\things.cc, so normalize the + # path for a slightly less crazy looking output. + cleaned_up = [os.path.normpath(x) for x in missing] + raise Exception('Missing input files:\n%s' % '\n'.join(cleaned_up)) + +# Sets some values in default_variables, which are required for many +# generators, run on Windows. +def CalculateCommonVariables(default_variables, params): + generator_flags = params.get('generator_flags', {}) + + # Set a variable so conditions can be based on msvs_version. + msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags) + default_variables['MSVS_VERSION'] = msvs_version.ShortName() + + # To determine processor word size on Windows, in addition to checking + # PROCESSOR_ARCHITECTURE (which reflects the word size of the current + # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which + # contains the actual word size of the system when running thru WOW64). + if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or + '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')): + default_variables['MSVS_OS_BITS'] = 64 + else: + default_variables['MSVS_OS_BITS'] = 32 diff --git a/deps/gyp/pylib/gyp/ninja_syntax.py b/deps/gyp/pylib/gyp/ninja_syntax.py new file mode 100644 index 000000000..d2948f06c --- /dev/null +++ b/deps/gyp/pylib/gyp/ninja_syntax.py @@ -0,0 +1,160 @@ +# This file comes from +# https://github.com/martine/ninja/blob/master/misc/ninja_syntax.py +# Do not edit! Edit the upstream one instead. + +"""Python module for generating .ninja files. + +Note that this is emphatically not a required piece of Ninja; it's +just a helpful utility for build-file-generation systems that already +use Python. +""" + +import textwrap +import re + +def escape_path(word): + return word.replace('$ ','$$ ').replace(' ','$ ').replace(':', '$:') + +class Writer(object): + def __init__(self, output, width=78): + self.output = output + self.width = width + + def newline(self): + self.output.write('\n') + + def comment(self, text): + for line in textwrap.wrap(text, self.width - 2): + self.output.write('# ' + line + '\n') + + def variable(self, key, value, indent=0): + if value is None: + return + if isinstance(value, list): + value = ' '.join(filter(None, value)) # Filter out empty strings. + self._line('%s = %s' % (key, value), indent) + + def pool(self, name, depth): + self._line('pool %s' % name) + self.variable('depth', depth, indent=1) + + def rule(self, name, command, description=None, depfile=None, + generator=False, pool=None, restat=False, rspfile=None, + rspfile_content=None, deps=None): + self._line('rule %s' % name) + self.variable('command', command, indent=1) + if description: + self.variable('description', description, indent=1) + if depfile: + self.variable('depfile', depfile, indent=1) + if generator: + self.variable('generator', '1', indent=1) + if pool: + self.variable('pool', pool, indent=1) + if restat: + self.variable('restat', '1', indent=1) + if rspfile: + self.variable('rspfile', rspfile, indent=1) + if rspfile_content: + self.variable('rspfile_content', rspfile_content, indent=1) + if deps: + self.variable('deps', deps, indent=1) + + def build(self, outputs, rule, inputs=None, implicit=None, order_only=None, + variables=None): + outputs = self._as_list(outputs) + all_inputs = self._as_list(inputs)[:] + out_outputs = list(map(escape_path, outputs)) + all_inputs = list(map(escape_path, all_inputs)) + + if implicit: + implicit = map(escape_path, self._as_list(implicit)) + all_inputs.append('|') + all_inputs.extend(implicit) + if order_only: + order_only = map(escape_path, self._as_list(order_only)) + all_inputs.append('||') + all_inputs.extend(order_only) + + self._line('build %s: %s' % (' '.join(out_outputs), + ' '.join([rule] + all_inputs))) + + if variables: + if isinstance(variables, dict): + iterator = iter(variables.items()) + else: + iterator = iter(variables) + + for key, val in iterator: + self.variable(key, val, indent=1) + + return outputs + + def include(self, path): + self._line('include %s' % path) + + def subninja(self, path): + self._line('subninja %s' % path) + + def default(self, paths): + self._line('default %s' % ' '.join(self._as_list(paths))) + + def _count_dollars_before_index(self, s, i): + """Returns the number of '$' characters right in front of s[i].""" + dollar_count = 0 + dollar_index = i - 1 + while dollar_index > 0 and s[dollar_index] == '$': + dollar_count += 1 + dollar_index -= 1 + return dollar_count + + def _line(self, text, indent=0): + """Write 'text' word-wrapped at self.width characters.""" + leading_space = ' ' * indent + while len(leading_space) + len(text) > self.width: + # The text is too wide; wrap if possible. + + # Find the rightmost space that would obey our width constraint and + # that's not an escaped space. + available_space = self.width - len(leading_space) - len(' $') + space = available_space + while True: + space = text.rfind(' ', 0, space) + if space < 0 or \ + self._count_dollars_before_index(text, space) % 2 == 0: + break + + if space < 0: + # No such space; just use the first unescaped space we can find. + space = available_space - 1 + while True: + space = text.find(' ', space + 1) + if space < 0 or \ + self._count_dollars_before_index(text, space) % 2 == 0: + break + if space < 0: + # Give up on breaking. + break + + self.output.write(leading_space + text[0:space] + ' $\n') + text = text[space+1:] + + # Subsequent lines are continuations, so indent them. + leading_space = ' ' * (indent+2) + + self.output.write(leading_space + text + '\n') + + def _as_list(self, input): + if input is None: + return [] + if isinstance(input, list): + return input + return [input] + + +def escape(string): + """Escape a string such that it can be embedded into a Ninja file without + further interpretation.""" + assert '\n' not in string, 'Ninja syntax does not allow newlines' + # We only have one special metacharacter: '$'. + return string.replace('$', '$$') diff --git a/deps/gyp/pylib/gyp/ordered_dict.py b/deps/gyp/pylib/gyp/ordered_dict.py new file mode 100644 index 000000000..a1e89f919 --- /dev/null +++ b/deps/gyp/pylib/gyp/ordered_dict.py @@ -0,0 +1,289 @@ +# Unmodified from http://code.activestate.com/recipes/576693/ +# other than to add MIT license header (as specified on page, but not in code). +# Linked from Python documentation here: +# http://docs.python.org/2/library/collections.html#collections.OrderedDict +# +# This should be deleted once Py2.7 is available on all bots, see +# http://crbug.com/241769. +# +# Copyright (c) 2009 Raymond Hettinger. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. + +try: + from thread import get_ident as _get_ident +except ImportError: + from dummy_thread import get_ident as _get_ident + +try: + from _abcoll import KeysView, ValuesView, ItemsView +except ImportError: + pass + + +class OrderedDict(dict): + 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The circular doubly linked list starts and ends with a sentinel element. + # The sentinel element never gets deleted (this simplifies the algorithm). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + # Suppress 'OrderedDict.update: Method has no argument': + # pylint: disable=E0211 + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args),)) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running={}): + 'od.__repr__() <==> repr(od)' + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self)==len(other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) + diff --git a/deps/gyp/pylib/gyp/simple_copy.py b/deps/gyp/pylib/gyp/simple_copy.py new file mode 100644 index 000000000..74c98c5a7 --- /dev/null +++ b/deps/gyp/pylib/gyp/simple_copy.py @@ -0,0 +1,46 @@ +# Copyright 2014 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""A clone of the default copy.deepcopy that doesn't handle cyclic +structures or complex types except for dicts and lists. This is +because gyp copies so large structure that small copy overhead ends up +taking seconds in a project the size of Chromium.""" + +class Error(Exception): + pass + +__all__ = ["Error", "deepcopy"] + +def deepcopy(x): + """Deep copy operation on gyp objects such as strings, ints, dicts + and lists. More than twice as fast as copy.deepcopy but much less + generic.""" + + try: + return _deepcopy_dispatch[type(x)](x) + except KeyError: + raise Error('Unsupported type %s for deepcopy. Use copy.deepcopy ' + + 'or expand simple_copy support.' % type(x)) + +_deepcopy_dispatch = d = {} + +def _deepcopy_atomic(x): + return x + +for x in (type(None), int, long, float, + bool, str, unicode, type): + d[x] = _deepcopy_atomic + +def _deepcopy_list(x): + return [deepcopy(a) for a in x] +d[list] = _deepcopy_list + +def _deepcopy_dict(x): + y = {} + for key, value in x.iteritems(): + y[deepcopy(key)] = deepcopy(value) + return y +d[dict] = _deepcopy_dict + +del d diff --git a/deps/gyp/pylib/gyp/win_tool.py b/deps/gyp/pylib/gyp/win_tool.py new file mode 100755 index 000000000..44e1b0760 --- /dev/null +++ b/deps/gyp/pylib/gyp/win_tool.py @@ -0,0 +1,315 @@ +#!/usr/bin/env python + +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Utility functions for Windows builds. + +These functions are executed via gyp-win-tool when using the ninja generator. +""" + +import os +import re +import shutil +import subprocess +import stat +import string +import sys + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) + +# A regex matching an argument corresponding to the output filename passed to +# link.exe. +_LINK_EXE_OUT_ARG = re.compile('/OUT:(?P.+)$', re.IGNORECASE) + +def main(args): + executor = WinTool() + exit_code = executor.Dispatch(args) + if exit_code is not None: + sys.exit(exit_code) + + +class WinTool(object): + """This class performs all the Windows tooling steps. The methods can either + be executed directly, or dispatched from an argument list.""" + + def _UseSeparateMspdbsrv(self, env, args): + """Allows to use a unique instance of mspdbsrv.exe per linker instead of a + shared one.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + if args[0] != 'link.exe': + return + + # Use the output filename passed to the linker to generate an endpoint name + # for mspdbsrv.exe. + endpoint_name = None + for arg in args: + m = _LINK_EXE_OUT_ARG.match(arg) + if m: + endpoint_name = re.sub(r'\W+', '', + '%s_%d' % (m.group('out'), os.getpid())) + break + + if endpoint_name is None: + return + + # Adds the appropriate environment variable. This will be read by link.exe + # to know which instance of mspdbsrv.exe it should connect to (if it's + # not set then the default endpoint is used). + env['_MSPDBSRV_ENDPOINT_'] = endpoint_name + + def Dispatch(self, args): + """Dispatches a string command to a method.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + method = "Exec%s" % self._CommandifyName(args[0]) + return getattr(self, method)(*args[1:]) + + def _CommandifyName(self, name_string): + """Transforms a tool name like recursive-mirror to RecursiveMirror.""" + return name_string.title().replace('-', '') + + def _GetEnv(self, arch): + """Gets the saved environment from a file for a given architecture.""" + # The environment is saved as an "environment block" (see CreateProcess + # and msvs_emulation for details). We convert to a dict here. + # Drop last 2 NULs, one for list terminator, one for trailing vs. separator. + pairs = open(arch).read()[:-2].split('\0') + kvs = [item.split('=', 1) for item in pairs] + return dict(kvs) + + def ExecStamp(self, path): + """Simple stamp command.""" + open(path, 'w').close() + + def ExecRecursiveMirror(self, source, dest): + """Emulation of rm -rf out && cp -af in out.""" + if os.path.exists(dest): + if os.path.isdir(dest): + def _on_error(fn, path, excinfo): + # The operation failed, possibly because the file is set to + # read-only. If that's why, make it writable and try the op again. + if not os.access(path, os.W_OK): + os.chmod(path, stat.S_IWRITE) + fn(path) + shutil.rmtree(dest, onerror=_on_error) + else: + if not os.access(dest, os.W_OK): + # Attempt to make the file writable before deleting it. + os.chmod(dest, stat.S_IWRITE) + os.unlink(dest) + + if os.path.isdir(source): + shutil.copytree(source, dest) + else: + shutil.copy2(source, dest) + + def ExecLinkWrapper(self, arch, use_separate_mspdbsrv, *args): + """Filter diagnostic output from link that looks like: + ' Creating library ui.dll.lib and object ui.dll.exp' + This happens when there are exports from the dll or exe. + """ + env = self._GetEnv(arch) + if use_separate_mspdbsrv == 'True': + self._UseSeparateMspdbsrv(env, args) + link = subprocess.Popen(args, + shell=True, + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + out, _ = link.communicate() + for line in out.splitlines(): + if not line.startswith(' Creating library '): + print line + return link.returncode + + def ExecLinkWithManifests(self, arch, embed_manifest, out, ldcmd, resname, + mt, rc, intermediate_manifest, *manifests): + """A wrapper for handling creating a manifest resource and then executing + a link command.""" + # The 'normal' way to do manifests is to have link generate a manifest + # based on gathering dependencies from the object files, then merge that + # manifest with other manifests supplied as sources, convert the merged + # manifest to a resource, and then *relink*, including the compiled + # version of the manifest resource. This breaks incremental linking, and + # is generally overly complicated. Instead, we merge all the manifests + # provided (along with one that includes what would normally be in the + # linker-generated one, see msvs_emulation.py), and include that into the + # first and only link. We still tell link to generate a manifest, but we + # only use that to assert that our simpler process did not miss anything. + variables = { + 'python': sys.executable, + 'arch': arch, + 'out': out, + 'ldcmd': ldcmd, + 'resname': resname, + 'mt': mt, + 'rc': rc, + 'intermediate_manifest': intermediate_manifest, + 'manifests': ' '.join(manifests), + } + add_to_ld = '' + if manifests: + subprocess.check_call( + '%(python)s gyp-win-tool manifest-wrapper %(arch)s %(mt)s -nologo ' + '-manifest %(manifests)s -out:%(out)s.manifest' % variables) + if embed_manifest == 'True': + subprocess.check_call( + '%(python)s gyp-win-tool manifest-to-rc %(arch)s %(out)s.manifest' + ' %(out)s.manifest.rc %(resname)s' % variables) + subprocess.check_call( + '%(python)s gyp-win-tool rc-wrapper %(arch)s %(rc)s ' + '%(out)s.manifest.rc' % variables) + add_to_ld = ' %(out)s.manifest.res' % variables + subprocess.check_call(ldcmd + add_to_ld) + + # Run mt.exe on the theoretically complete manifest we generated, merging + # it with the one the linker generated to confirm that the linker + # generated one does not add anything. This is strictly unnecessary for + # correctness, it's only to verify that e.g. /MANIFESTDEPENDENCY was not + # used in a #pragma comment. + if manifests: + # Merge the intermediate one with ours to .assert.manifest, then check + # that .assert.manifest is identical to ours. + subprocess.check_call( + '%(python)s gyp-win-tool manifest-wrapper %(arch)s %(mt)s -nologo ' + '-manifest %(out)s.manifest %(intermediate_manifest)s ' + '-out:%(out)s.assert.manifest' % variables) + assert_manifest = '%(out)s.assert.manifest' % variables + our_manifest = '%(out)s.manifest' % variables + # Load and normalize the manifests. mt.exe sometimes removes whitespace, + # and sometimes doesn't unfortunately. + with open(our_manifest, 'rb') as our_f: + with open(assert_manifest, 'rb') as assert_f: + our_data = our_f.read().translate(None, string.whitespace) + assert_data = assert_f.read().translate(None, string.whitespace) + if our_data != assert_data: + os.unlink(out) + def dump(filename): + sys.stderr.write('%s\n-----\n' % filename) + with open(filename, 'rb') as f: + sys.stderr.write(f.read() + '\n-----\n') + dump(intermediate_manifest) + dump(our_manifest) + dump(assert_manifest) + sys.stderr.write( + 'Linker generated manifest "%s" added to final manifest "%s" ' + '(result in "%s"). ' + 'Were /MANIFEST switches used in #pragma statements? ' % ( + intermediate_manifest, our_manifest, assert_manifest)) + return 1 + + def ExecManifestWrapper(self, arch, *args): + """Run manifest tool with environment set. Strip out undesirable warning + (some XML blocks are recognized by the OS loader, but not the manifest + tool).""" + env = self._GetEnv(arch) + popen = subprocess.Popen(args, shell=True, env=env, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + out, _ = popen.communicate() + for line in out.splitlines(): + if line and 'manifest authoring warning 81010002' not in line: + print line + return popen.returncode + + def ExecManifestToRc(self, arch, *args): + """Creates a resource file pointing a SxS assembly manifest. + |args| is tuple containing path to resource file, path to manifest file + and resource name which can be "1" (for executables) or "2" (for DLLs).""" + manifest_path, resource_path, resource_name = args + with open(resource_path, 'wb') as output: + output.write('#include \n%s RT_MANIFEST "%s"' % ( + resource_name, + os.path.abspath(manifest_path).replace('\\', '/'))) + + def ExecMidlWrapper(self, arch, outdir, tlb, h, dlldata, iid, proxy, idl, + *flags): + """Filter noisy filenames output from MIDL compile step that isn't + quietable via command line flags. + """ + args = ['midl', '/nologo'] + list(flags) + [ + '/out', outdir, + '/tlb', tlb, + '/h', h, + '/dlldata', dlldata, + '/iid', iid, + '/proxy', proxy, + idl] + env = self._GetEnv(arch) + popen = subprocess.Popen(args, shell=True, env=env, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + out, _ = popen.communicate() + # Filter junk out of stdout, and write filtered versions. Output we want + # to filter is pairs of lines that look like this: + # Processing C:\Program Files (x86)\Microsoft SDKs\...\include\objidl.idl + # objidl.idl + lines = out.splitlines() + prefixes = ('Processing ', '64 bit Processing ') + processing = set(os.path.basename(x) + for x in lines if x.startswith(prefixes)) + for line in lines: + if not line.startswith(prefixes) and line not in processing: + print line + return popen.returncode + + def ExecAsmWrapper(self, arch, *args): + """Filter logo banner from invocations of asm.exe.""" + env = self._GetEnv(arch) + # MSVS doesn't assemble x64 asm files. + if arch == 'environment.x64': + return 0 + popen = subprocess.Popen(args, shell=True, env=env, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + out, _ = popen.communicate() + for line in out.splitlines(): + if (not line.startswith('Copyright (C) Microsoft Corporation') and + not line.startswith('Microsoft (R) Macro Assembler') and + not line.startswith(' Assembling: ') and + line): + print line + return popen.returncode + + def ExecRcWrapper(self, arch, *args): + """Filter logo banner from invocations of rc.exe. Older versions of RC + don't support the /nologo flag.""" + env = self._GetEnv(arch) + popen = subprocess.Popen(args, shell=True, env=env, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + out, _ = popen.communicate() + for line in out.splitlines(): + if (not line.startswith('Microsoft (R) Windows (R) Resource Compiler') and + not line.startswith('Copyright (C) Microsoft Corporation') and + line): + print line + return popen.returncode + + def ExecActionWrapper(self, arch, rspfile, *dir): + """Runs an action command line from a response file using the environment + for |arch|. If |dir| is supplied, use that as the working directory.""" + env = self._GetEnv(arch) + # TODO(scottmg): This is a temporary hack to get some specific variables + # through to actions that are set after gyp-time. http://crbug.com/333738. + for k, v in os.environ.iteritems(): + if k not in env: + env[k] = v + args = open(rspfile).read() + dir = dir[0] if dir else None + return subprocess.call(args, shell=True, env=env, cwd=dir) + + def ExecClCompile(self, project_dir, selected_files): + """Executed by msvs-ninja projects when the 'ClCompile' target is used to + build selected C/C++ files.""" + project_dir = os.path.relpath(project_dir, BASE_DIR) + selected_files = selected_files.split(';') + ninja_targets = [os.path.join(project_dir, filename) + '^^' + for filename in selected_files] + cmd = ['ninja.exe'] + cmd.extend(ninja_targets) + return subprocess.call(cmd, shell=True, cwd=BASE_DIR) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/deps/gyp/pylib/gyp/xcode_emulation.py b/deps/gyp/pylib/gyp/xcode_emulation.py new file mode 100644 index 000000000..859cd5a93 --- /dev/null +++ b/deps/gyp/pylib/gyp/xcode_emulation.py @@ -0,0 +1,1559 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +This module contains classes that help to emulate xcodebuild behavior on top of +other build systems, such as make and ninja. +""" + +import copy +import gyp.common +import os +import os.path +import re +import shlex +import subprocess +import sys +import tempfile +from gyp.common import GypError + +# Populated lazily by XcodeVersion, for efficiency, and to fix an issue when +# "xcodebuild" is called too quickly (it has been found to return incorrect +# version number). +XCODE_VERSION_CACHE = None + +# Populated lazily by GetXcodeArchsDefault, to an |XcodeArchsDefault| instance +# corresponding to the installed version of Xcode. +XCODE_ARCHS_DEFAULT_CACHE = None + + +def XcodeArchsVariableMapping(archs, archs_including_64_bit=None): + """Constructs a dictionary with expansion for $(ARCHS_STANDARD) variable, + and optionally for $(ARCHS_STANDARD_INCLUDING_64_BIT).""" + mapping = {'$(ARCHS_STANDARD)': archs} + if archs_including_64_bit: + mapping['$(ARCHS_STANDARD_INCLUDING_64_BIT)'] = archs_including_64_bit + return mapping + +class XcodeArchsDefault(object): + """A class to resolve ARCHS variable from xcode_settings, resolving Xcode + macros and implementing filtering by VALID_ARCHS. The expansion of macros + depends on the SDKROOT used ("macosx", "iphoneos", "iphonesimulator") and + on the version of Xcode. + """ + + # Match variable like $(ARCHS_STANDARD). + variable_pattern = re.compile(r'\$\([a-zA-Z_][a-zA-Z0-9_]*\)$') + + def __init__(self, default, mac, iphonesimulator, iphoneos): + self._default = (default,) + self._archs = {'mac': mac, 'ios': iphoneos, 'iossim': iphonesimulator} + + def _VariableMapping(self, sdkroot): + """Returns the dictionary of variable mapping depending on the SDKROOT.""" + sdkroot = sdkroot.lower() + if 'iphoneos' in sdkroot: + return self._archs['ios'] + elif 'iphonesimulator' in sdkroot: + return self._archs['iossim'] + else: + return self._archs['mac'] + + def _ExpandArchs(self, archs, sdkroot): + """Expands variables references in ARCHS, and remove duplicates.""" + variable_mapping = self._VariableMapping(sdkroot) + expanded_archs = [] + for arch in archs: + if self.variable_pattern.match(arch): + variable = arch + try: + variable_expansion = variable_mapping[variable] + for arch in variable_expansion: + if arch not in expanded_archs: + expanded_archs.append(arch) + except KeyError as e: + print 'Warning: Ignoring unsupported variable "%s".' % variable + elif arch not in expanded_archs: + expanded_archs.append(arch) + return expanded_archs + + def ActiveArchs(self, archs, valid_archs, sdkroot): + """Expands variables references in ARCHS, and filter by VALID_ARCHS if it + is defined (if not set, Xcode accept any value in ARCHS, otherwise, only + values present in VALID_ARCHS are kept).""" + expanded_archs = self._ExpandArchs(archs or self._default, sdkroot or '') + if valid_archs: + filtered_archs = [] + for arch in expanded_archs: + if arch in valid_archs: + filtered_archs.append(arch) + expanded_archs = filtered_archs + return expanded_archs + + +def GetXcodeArchsDefault(): + """Returns the |XcodeArchsDefault| object to use to expand ARCHS for the + installed version of Xcode. The default values used by Xcode for ARCHS + and the expansion of the variables depends on the version of Xcode used. + + For all version anterior to Xcode 5.0 or posterior to Xcode 5.1 included + uses $(ARCHS_STANDARD) if ARCHS is unset, while Xcode 5.0 to 5.0.2 uses + $(ARCHS_STANDARD_INCLUDING_64_BIT). This variable was added to Xcode 5.0 + and deprecated with Xcode 5.1. + + For "macosx" SDKROOT, all version starting with Xcode 5.0 includes 64-bit + architecture as part of $(ARCHS_STANDARD) and default to only building it. + + For "iphoneos" and "iphonesimulator" SDKROOT, 64-bit architectures are part + of $(ARCHS_STANDARD_INCLUDING_64_BIT) from Xcode 5.0. From Xcode 5.1, they + are also part of $(ARCHS_STANDARD). + + All thoses rules are coded in the construction of the |XcodeArchsDefault| + object to use depending on the version of Xcode detected. The object is + for performance reason.""" + global XCODE_ARCHS_DEFAULT_CACHE + if XCODE_ARCHS_DEFAULT_CACHE: + return XCODE_ARCHS_DEFAULT_CACHE + xcode_version, _ = XcodeVersion() + if xcode_version < '0500': + XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault( + '$(ARCHS_STANDARD)', + XcodeArchsVariableMapping(['i386']), + XcodeArchsVariableMapping(['i386']), + XcodeArchsVariableMapping(['armv7'])) + elif xcode_version < '0510': + XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault( + '$(ARCHS_STANDARD_INCLUDING_64_BIT)', + XcodeArchsVariableMapping(['x86_64'], ['x86_64']), + XcodeArchsVariableMapping(['i386'], ['i386', 'x86_64']), + XcodeArchsVariableMapping( + ['armv7', 'armv7s'], + ['armv7', 'armv7s', 'arm64'])) + else: + XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault( + '$(ARCHS_STANDARD)', + XcodeArchsVariableMapping(['x86_64'], ['x86_64']), + XcodeArchsVariableMapping(['i386', 'x86_64'], ['i386', 'x86_64']), + XcodeArchsVariableMapping( + ['armv7', 'armv7s', 'arm64'], + ['armv7', 'armv7s', 'arm64'])) + return XCODE_ARCHS_DEFAULT_CACHE + + +class XcodeSettings(object): + """A class that understands the gyp 'xcode_settings' object.""" + + # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached + # at class-level for efficiency. + _sdk_path_cache = {} + _sdk_root_cache = {} + + # Populated lazily by GetExtraPlistItems(). Shared by all XcodeSettings, so + # cached at class-level for efficiency. + _plist_cache = {} + + # Populated lazily by GetIOSPostbuilds. Shared by all XcodeSettings, so + # cached at class-level for efficiency. + _codesigning_key_cache = {} + + def __init__(self, spec): + self.spec = spec + + self.isIOS = False + + # Per-target 'xcode_settings' are pushed down into configs earlier by gyp. + # This means self.xcode_settings[config] always contains all settings + # for that config -- the per-target settings as well. Settings that are + # the same for all configs are implicitly per-target settings. + self.xcode_settings = {} + configs = spec['configurations'] + for configname, config in configs.iteritems(): + self.xcode_settings[configname] = config.get('xcode_settings', {}) + self._ConvertConditionalKeys(configname) + if self.xcode_settings[configname].get('IPHONEOS_DEPLOYMENT_TARGET', + None): + self.isIOS = True + + # This is only non-None temporarily during the execution of some methods. + self.configname = None + + # Used by _AdjustLibrary to match .a and .dylib entries in libraries. + self.library_re = re.compile(r'^lib([^/]+)\.(a|dylib)$') + + def _ConvertConditionalKeys(self, configname): + """Converts or warns on conditional keys. Xcode supports conditional keys, + such as CODE_SIGN_IDENTITY[sdk=iphoneos*]. This is a partial implementation + with some keys converted while the rest force a warning.""" + settings = self.xcode_settings[configname] + conditional_keys = [key for key in settings if key.endswith(']')] + for key in conditional_keys: + # If you need more, speak up at http://crbug.com/122592 + if key.endswith("[sdk=iphoneos*]"): + if configname.endswith("iphoneos"): + new_key = key.split("[")[0] + settings[new_key] = settings[key] + else: + print 'Warning: Conditional keys not implemented, ignoring:', \ + ' '.join(conditional_keys) + del settings[key] + + def _Settings(self): + assert self.configname + return self.xcode_settings[self.configname] + + def _Test(self, test_key, cond_key, default): + return self._Settings().get(test_key, default) == cond_key + + def _Appendf(self, lst, test_key, format_str, default=None): + if test_key in self._Settings(): + lst.append(format_str % str(self._Settings()[test_key])) + elif default: + lst.append(format_str % str(default)) + + def _WarnUnimplemented(self, test_key): + if test_key in self._Settings(): + print 'Warning: Ignoring not yet implemented key "%s".' % test_key + + def _IsBundle(self): + return int(self.spec.get('mac_bundle', 0)) != 0 + + def GetFrameworkVersion(self): + """Returns the framework version of the current target. Only valid for + bundles.""" + assert self._IsBundle() + return self.GetPerTargetSetting('FRAMEWORK_VERSION', default='A') + + def GetWrapperExtension(self): + """Returns the bundle extension (.app, .framework, .plugin, etc). Only + valid for bundles.""" + assert self._IsBundle() + if self.spec['type'] in ('loadable_module', 'shared_library'): + default_wrapper_extension = { + 'loadable_module': 'bundle', + 'shared_library': 'framework', + }[self.spec['type']] + wrapper_extension = self.GetPerTargetSetting( + 'WRAPPER_EXTENSION', default=default_wrapper_extension) + return '.' + self.spec.get('product_extension', wrapper_extension) + elif self.spec['type'] == 'executable': + return '.' + self.spec.get('product_extension', 'app') + else: + assert False, "Don't know extension for '%s', target '%s'" % ( + self.spec['type'], self.spec['target_name']) + + def GetProductName(self): + """Returns PRODUCT_NAME.""" + return self.spec.get('product_name', self.spec['target_name']) + + def GetFullProductName(self): + """Returns FULL_PRODUCT_NAME.""" + if self._IsBundle(): + return self.GetWrapperName() + else: + return self._GetStandaloneBinaryPath() + + def GetWrapperName(self): + """Returns the directory name of the bundle represented by this target. + Only valid for bundles.""" + assert self._IsBundle() + return self.GetProductName() + self.GetWrapperExtension() + + def GetBundleContentsFolderPath(self): + """Returns the qualified path to the bundle's contents folder. E.g. + Chromium.app/Contents or Foo.bundle/Versions/A. Only valid for bundles.""" + if self.isIOS: + return self.GetWrapperName() + assert self._IsBundle() + if self.spec['type'] == 'shared_library': + return os.path.join( + self.GetWrapperName(), 'Versions', self.GetFrameworkVersion()) + else: + # loadable_modules have a 'Contents' folder like executables. + return os.path.join(self.GetWrapperName(), 'Contents') + + def GetBundleResourceFolder(self): + """Returns the qualified path to the bundle's resource folder. E.g. + Chromium.app/Contents/Resources. Only valid for bundles.""" + assert self._IsBundle() + if self.isIOS: + return self.GetBundleContentsFolderPath() + return os.path.join(self.GetBundleContentsFolderPath(), 'Resources') + + def GetBundlePlistPath(self): + """Returns the qualified path to the bundle's plist file. E.g. + Chromium.app/Contents/Info.plist. Only valid for bundles.""" + assert self._IsBundle() + if self.spec['type'] in ('executable', 'loadable_module'): + return os.path.join(self.GetBundleContentsFolderPath(), 'Info.plist') + else: + return os.path.join(self.GetBundleContentsFolderPath(), + 'Resources', 'Info.plist') + + def GetProductType(self): + """Returns the PRODUCT_TYPE of this target.""" + if self._IsBundle(): + return { + 'executable': 'com.apple.product-type.application', + 'loadable_module': 'com.apple.product-type.bundle', + 'shared_library': 'com.apple.product-type.framework', + }[self.spec['type']] + else: + return { + 'executable': 'com.apple.product-type.tool', + 'loadable_module': 'com.apple.product-type.library.dynamic', + 'shared_library': 'com.apple.product-type.library.dynamic', + 'static_library': 'com.apple.product-type.library.static', + }[self.spec['type']] + + def GetMachOType(self): + """Returns the MACH_O_TYPE of this target.""" + # Weird, but matches Xcode. + if not self._IsBundle() and self.spec['type'] == 'executable': + return '' + return { + 'executable': 'mh_execute', + 'static_library': 'staticlib', + 'shared_library': 'mh_dylib', + 'loadable_module': 'mh_bundle', + }[self.spec['type']] + + def _GetBundleBinaryPath(self): + """Returns the name of the bundle binary of by this target. + E.g. Chromium.app/Contents/MacOS/Chromium. Only valid for bundles.""" + assert self._IsBundle() + if self.spec['type'] in ('shared_library') or self.isIOS: + path = self.GetBundleContentsFolderPath() + elif self.spec['type'] in ('executable', 'loadable_module'): + path = os.path.join(self.GetBundleContentsFolderPath(), 'MacOS') + return os.path.join(path, self.GetExecutableName()) + + def _GetStandaloneExecutableSuffix(self): + if 'product_extension' in self.spec: + return '.' + self.spec['product_extension'] + return { + 'executable': '', + 'static_library': '.a', + 'shared_library': '.dylib', + 'loadable_module': '.so', + }[self.spec['type']] + + def _GetStandaloneExecutablePrefix(self): + return self.spec.get('product_prefix', { + 'executable': '', + 'static_library': 'lib', + 'shared_library': 'lib', + # Non-bundled loadable_modules are called foo.so for some reason + # (that is, .so and no prefix) with the xcode build -- match that. + 'loadable_module': '', + }[self.spec['type']]) + + def _GetStandaloneBinaryPath(self): + """Returns the name of the non-bundle binary represented by this target. + E.g. hello_world. Only valid for non-bundles.""" + assert not self._IsBundle() + assert self.spec['type'] in ( + 'executable', 'shared_library', 'static_library', 'loadable_module'), ( + 'Unexpected type %s' % self.spec['type']) + target = self.spec['target_name'] + if self.spec['type'] == 'static_library': + if target[:3] == 'lib': + target = target[3:] + elif self.spec['type'] in ('loadable_module', 'shared_library'): + if target[:3] == 'lib': + target = target[3:] + + target_prefix = self._GetStandaloneExecutablePrefix() + target = self.spec.get('product_name', target) + target_ext = self._GetStandaloneExecutableSuffix() + return target_prefix + target + target_ext + + def GetExecutableName(self): + """Returns the executable name of the bundle represented by this target. + E.g. Chromium.""" + if self._IsBundle(): + return self.spec.get('product_name', self.spec['target_name']) + else: + return self._GetStandaloneBinaryPath() + + def GetExecutablePath(self): + """Returns the directory name of the bundle represented by this target. E.g. + Chromium.app/Contents/MacOS/Chromium.""" + if self._IsBundle(): + return self._GetBundleBinaryPath() + else: + return self._GetStandaloneBinaryPath() + + def GetActiveArchs(self, configname): + """Returns the architectures this target should be built for.""" + config_settings = self.xcode_settings[configname] + xcode_archs_default = GetXcodeArchsDefault() + return xcode_archs_default.ActiveArchs( + config_settings.get('ARCHS'), + config_settings.get('VALID_ARCHS'), + config_settings.get('SDKROOT')) + + def _GetSdkVersionInfoItem(self, sdk, infoitem): + # xcodebuild requires Xcode and can't run on Command Line Tools-only + # systems from 10.7 onward. + # Since the CLT has no SDK paths anyway, returning None is the + # most sensible route and should still do the right thing. + try: + return GetStdout(['xcodebuild', '-version', '-sdk', sdk, infoitem]) + except: + pass + + def _SdkRoot(self, configname): + if configname is None: + configname = self.configname + return self.GetPerConfigSetting('SDKROOT', configname, default='') + + def _SdkPath(self, configname=None): + sdk_root = self._SdkRoot(configname) + if sdk_root.startswith('/'): + return sdk_root + return self._XcodeSdkPath(sdk_root) + + def _XcodeSdkPath(self, sdk_root): + if sdk_root not in XcodeSettings._sdk_path_cache: + sdk_path = self._GetSdkVersionInfoItem(sdk_root, 'Path') + XcodeSettings._sdk_path_cache[sdk_root] = sdk_path + if sdk_root: + XcodeSettings._sdk_root_cache[sdk_path] = sdk_root + return XcodeSettings._sdk_path_cache[sdk_root] + + def _AppendPlatformVersionMinFlags(self, lst): + self._Appendf(lst, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s') + if 'IPHONEOS_DEPLOYMENT_TARGET' in self._Settings(): + # TODO: Implement this better? + sdk_path_basename = os.path.basename(self._SdkPath()) + if sdk_path_basename.lower().startswith('iphonesimulator'): + self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET', + '-mios-simulator-version-min=%s') + else: + self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET', + '-miphoneos-version-min=%s') + + def GetCflags(self, configname, arch=None): + """Returns flags that need to be added to .c, .cc, .m, and .mm + compilations.""" + # This functions (and the similar ones below) do not offer complete + # emulation of all xcode_settings keys. They're implemented on demand. + + self.configname = configname + cflags = [] + + sdk_root = self._SdkPath() + if 'SDKROOT' in self._Settings() and sdk_root: + cflags.append('-isysroot %s' % sdk_root) + + if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'): + cflags.append('-Wconstant-conversion') + + if self._Test('GCC_CHAR_IS_UNSIGNED_CHAR', 'YES', default='NO'): + cflags.append('-funsigned-char') + + if self._Test('GCC_CW_ASM_SYNTAX', 'YES', default='YES'): + cflags.append('-fasm-blocks') + + if 'GCC_DYNAMIC_NO_PIC' in self._Settings(): + if self._Settings()['GCC_DYNAMIC_NO_PIC'] == 'YES': + cflags.append('-mdynamic-no-pic') + else: + pass + # TODO: In this case, it depends on the target. xcode passes + # mdynamic-no-pic by default for executable and possibly static lib + # according to mento + + if self._Test('GCC_ENABLE_PASCAL_STRINGS', 'YES', default='YES'): + cflags.append('-mpascal-strings') + + self._Appendf(cflags, 'GCC_OPTIMIZATION_LEVEL', '-O%s', default='s') + + if self._Test('GCC_GENERATE_DEBUGGING_SYMBOLS', 'YES', default='YES'): + dbg_format = self._Settings().get('DEBUG_INFORMATION_FORMAT', 'dwarf') + if dbg_format == 'dwarf': + cflags.append('-gdwarf-2') + elif dbg_format == 'stabs': + raise NotImplementedError('stabs debug format is not supported yet.') + elif dbg_format == 'dwarf-with-dsym': + cflags.append('-gdwarf-2') + else: + raise NotImplementedError('Unknown debug format %s' % dbg_format) + + if self._Settings().get('GCC_STRICT_ALIASING') == 'YES': + cflags.append('-fstrict-aliasing') + elif self._Settings().get('GCC_STRICT_ALIASING') == 'NO': + cflags.append('-fno-strict-aliasing') + + if self._Test('GCC_SYMBOLS_PRIVATE_EXTERN', 'YES', default='NO'): + cflags.append('-fvisibility=hidden') + + if self._Test('GCC_TREAT_WARNINGS_AS_ERRORS', 'YES', default='NO'): + cflags.append('-Werror') + + if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'): + cflags.append('-Wnewline-eof') + + self._AppendPlatformVersionMinFlags(cflags) + + # TODO: + if self._Test('COPY_PHASE_STRIP', 'YES', default='NO'): + self._WarnUnimplemented('COPY_PHASE_STRIP') + self._WarnUnimplemented('GCC_DEBUGGING_SYMBOLS') + self._WarnUnimplemented('GCC_ENABLE_OBJC_EXCEPTIONS') + + # TODO: This is exported correctly, but assigning to it is not supported. + self._WarnUnimplemented('MACH_O_TYPE') + self._WarnUnimplemented('PRODUCT_TYPE') + + if arch is not None: + archs = [arch] + else: + assert self.configname + archs = self.GetActiveArchs(self.configname) + if len(archs) != 1: + # TODO: Supporting fat binaries will be annoying. + self._WarnUnimplemented('ARCHS') + archs = ['i386'] + cflags.append('-arch ' + archs[0]) + + if archs[0] in ('i386', 'x86_64'): + if self._Test('GCC_ENABLE_SSE3_EXTENSIONS', 'YES', default='NO'): + cflags.append('-msse3') + if self._Test('GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS', 'YES', + default='NO'): + cflags.append('-mssse3') # Note 3rd 's'. + if self._Test('GCC_ENABLE_SSE41_EXTENSIONS', 'YES', default='NO'): + cflags.append('-msse4.1') + if self._Test('GCC_ENABLE_SSE42_EXTENSIONS', 'YES', default='NO'): + cflags.append('-msse4.2') + + cflags += self._Settings().get('WARNING_CFLAGS', []) + + if sdk_root: + framework_root = sdk_root + else: + framework_root = '' + config = self.spec['configurations'][self.configname] + framework_dirs = config.get('mac_framework_dirs', []) + for directory in framework_dirs: + cflags.append('-F' + directory.replace('$(SDKROOT)', framework_root)) + + self.configname = None + return cflags + + def GetCflagsC(self, configname): + """Returns flags that need to be added to .c, and .m compilations.""" + self.configname = configname + cflags_c = [] + if self._Settings().get('GCC_C_LANGUAGE_STANDARD', '') == 'ansi': + cflags_c.append('-ansi') + else: + self._Appendf(cflags_c, 'GCC_C_LANGUAGE_STANDARD', '-std=%s') + cflags_c += self._Settings().get('OTHER_CFLAGS', []) + self.configname = None + return cflags_c + + def GetCflagsCC(self, configname): + """Returns flags that need to be added to .cc, and .mm compilations.""" + self.configname = configname + cflags_cc = [] + + clang_cxx_language_standard = self._Settings().get( + 'CLANG_CXX_LANGUAGE_STANDARD') + # Note: Don't make c++0x to c++11 so that c++0x can be used with older + # clangs that don't understand c++11 yet (like Xcode 4.2's). + if clang_cxx_language_standard: + cflags_cc.append('-std=%s' % clang_cxx_language_standard) + + self._Appendf(cflags_cc, 'CLANG_CXX_LIBRARY', '-stdlib=%s') + + if self._Test('GCC_ENABLE_CPP_RTTI', 'NO', default='YES'): + cflags_cc.append('-fno-rtti') + if self._Test('GCC_ENABLE_CPP_EXCEPTIONS', 'NO', default='YES'): + cflags_cc.append('-fno-exceptions') + if self._Test('GCC_INLINES_ARE_PRIVATE_EXTERN', 'YES', default='NO'): + cflags_cc.append('-fvisibility-inlines-hidden') + if self._Test('GCC_THREADSAFE_STATICS', 'NO', default='YES'): + cflags_cc.append('-fno-threadsafe-statics') + # Note: This flag is a no-op for clang, it only has an effect for gcc. + if self._Test('GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO', 'NO', default='YES'): + cflags_cc.append('-Wno-invalid-offsetof') + + other_ccflags = [] + + for flag in self._Settings().get('OTHER_CPLUSPLUSFLAGS', ['$(inherited)']): + # TODO: More general variable expansion. Missing in many other places too. + if flag in ('$inherited', '$(inherited)', '${inherited}'): + flag = '$OTHER_CFLAGS' + if flag in ('$OTHER_CFLAGS', '$(OTHER_CFLAGS)', '${OTHER_CFLAGS}'): + other_ccflags += self._Settings().get('OTHER_CFLAGS', []) + else: + other_ccflags.append(flag) + cflags_cc += other_ccflags + + self.configname = None + return cflags_cc + + def _AddObjectiveCGarbageCollectionFlags(self, flags): + gc_policy = self._Settings().get('GCC_ENABLE_OBJC_GC', 'unsupported') + if gc_policy == 'supported': + flags.append('-fobjc-gc') + elif gc_policy == 'required': + flags.append('-fobjc-gc-only') + + def _AddObjectiveCARCFlags(self, flags): + if self._Test('CLANG_ENABLE_OBJC_ARC', 'YES', default='NO'): + flags.append('-fobjc-arc') + + def _AddObjectiveCMissingPropertySynthesisFlags(self, flags): + if self._Test('CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS', + 'YES', default='NO'): + flags.append('-Wobjc-missing-property-synthesis') + + def GetCflagsObjC(self, configname): + """Returns flags that need to be added to .m compilations.""" + self.configname = configname + cflags_objc = [] + self._AddObjectiveCGarbageCollectionFlags(cflags_objc) + self._AddObjectiveCARCFlags(cflags_objc) + self._AddObjectiveCMissingPropertySynthesisFlags(cflags_objc) + self.configname = None + return cflags_objc + + def GetCflagsObjCC(self, configname): + """Returns flags that need to be added to .mm compilations.""" + self.configname = configname + cflags_objcc = [] + self._AddObjectiveCGarbageCollectionFlags(cflags_objcc) + self._AddObjectiveCARCFlags(cflags_objcc) + self._AddObjectiveCMissingPropertySynthesisFlags(cflags_objcc) + if self._Test('GCC_OBJC_CALL_CXX_CDTORS', 'YES', default='NO'): + cflags_objcc.append('-fobjc-call-cxx-cdtors') + self.configname = None + return cflags_objcc + + def GetInstallNameBase(self): + """Return DYLIB_INSTALL_NAME_BASE for this target.""" + # Xcode sets this for shared_libraries, and for nonbundled loadable_modules. + if (self.spec['type'] != 'shared_library' and + (self.spec['type'] != 'loadable_module' or self._IsBundle())): + return None + install_base = self.GetPerTargetSetting( + 'DYLIB_INSTALL_NAME_BASE', + default='/Library/Frameworks' if self._IsBundle() else '/usr/local/lib') + return install_base + + def _StandardizePath(self, path): + """Do :standardizepath processing for path.""" + # I'm not quite sure what :standardizepath does. Just call normpath(), + # but don't let @executable_path/../foo collapse to foo. + if '/' in path: + prefix, rest = '', path + if path.startswith('@'): + prefix, rest = path.split('/', 1) + rest = os.path.normpath(rest) # :standardizepath + path = os.path.join(prefix, rest) + return path + + def GetInstallName(self): + """Return LD_DYLIB_INSTALL_NAME for this target.""" + # Xcode sets this for shared_libraries, and for nonbundled loadable_modules. + if (self.spec['type'] != 'shared_library' and + (self.spec['type'] != 'loadable_module' or self._IsBundle())): + return None + + default_install_name = \ + '$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)' + install_name = self.GetPerTargetSetting( + 'LD_DYLIB_INSTALL_NAME', default=default_install_name) + + # Hardcode support for the variables used in chromium for now, to + # unblock people using the make build. + if '$' in install_name: + assert install_name in ('$(DYLIB_INSTALL_NAME_BASE:standardizepath)/' + '$(WRAPPER_NAME)/$(PRODUCT_NAME)', default_install_name), ( + 'Variables in LD_DYLIB_INSTALL_NAME are not generally supported ' + 'yet in target \'%s\' (got \'%s\')' % + (self.spec['target_name'], install_name)) + + install_name = install_name.replace( + '$(DYLIB_INSTALL_NAME_BASE:standardizepath)', + self._StandardizePath(self.GetInstallNameBase())) + if self._IsBundle(): + # These are only valid for bundles, hence the |if|. + install_name = install_name.replace( + '$(WRAPPER_NAME)', self.GetWrapperName()) + install_name = install_name.replace( + '$(PRODUCT_NAME)', self.GetProductName()) + else: + assert '$(WRAPPER_NAME)' not in install_name + assert '$(PRODUCT_NAME)' not in install_name + + install_name = install_name.replace( + '$(EXECUTABLE_PATH)', self.GetExecutablePath()) + return install_name + + def _MapLinkerFlagFilename(self, ldflag, gyp_to_build_path): + """Checks if ldflag contains a filename and if so remaps it from + gyp-directory-relative to build-directory-relative.""" + # This list is expanded on demand. + # They get matched as: + # -exported_symbols_list file + # -Wl,exported_symbols_list file + # -Wl,exported_symbols_list,file + LINKER_FILE = '(\S+)' + WORD = '\S+' + linker_flags = [ + ['-exported_symbols_list', LINKER_FILE], # Needed for NaCl. + ['-unexported_symbols_list', LINKER_FILE], + ['-reexported_symbols_list', LINKER_FILE], + ['-sectcreate', WORD, WORD, LINKER_FILE], # Needed for remoting. + ] + for flag_pattern in linker_flags: + regex = re.compile('(?:-Wl,)?' + '[ ,]'.join(flag_pattern)) + m = regex.match(ldflag) + if m: + ldflag = ldflag[:m.start(1)] + gyp_to_build_path(m.group(1)) + \ + ldflag[m.end(1):] + # Required for ffmpeg (no idea why they don't use LIBRARY_SEARCH_PATHS, + # TODO(thakis): Update ffmpeg.gyp): + if ldflag.startswith('-L'): + ldflag = '-L' + gyp_to_build_path(ldflag[len('-L'):]) + return ldflag + + def GetLdflags(self, configname, product_dir, gyp_to_build_path, arch=None): + """Returns flags that need to be passed to the linker. + + Args: + configname: The name of the configuration to get ld flags for. + product_dir: The directory where products such static and dynamic + libraries are placed. This is added to the library search path. + gyp_to_build_path: A function that converts paths relative to the + current gyp file to paths relative to the build direcotry. + """ + self.configname = configname + ldflags = [] + + # The xcode build is relative to a gyp file's directory, and OTHER_LDFLAGS + # can contain entries that depend on this. Explicitly absolutify these. + for ldflag in self._Settings().get('OTHER_LDFLAGS', []): + ldflags.append(self._MapLinkerFlagFilename(ldflag, gyp_to_build_path)) + + if self._Test('DEAD_CODE_STRIPPING', 'YES', default='NO'): + ldflags.append('-Wl,-dead_strip') + + if self._Test('PREBINDING', 'YES', default='NO'): + ldflags.append('-Wl,-prebind') + + self._Appendf( + ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s') + self._Appendf( + ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s') + + self._AppendPlatformVersionMinFlags(ldflags) + + if 'SDKROOT' in self._Settings() and self._SdkPath(): + ldflags.append('-isysroot ' + self._SdkPath()) + + for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []): + ldflags.append('-L' + gyp_to_build_path(library_path)) + + if 'ORDER_FILE' in self._Settings(): + ldflags.append('-Wl,-order_file ' + + '-Wl,' + gyp_to_build_path( + self._Settings()['ORDER_FILE'])) + + if arch is not None: + archs = [arch] + else: + assert self.configname + archs = self.GetActiveArchs(self.configname) + if len(archs) != 1: + # TODO: Supporting fat binaries will be annoying. + self._WarnUnimplemented('ARCHS') + archs = ['i386'] + ldflags.append('-arch ' + archs[0]) + + # Xcode adds the product directory by default. + ldflags.append('-L' + product_dir) + + install_name = self.GetInstallName() + if install_name and self.spec['type'] != 'loadable_module': + ldflags.append('-install_name ' + install_name.replace(' ', r'\ ')) + + for rpath in self._Settings().get('LD_RUNPATH_SEARCH_PATHS', []): + ldflags.append('-Wl,-rpath,' + rpath) + + sdk_root = self._SdkPath() + if not sdk_root: + sdk_root = '' + config = self.spec['configurations'][self.configname] + framework_dirs = config.get('mac_framework_dirs', []) + for directory in framework_dirs: + ldflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root)) + + self._Appendf(ldflags, 'CLANG_CXX_LIBRARY', '-stdlib=%s') + + self.configname = None + return ldflags + + def GetLibtoolflags(self, configname): + """Returns flags that need to be passed to the static linker. + + Args: + configname: The name of the configuration to get ld flags for. + """ + self.configname = configname + libtoolflags = [] + + for libtoolflag in self._Settings().get('OTHER_LDFLAGS', []): + libtoolflags.append(libtoolflag) + # TODO(thakis): ARCHS? + + self.configname = None + return libtoolflags + + def GetPerTargetSettings(self): + """Gets a list of all the per-target settings. This will only fetch keys + whose values are the same across all configurations.""" + first_pass = True + result = {} + for configname in sorted(self.xcode_settings.keys()): + if first_pass: + result = dict(self.xcode_settings[configname]) + first_pass = False + else: + for key, value in self.xcode_settings[configname].iteritems(): + if key not in result: + continue + elif result[key] != value: + del result[key] + return result + + def GetPerConfigSetting(self, setting, configname, default=None): + if configname in self.xcode_settings: + return self.xcode_settings[configname].get(setting, default) + else: + return self.GetPerTargetSetting(setting, default) + + def GetPerTargetSetting(self, setting, default=None): + """Tries to get xcode_settings.setting from spec. Assumes that the setting + has the same value in all configurations and throws otherwise.""" + is_first_pass = True + result = None + for configname in sorted(self.xcode_settings.keys()): + if is_first_pass: + result = self.xcode_settings[configname].get(setting, None) + is_first_pass = False + else: + assert result == self.xcode_settings[configname].get(setting, None), ( + "Expected per-target setting for '%s', got per-config setting " + "(target %s)" % (setting, self.spec['target_name'])) + if result is None: + return default + return result + + def _GetStripPostbuilds(self, configname, output_binary, quiet): + """Returns a list of shell commands that contain the shell commands + neccessary to strip this target's binary. These should be run as postbuilds + before the actual postbuilds run.""" + self.configname = configname + + result = [] + if (self._Test('DEPLOYMENT_POSTPROCESSING', 'YES', default='NO') and + self._Test('STRIP_INSTALLED_PRODUCT', 'YES', default='NO')): + + default_strip_style = 'debugging' + if self.spec['type'] == 'loadable_module' and self._IsBundle(): + default_strip_style = 'non-global' + elif self.spec['type'] == 'executable': + default_strip_style = 'all' + + strip_style = self._Settings().get('STRIP_STYLE', default_strip_style) + strip_flags = { + 'all': '', + 'non-global': '-x', + 'debugging': '-S', + }[strip_style] + + explicit_strip_flags = self._Settings().get('STRIPFLAGS', '') + if explicit_strip_flags: + strip_flags += ' ' + _NormalizeEnvVarReferences(explicit_strip_flags) + + if not quiet: + result.append('echo STRIP\\(%s\\)' % self.spec['target_name']) + result.append('strip %s %s' % (strip_flags, output_binary)) + + self.configname = None + return result + + def _GetDebugInfoPostbuilds(self, configname, output, output_binary, quiet): + """Returns a list of shell commands that contain the shell commands + neccessary to massage this target's debug information. These should be run + as postbuilds before the actual postbuilds run.""" + self.configname = configname + + # For static libraries, no dSYMs are created. + result = [] + if (self._Test('GCC_GENERATE_DEBUGGING_SYMBOLS', 'YES', default='YES') and + self._Test( + 'DEBUG_INFORMATION_FORMAT', 'dwarf-with-dsym', default='dwarf') and + self.spec['type'] != 'static_library'): + if not quiet: + result.append('echo DSYMUTIL\\(%s\\)' % self.spec['target_name']) + result.append('dsymutil %s -o %s' % (output_binary, output + '.dSYM')) + + self.configname = None + return result + + def _GetTargetPostbuilds(self, configname, output, output_binary, + quiet=False): + """Returns a list of shell commands that contain the shell commands + to run as postbuilds for this target, before the actual postbuilds.""" + # dSYMs need to build before stripping happens. + return ( + self._GetDebugInfoPostbuilds(configname, output, output_binary, quiet) + + self._GetStripPostbuilds(configname, output_binary, quiet)) + + def _GetIOSPostbuilds(self, configname, output_binary): + """Return a shell command to codesign the iOS output binary so it can + be deployed to a device. This should be run as the very last step of the + build.""" + if not (self.isIOS and self.spec['type'] == "executable"): + return [] + + settings = self.xcode_settings[configname] + key = self._GetIOSCodeSignIdentityKey(settings) + if not key: + return [] + + # Warn for any unimplemented signing xcode keys. + unimpl = ['OTHER_CODE_SIGN_FLAGS'] + unimpl = set(unimpl) & set(self.xcode_settings[configname].keys()) + if unimpl: + print 'Warning: Some codesign keys not implemented, ignoring: %s' % ( + ', '.join(sorted(unimpl))) + + return ['%s code-sign-bundle "%s" "%s" "%s" "%s"' % ( + os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key, + settings.get('CODE_SIGN_RESOURCE_RULES_PATH', ''), + settings.get('CODE_SIGN_ENTITLEMENTS', ''), + settings.get('PROVISIONING_PROFILE', '')) + ] + + def _GetIOSCodeSignIdentityKey(self, settings): + identity = settings.get('CODE_SIGN_IDENTITY') + if not identity: + return None + if identity not in XcodeSettings._codesigning_key_cache: + output = subprocess.check_output( + ['security', 'find-identity', '-p', 'codesigning', '-v']) + for line in output.splitlines(): + if identity in line: + fingerprint = line.split()[1] + cache = XcodeSettings._codesigning_key_cache + assert identity not in cache or fingerprint == cache[identity], ( + "Multiple codesigning fingerprints for identity: %s" % identity) + XcodeSettings._codesigning_key_cache[identity] = fingerprint + return XcodeSettings._codesigning_key_cache.get(identity, '') + + def AddImplicitPostbuilds(self, configname, output, output_binary, + postbuilds=[], quiet=False): + """Returns a list of shell commands that should run before and after + |postbuilds|.""" + assert output_binary is not None + pre = self._GetTargetPostbuilds(configname, output, output_binary, quiet) + post = self._GetIOSPostbuilds(configname, output_binary) + return pre + postbuilds + post + + def _AdjustLibrary(self, library, config_name=None): + if library.endswith('.framework'): + l = '-framework ' + os.path.splitext(os.path.basename(library))[0] + else: + m = self.library_re.match(library) + if m: + l = '-l' + m.group(1) + else: + l = library + + sdk_root = self._SdkPath(config_name) + if not sdk_root: + sdk_root = '' + return l.replace('$(SDKROOT)', sdk_root) + + def AdjustLibraries(self, libraries, config_name=None): + """Transforms entries like 'Cocoa.framework' in libraries into entries like + '-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc. + """ + libraries = [self._AdjustLibrary(library, config_name) + for library in libraries] + return libraries + + def _BuildMachineOSBuild(self): + return GetStdout(['sw_vers', '-buildVersion']) + + def _XcodeIOSDeviceFamily(self, configname): + family = self.xcode_settings[configname].get('TARGETED_DEVICE_FAMILY', '1') + return [int(x) for x in family.split(',')] + + def GetExtraPlistItems(self, configname=None): + """Returns a dictionary with extra items to insert into Info.plist.""" + if configname not in XcodeSettings._plist_cache: + cache = {} + cache['BuildMachineOSBuild'] = self._BuildMachineOSBuild() + + xcode, xcode_build = XcodeVersion() + cache['DTXcode'] = xcode + cache['DTXcodeBuild'] = xcode_build + + sdk_root = self._SdkRoot(configname) + if not sdk_root: + sdk_root = self._DefaultSdkRoot() + cache['DTSDKName'] = sdk_root + if xcode >= '0430': + cache['DTSDKBuild'] = self._GetSdkVersionInfoItem( + sdk_root, 'ProductBuildVersion') + else: + cache['DTSDKBuild'] = cache['BuildMachineOSBuild'] + + if self.isIOS: + cache['DTPlatformName'] = cache['DTSDKName'] + if configname.endswith("iphoneos"): + cache['DTPlatformVersion'] = self._GetSdkVersionInfoItem( + sdk_root, 'ProductVersion') + cache['CFBundleSupportedPlatforms'] = ['iPhoneOS'] + else: + cache['CFBundleSupportedPlatforms'] = ['iPhoneSimulator'] + XcodeSettings._plist_cache[configname] = cache + + # Include extra plist items that are per-target, not per global + # XcodeSettings. + items = dict(XcodeSettings._plist_cache[configname]) + if self.isIOS: + items['UIDeviceFamily'] = self._XcodeIOSDeviceFamily(configname) + return items + + def _DefaultSdkRoot(self): + """Returns the default SDKROOT to use. + + Prior to version 5.0.0, if SDKROOT was not explicitly set in the Xcode + project, then the environment variable was empty. Starting with this + version, Xcode uses the name of the newest SDK installed. + """ + xcode_version, xcode_build = XcodeVersion() + if xcode_version < '0500': + return '' + default_sdk_path = self._XcodeSdkPath('') + default_sdk_root = XcodeSettings._sdk_root_cache.get(default_sdk_path) + if default_sdk_root: + return default_sdk_root + try: + all_sdks = GetStdout(['xcodebuild', '-showsdks']) + except: + # If xcodebuild fails, there will be no valid SDKs + return '' + for line in all_sdks.splitlines(): + items = line.split() + if len(items) >= 3 and items[-2] == '-sdk': + sdk_root = items[-1] + sdk_path = self._XcodeSdkPath(sdk_root) + if sdk_path == default_sdk_path: + return sdk_root + return '' + + +class MacPrefixHeader(object): + """A class that helps with emulating Xcode's GCC_PREFIX_HEADER feature. + + This feature consists of several pieces: + * If GCC_PREFIX_HEADER is present, all compilations in that project get an + additional |-include path_to_prefix_header| cflag. + * If GCC_PRECOMPILE_PREFIX_HEADER is present too, then the prefix header is + instead compiled, and all other compilations in the project get an + additional |-include path_to_compiled_header| instead. + + Compiled prefix headers have the extension gch. There is one gch file for + every language used in the project (c, cc, m, mm), since gch files for + different languages aren't compatible. + + gch files themselves are built with the target's normal cflags, but they + obviously don't get the |-include| flag. Instead, they need a -x flag that + describes their language. + + All o files in the target need to depend on the gch file, to make sure + it's built before any o file is built. + + This class helps with some of these tasks, but it needs help from the build + system for writing dependencies to the gch files, for writing build commands + for the gch files, and for figuring out the location of the gch files. + """ + def __init__(self, xcode_settings, + gyp_path_to_build_path, gyp_path_to_build_output): + """If xcode_settings is None, all methods on this class are no-ops. + + Args: + gyp_path_to_build_path: A function that takes a gyp-relative path, + and returns a path relative to the build directory. + gyp_path_to_build_output: A function that takes a gyp-relative path and + a language code ('c', 'cc', 'm', or 'mm'), and that returns a path + to where the output of precompiling that path for that language + should be placed (without the trailing '.gch'). + """ + # This doesn't support per-configuration prefix headers. Good enough + # for now. + self.header = None + self.compile_headers = False + if xcode_settings: + self.header = xcode_settings.GetPerTargetSetting('GCC_PREFIX_HEADER') + self.compile_headers = xcode_settings.GetPerTargetSetting( + 'GCC_PRECOMPILE_PREFIX_HEADER', default='NO') != 'NO' + self.compiled_headers = {} + if self.header: + if self.compile_headers: + for lang in ['c', 'cc', 'm', 'mm']: + self.compiled_headers[lang] = gyp_path_to_build_output( + self.header, lang) + self.header = gyp_path_to_build_path(self.header) + + def _CompiledHeader(self, lang, arch): + assert self.compile_headers + h = self.compiled_headers[lang] + if arch: + h += '.' + arch + return h + + def GetInclude(self, lang, arch=None): + """Gets the cflags to include the prefix header for language |lang|.""" + if self.compile_headers and lang in self.compiled_headers: + return '-include %s' % self._CompiledHeader(lang, arch) + elif self.header: + return '-include %s' % self.header + else: + return '' + + def _Gch(self, lang, arch): + """Returns the actual file name of the prefix header for language |lang|.""" + assert self.compile_headers + return self._CompiledHeader(lang, arch) + '.gch' + + def GetObjDependencies(self, sources, objs, arch=None): + """Given a list of source files and the corresponding object files, returns + a list of (source, object, gch) tuples, where |gch| is the build-directory + relative path to the gch file each object file depends on. |compilable[i]| + has to be the source file belonging to |objs[i]|.""" + if not self.header or not self.compile_headers: + return [] + + result = [] + for source, obj in zip(sources, objs): + ext = os.path.splitext(source)[1] + lang = { + '.c': 'c', + '.cpp': 'cc', '.cc': 'cc', '.cxx': 'cc', + '.m': 'm', + '.mm': 'mm', + }.get(ext, None) + if lang: + result.append((source, obj, self._Gch(lang, arch))) + return result + + def GetPchBuildCommands(self, arch=None): + """Returns [(path_to_gch, language_flag, language, header)]. + |path_to_gch| and |header| are relative to the build directory. + """ + if not self.header or not self.compile_headers: + return [] + return [ + (self._Gch('c', arch), '-x c-header', 'c', self.header), + (self._Gch('cc', arch), '-x c++-header', 'cc', self.header), + (self._Gch('m', arch), '-x objective-c-header', 'm', self.header), + (self._Gch('mm', arch), '-x objective-c++-header', 'mm', self.header), + ] + + +def XcodeVersion(): + """Returns a tuple of version and build version of installed Xcode.""" + # `xcodebuild -version` output looks like + # Xcode 4.6.3 + # Build version 4H1503 + # or like + # Xcode 3.2.6 + # Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0 + # BuildVersion: 10M2518 + # Convert that to '0463', '4H1503'. + global XCODE_VERSION_CACHE + if XCODE_VERSION_CACHE: + return XCODE_VERSION_CACHE + try: + version_list = GetStdout(['xcodebuild', '-version']).splitlines() + # In some circumstances xcodebuild exits 0 but doesn't return + # the right results; for example, a user on 10.7 or 10.8 with + # a bogus path set via xcode-select + # In that case this may be a CLT-only install so fall back to + # checking that version. + if len(version_list) < 2: + raise GypError, "xcodebuild returned unexpected results" + except: + version = CLTVersion() + if version: + version = re.match('(\d\.\d\.?\d*)', version).groups()[0] + else: + raise GypError, "No Xcode or CLT version detected!" + # The CLT has no build information, so we return an empty string. + version_list = [version, ''] + version = version_list[0] + build = version_list[-1] + # Be careful to convert "4.2" to "0420": + version = version.split()[-1].replace('.', '') + version = (version + '0' * (3 - len(version))).zfill(4) + if build: + build = build.split()[-1] + XCODE_VERSION_CACHE = (version, build) + return XCODE_VERSION_CACHE + + +# This function ported from the logic in Homebrew's CLT version check +def CLTVersion(): + """Returns the version of command-line tools from pkgutil.""" + # pkgutil output looks like + # package-id: com.apple.pkg.CLTools_Executables + # version: 5.0.1.0.1.1382131676 + # volume: / + # location: / + # install-time: 1382544035 + # groups: com.apple.FindSystemFiles.pkg-group com.apple.DevToolsBoth.pkg-group com.apple.DevToolsNonRelocatableShared.pkg-group + STANDALONE_PKG_ID = "com.apple.pkg.DeveloperToolsCLILeo" + FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI" + MAVERICKS_PKG_ID = "com.apple.pkg.CLTools_Executables" + + regex = re.compile('version: (?P.+)') + for key in [MAVERICKS_PKG_ID, STANDALONE_PKG_ID, FROM_XCODE_PKG_ID]: + try: + output = GetStdout(['/usr/sbin/pkgutil', '--pkg-info', key]) + return re.search(regex, output).groupdict()['version'] + except: + continue + + +def GetStdout(cmdlist): + """Returns the content of standard output returned by invoking |cmdlist|. + Raises |GypError| if the command return with a non-zero return code.""" + job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE) + out = job.communicate()[0] + if job.returncode != 0: + sys.stderr.write(out + '\n') + raise GypError('Error %d running %s' % (job.returncode, cmdlist[0])) + return out.rstrip('\n') + + +def MergeGlobalXcodeSettingsToSpec(global_dict, spec): + """Merges the global xcode_settings dictionary into each configuration of the + target represented by spec. For keys that are both in the global and the local + xcode_settings dict, the local key gets precendence. + """ + # The xcode generator special-cases global xcode_settings and does something + # that amounts to merging in the global xcode_settings into each local + # xcode_settings dict. + global_xcode_settings = global_dict.get('xcode_settings', {}) + for config in spec['configurations'].values(): + if 'xcode_settings' in config: + new_settings = global_xcode_settings.copy() + new_settings.update(config['xcode_settings']) + config['xcode_settings'] = new_settings + + +def IsMacBundle(flavor, spec): + """Returns if |spec| should be treated as a bundle. + + Bundles are directories with a certain subdirectory structure, instead of + just a single file. Bundle rules do not produce a binary but also package + resources into that directory.""" + is_mac_bundle = (int(spec.get('mac_bundle', 0)) != 0 and flavor == 'mac') + if is_mac_bundle: + assert spec['type'] != 'none', ( + 'mac_bundle targets cannot have type none (target "%s")' % + spec['target_name']) + return is_mac_bundle + + +def GetMacBundleResources(product_dir, xcode_settings, resources): + """Yields (output, resource) pairs for every resource in |resources|. + Only call this for mac bundle targets. + + Args: + product_dir: Path to the directory containing the output bundle, + relative to the build directory. + xcode_settings: The XcodeSettings of the current target. + resources: A list of bundle resources, relative to the build directory. + """ + dest = os.path.join(product_dir, + xcode_settings.GetBundleResourceFolder()) + for res in resources: + output = dest + + # The make generator doesn't support it, so forbid it everywhere + # to keep the generators more interchangable. + assert ' ' not in res, ( + "Spaces in resource filenames not supported (%s)" % res) + + # Split into (path,file). + res_parts = os.path.split(res) + + # Now split the path into (prefix,maybe.lproj). + lproj_parts = os.path.split(res_parts[0]) + # If the resource lives in a .lproj bundle, add that to the destination. + if lproj_parts[1].endswith('.lproj'): + output = os.path.join(output, lproj_parts[1]) + + output = os.path.join(output, res_parts[1]) + # Compiled XIB files are referred to by .nib. + if output.endswith('.xib'): + output = os.path.splitext(output)[0] + '.nib' + # Compiled storyboard files are referred to by .storyboardc. + if output.endswith('.storyboard'): + output = os.path.splitext(output)[0] + '.storyboardc' + + yield output, res + + +def GetMacInfoPlist(product_dir, xcode_settings, gyp_path_to_build_path): + """Returns (info_plist, dest_plist, defines, extra_env), where: + * |info_plist| is the source plist path, relative to the + build directory, + * |dest_plist| is the destination plist path, relative to the + build directory, + * |defines| is a list of preprocessor defines (empty if the plist + shouldn't be preprocessed, + * |extra_env| is a dict of env variables that should be exported when + invoking |mac_tool copy-info-plist|. + + Only call this for mac bundle targets. + + Args: + product_dir: Path to the directory containing the output bundle, + relative to the build directory. + xcode_settings: The XcodeSettings of the current target. + gyp_to_build_path: A function that converts paths relative to the + current gyp file to paths relative to the build direcotry. + """ + info_plist = xcode_settings.GetPerTargetSetting('INFOPLIST_FILE') + if not info_plist: + return None, None, [], {} + + # The make generator doesn't support it, so forbid it everywhere + # to keep the generators more interchangable. + assert ' ' not in info_plist, ( + "Spaces in Info.plist filenames not supported (%s)" % info_plist) + + info_plist = gyp_path_to_build_path(info_plist) + + # If explicitly set to preprocess the plist, invoke the C preprocessor and + # specify any defines as -D flags. + if xcode_settings.GetPerTargetSetting( + 'INFOPLIST_PREPROCESS', default='NO') == 'YES': + # Create an intermediate file based on the path. + defines = shlex.split(xcode_settings.GetPerTargetSetting( + 'INFOPLIST_PREPROCESSOR_DEFINITIONS', default='')) + else: + defines = [] + + dest_plist = os.path.join(product_dir, xcode_settings.GetBundlePlistPath()) + extra_env = xcode_settings.GetPerTargetSettings() + + return info_plist, dest_plist, defines, extra_env + + +def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration, + additional_settings=None): + """Return the environment variables that Xcode would set. See + http://developer.apple.com/library/mac/#documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW153 + for a full list. + + Args: + xcode_settings: An XcodeSettings object. If this is None, this function + returns an empty dict. + built_products_dir: Absolute path to the built products dir. + srcroot: Absolute path to the source root. + configuration: The build configuration name. + additional_settings: An optional dict with more values to add to the + result. + """ + if not xcode_settings: return {} + + # This function is considered a friend of XcodeSettings, so let it reach into + # its implementation details. + spec = xcode_settings.spec + + # These are filled in on a as-needed basis. + env = { + 'BUILT_PRODUCTS_DIR' : built_products_dir, + 'CONFIGURATION' : configuration, + 'PRODUCT_NAME' : xcode_settings.GetProductName(), + # See /Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX\ Product\ Types.xcspec for FULL_PRODUCT_NAME + 'SRCROOT' : srcroot, + 'SOURCE_ROOT': '${SRCROOT}', + # This is not true for static libraries, but currently the env is only + # written for bundles: + 'TARGET_BUILD_DIR' : built_products_dir, + 'TEMP_DIR' : '${TMPDIR}', + } + if xcode_settings.GetPerConfigSetting('SDKROOT', configuration): + env['SDKROOT'] = xcode_settings._SdkPath(configuration) + else: + env['SDKROOT'] = '' + + if spec['type'] in ( + 'executable', 'static_library', 'shared_library', 'loadable_module'): + env['EXECUTABLE_NAME'] = xcode_settings.GetExecutableName() + env['EXECUTABLE_PATH'] = xcode_settings.GetExecutablePath() + env['FULL_PRODUCT_NAME'] = xcode_settings.GetFullProductName() + mach_o_type = xcode_settings.GetMachOType() + if mach_o_type: + env['MACH_O_TYPE'] = mach_o_type + env['PRODUCT_TYPE'] = xcode_settings.GetProductType() + if xcode_settings._IsBundle(): + env['CONTENTS_FOLDER_PATH'] = \ + xcode_settings.GetBundleContentsFolderPath() + env['UNLOCALIZED_RESOURCES_FOLDER_PATH'] = \ + xcode_settings.GetBundleResourceFolder() + env['INFOPLIST_PATH'] = xcode_settings.GetBundlePlistPath() + env['WRAPPER_NAME'] = xcode_settings.GetWrapperName() + + install_name = xcode_settings.GetInstallName() + if install_name: + env['LD_DYLIB_INSTALL_NAME'] = install_name + install_name_base = xcode_settings.GetInstallNameBase() + if install_name_base: + env['DYLIB_INSTALL_NAME_BASE'] = install_name_base + if XcodeVersion() >= '0500' and not env.get('SDKROOT'): + sdk_root = xcode_settings._SdkRoot(configuration) + if not sdk_root: + sdk_root = xcode_settings._XcodeSdkPath('') + env['SDKROOT'] = sdk_root + + if not additional_settings: + additional_settings = {} + else: + # Flatten lists to strings. + for k in additional_settings: + if not isinstance(additional_settings[k], str): + additional_settings[k] = ' '.join(additional_settings[k]) + additional_settings.update(env) + + for k in additional_settings: + additional_settings[k] = _NormalizeEnvVarReferences(additional_settings[k]) + + return additional_settings + + +def _NormalizeEnvVarReferences(str): + """Takes a string containing variable references in the form ${FOO}, $(FOO), + or $FOO, and returns a string with all variable references in the form ${FOO}. + """ + # $FOO -> ${FOO} + str = re.sub(r'\$([a-zA-Z_][a-zA-Z0-9_]*)', r'${\1}', str) + + # $(FOO) -> ${FOO} + matches = re.findall(r'(\$\(([a-zA-Z0-9\-_]+)\))', str) + for match in matches: + to_replace, variable = match + assert '$(' not in match, '$($(FOO)) variables not supported: ' + match + str = str.replace(to_replace, '${' + variable + '}') + + return str + + +def ExpandEnvVars(string, expansions): + """Expands ${VARIABLES}, $(VARIABLES), and $VARIABLES in string per the + expansions list. If the variable expands to something that references + another variable, this variable is expanded as well if it's in env -- + until no variables present in env are left.""" + for k, v in reversed(expansions): + string = string.replace('${' + k + '}', v) + string = string.replace('$(' + k + ')', v) + string = string.replace('$' + k, v) + return string + + +def _TopologicallySortedEnvVarKeys(env): + """Takes a dict |env| whose values are strings that can refer to other keys, + for example env['foo'] = '$(bar) and $(baz)'. Returns a list L of all keys of + env such that key2 is after key1 in L if env[key2] refers to env[key1]. + + Throws an Exception in case of dependency cycles. + """ + # Since environment variables can refer to other variables, the evaluation + # order is important. Below is the logic to compute the dependency graph + # and sort it. + regex = re.compile(r'\$\{([a-zA-Z0-9\-_]+)\}') + def GetEdges(node): + # Use a definition of edges such that user_of_variable -> used_varible. + # This happens to be easier in this case, since a variable's + # definition contains all variables it references in a single string. + # We can then reverse the result of the topological sort at the end. + # Since: reverse(topsort(DAG)) = topsort(reverse_edges(DAG)) + matches = set([v for v in regex.findall(env[node]) if v in env]) + for dependee in matches: + assert '${' not in dependee, 'Nested variables not supported: ' + dependee + return matches + + try: + # Topologically sort, and then reverse, because we used an edge definition + # that's inverted from the expected result of this function (see comment + # above). + order = gyp.common.TopologicallySorted(env.keys(), GetEdges) + order.reverse() + return order + except gyp.common.CycleError, e: + raise GypError( + 'Xcode environment variables are cyclically dependent: ' + str(e.nodes)) + + +def GetSortedXcodeEnv(xcode_settings, built_products_dir, srcroot, + configuration, additional_settings=None): + env = _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration, + additional_settings) + return [(key, env[key]) for key in _TopologicallySortedEnvVarKeys(env)] + + +def GetSpecPostbuildCommands(spec, quiet=False): + """Returns the list of postbuilds explicitly defined on |spec|, in a form + executable by a shell.""" + postbuilds = [] + for postbuild in spec.get('postbuilds', []): + if not quiet: + postbuilds.append('echo POSTBUILD\\(%s\\) %s' % ( + spec['target_name'], postbuild['postbuild_name'])) + postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action'])) + return postbuilds + + +def _HasIOSTarget(targets): + """Returns true if any target contains the iOS specific key + IPHONEOS_DEPLOYMENT_TARGET.""" + for target_dict in targets.values(): + for config in target_dict['configurations'].values(): + if config.get('xcode_settings', {}).get('IPHONEOS_DEPLOYMENT_TARGET'): + return True + return False + + +def _AddIOSDeviceConfigurations(targets): + """Clone all targets and append -iphoneos to the name. Configure these targets + to build for iOS devices and use correct architectures for those builds.""" + for target_dict in targets.itervalues(): + toolset = target_dict['toolset'] + configs = target_dict['configurations'] + for config_name, config_dict in dict(configs).iteritems(): + iphoneos_config_dict = copy.deepcopy(config_dict) + configs[config_name + '-iphoneos'] = iphoneos_config_dict + configs[config_name + '-iphonesimulator'] = config_dict + if toolset == 'target': + iphoneos_config_dict['xcode_settings']['SDKROOT'] = 'iphoneos' + return targets + +def CloneConfigurationForDeviceAndEmulator(target_dicts): + """If |target_dicts| contains any iOS targets, automatically create -iphoneos + targets for iOS device builds.""" + if _HasIOSTarget(target_dicts): + return _AddIOSDeviceConfigurations(target_dicts) + return target_dicts diff --git a/deps/gyp/pylib/gyp/xcode_ninja.py b/deps/gyp/pylib/gyp/xcode_ninja.py new file mode 100644 index 000000000..0e5a70c71 --- /dev/null +++ b/deps/gyp/pylib/gyp/xcode_ninja.py @@ -0,0 +1,257 @@ +# Copyright (c) 2014 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Xcode-ninja wrapper project file generator. + +This updates the data structures passed to the Xcode gyp generator to build +with ninja instead. The Xcode project itself is transformed into a list of +executable targets, each with a build step to build with ninja, and a target +with every source and resource file. This appears to sidestep some of the +major performance headaches experienced using complex projects and large number +of targets within Xcode. +""" + +import errno +import gyp.generator.ninja +import os +import re +import xml.sax.saxutils + + +def _WriteWorkspace(main_gyp, sources_gyp): + """ Create a workspace to wrap main and sources gyp paths. """ + (build_file_root, build_file_ext) = os.path.splitext(main_gyp) + workspace_path = build_file_root + '.xcworkspace' + try: + os.makedirs(workspace_path) + except OSError, e: + if e.errno != errno.EEXIST: + raise + output_string = '\n' + \ + '\n' + for gyp_name in [main_gyp, sources_gyp]: + name = os.path.splitext(os.path.basename(gyp_name))[0] + '.xcodeproj' + name = xml.sax.saxutils.quoteattr("group:" + name) + output_string += ' \n' % name + output_string += '\n' + + workspace_file = os.path.join(workspace_path, "contents.xcworkspacedata") + + try: + with open(workspace_file, 'r') as input_file: + input_string = input_file.read() + if input_string == output_string: + return + except IOError: + # Ignore errors if the file doesn't exist. + pass + + with open(workspace_file, 'w') as output_file: + output_file.write(output_string) + +def _TargetFromSpec(old_spec, params): + """ Create fake target for xcode-ninja wrapper. """ + # Determine ninja top level build dir (e.g. /path/to/out). + ninja_toplevel = None + jobs = 0 + if params: + options = params['options'] + ninja_toplevel = \ + os.path.join(options.toplevel_dir, + gyp.generator.ninja.ComputeOutputDir(params)) + jobs = params.get('generator_flags', {}).get('xcode_ninja_jobs', 0) + + target_name = old_spec.get('target_name') + product_name = old_spec.get('product_name', target_name) + + ninja_target = {} + ninja_target['target_name'] = target_name + ninja_target['product_name'] = product_name + ninja_target['toolset'] = old_spec.get('toolset') + ninja_target['default_configuration'] = old_spec.get('default_configuration') + ninja_target['configurations'] = {} + + # Tell Xcode to look in |ninja_toplevel| for build products. + new_xcode_settings = {} + if ninja_toplevel: + new_xcode_settings['CONFIGURATION_BUILD_DIR'] = \ + "%s/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)" % ninja_toplevel + + if 'configurations' in old_spec: + for config in old_spec['configurations'].iterkeys(): + old_xcode_settings = old_spec['configurations'][config]['xcode_settings'] + if 'IPHONEOS_DEPLOYMENT_TARGET' in old_xcode_settings: + new_xcode_settings['CODE_SIGNING_REQUIRED'] = "NO" + new_xcode_settings['IPHONEOS_DEPLOYMENT_TARGET'] = \ + old_xcode_settings['IPHONEOS_DEPLOYMENT_TARGET'] + ninja_target['configurations'][config] = {} + ninja_target['configurations'][config]['xcode_settings'] = \ + new_xcode_settings + + ninja_target['mac_bundle'] = old_spec.get('mac_bundle', 0) + ninja_target['type'] = old_spec['type'] + if ninja_toplevel: + ninja_target['actions'] = [ + { + 'action_name': 'Compile and copy %s via ninja' % target_name, + 'inputs': [], + 'outputs': [], + 'action': [ + 'env', + 'PATH=%s' % os.environ['PATH'], + 'ninja', + '-C', + new_xcode_settings['CONFIGURATION_BUILD_DIR'], + target_name, + ], + 'message': 'Compile and copy %s via ninja' % target_name, + }, + ] + if jobs > 0: + ninja_target['actions'][0]['action'].extend(('-j', jobs)) + return ninja_target + +def IsValidTargetForWrapper(target_extras, executable_target_pattern, spec): + """Limit targets for Xcode wrapper. + + Xcode sometimes performs poorly with too many targets, so only include + proper executable targets, with filters to customize. + Arguments: + target_extras: Regular expression to always add, matching any target. + executable_target_pattern: Regular expression limiting executable targets. + spec: Specifications for target. + """ + target_name = spec.get('target_name') + # Always include targets matching target_extras. + if target_extras is not None and re.search(target_extras, target_name): + return True + + # Otherwise just show executable targets. + if spec.get('type', '') == 'executable' and \ + spec.get('product_extension', '') != 'bundle': + + # If there is a filter and the target does not match, exclude the target. + if executable_target_pattern is not None: + if not re.search(executable_target_pattern, target_name): + return False + return True + return False + +def CreateWrapper(target_list, target_dicts, data, params): + """Initialize targets for the ninja wrapper. + + This sets up the necessary variables in the targets to generate Xcode projects + that use ninja as an external builder. + Arguments: + target_list: List of target pairs: 'base/base.gyp:base'. + target_dicts: Dict of target properties keyed on target pair. + data: Dict of flattened build files keyed on gyp path. + params: Dict of global options for gyp. + """ + orig_gyp = params['build_files'][0] + for gyp_name, gyp_dict in data.iteritems(): + if gyp_name == orig_gyp: + depth = gyp_dict['_DEPTH'] + + # Check for custom main gyp name, otherwise use the default CHROMIUM_GYP_FILE + # and prepend .ninja before the .gyp extension. + generator_flags = params.get('generator_flags', {}) + main_gyp = generator_flags.get('xcode_ninja_main_gyp', None) + if main_gyp is None: + (build_file_root, build_file_ext) = os.path.splitext(orig_gyp) + main_gyp = build_file_root + ".ninja" + build_file_ext + + # Create new |target_list|, |target_dicts| and |data| data structures. + new_target_list = [] + new_target_dicts = {} + new_data = {} + + # Set base keys needed for |data|. + new_data[main_gyp] = {} + new_data[main_gyp]['included_files'] = [] + new_data[main_gyp]['targets'] = [] + new_data[main_gyp]['xcode_settings'] = \ + data[orig_gyp].get('xcode_settings', {}) + + # Normally the xcode-ninja generator includes only valid executable targets. + # If |xcode_ninja_executable_target_pattern| is set, that list is reduced to + # executable targets that match the pattern. (Default all) + executable_target_pattern = \ + generator_flags.get('xcode_ninja_executable_target_pattern', None) + + # For including other non-executable targets, add the matching target name + # to the |xcode_ninja_target_pattern| regular expression. (Default none) + target_extras = generator_flags.get('xcode_ninja_target_pattern', None) + + for old_qualified_target in target_list: + spec = target_dicts[old_qualified_target] + if IsValidTargetForWrapper(target_extras, executable_target_pattern, spec): + # Add to new_target_list. + target_name = spec.get('target_name') + new_target_name = '%s:%s#target' % (main_gyp, target_name) + new_target_list.append(new_target_name) + + # Add to new_target_dicts. + new_target_dicts[new_target_name] = _TargetFromSpec(spec, params) + + # Add to new_data. + for old_target in data[old_qualified_target.split(':')[0]]['targets']: + if old_target['target_name'] == target_name: + new_data_target = {} + new_data_target['target_name'] = old_target['target_name'] + new_data_target['toolset'] = old_target['toolset'] + new_data[main_gyp]['targets'].append(new_data_target) + + # Create sources target. + sources_target_name = 'sources_for_indexing' + sources_target = _TargetFromSpec( + { 'target_name' : sources_target_name, + 'toolset': 'target', + 'default_configuration': 'Default', + 'mac_bundle': '0', + 'type': 'executable' + }, None) + + # Tell Xcode to look everywhere for headers. + sources_target['configurations'] = {'Default': { 'include_dirs': [ depth ] } } + + sources = [] + for target, target_dict in target_dicts.iteritems(): + base = os.path.dirname(target) + files = target_dict.get('sources', []) + \ + target_dict.get('mac_bundle_resources', []) + # Remove files starting with $. These are mostly intermediate files for the + # build system. + files = [ file for file in files if not file.startswith('$')] + + # Make sources relative to root build file. + relative_path = os.path.dirname(main_gyp) + sources += [ os.path.relpath(os.path.join(base, file), relative_path) + for file in files ] + + sources_target['sources'] = sorted(set(sources)) + + # Put sources_to_index in it's own gyp. + sources_gyp = \ + os.path.join(os.path.dirname(main_gyp), sources_target_name + ".gyp") + fully_qualified_target_name = \ + '%s:%s#target' % (sources_gyp, sources_target_name) + + # Add to new_target_list, new_target_dicts and new_data. + new_target_list.append(fully_qualified_target_name) + new_target_dicts[fully_qualified_target_name] = sources_target + new_data_target = {} + new_data_target['target_name'] = sources_target['target_name'] + new_data_target['_DEPTH'] = depth + new_data_target['toolset'] = "target" + new_data[sources_gyp] = {} + new_data[sources_gyp]['targets'] = [] + new_data[sources_gyp]['included_files'] = [] + new_data[sources_gyp]['xcode_settings'] = \ + data[orig_gyp].get('xcode_settings', {}) + new_data[sources_gyp]['targets'].append(new_data_target) + + # Write workspace to file. + _WriteWorkspace(main_gyp, sources_gyp) + return (new_target_list, new_target_dicts, new_data) diff --git a/deps/gyp/pylib/gyp/xcodeproj_file.py b/deps/gyp/pylib/gyp/xcodeproj_file.py new file mode 100644 index 000000000..fc40fcb2d --- /dev/null +++ b/deps/gyp/pylib/gyp/xcodeproj_file.py @@ -0,0 +1,2890 @@ +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Xcode project file generator. + +This module is both an Xcode project file generator and a documentation of the +Xcode project file format. Knowledge of the project file format was gained +based on extensive experience with Xcode, and by making changes to projects in +Xcode.app and observing the resultant changes in the associated project files. + +XCODE PROJECT FILES + +The generator targets the file format as written by Xcode 3.2 (specifically, +3.2.6), but past experience has taught that the format has not changed +significantly in the past several years, and future versions of Xcode are able +to read older project files. + +Xcode project files are "bundled": the project "file" from an end-user's +perspective is actually a directory with an ".xcodeproj" extension. The +project file from this module's perspective is actually a file inside this +directory, always named "project.pbxproj". This file contains a complete +description of the project and is all that is needed to use the xcodeproj. +Other files contained in the xcodeproj directory are simply used to store +per-user settings, such as the state of various UI elements in the Xcode +application. + +The project.pbxproj file is a property list, stored in a format almost +identical to the NeXTstep property list format. The file is able to carry +Unicode data, and is encoded in UTF-8. The root element in the property list +is a dictionary that contains several properties of minimal interest, and two +properties of immense interest. The most important property is a dictionary +named "objects". The entire structure of the project is represented by the +children of this property. The objects dictionary is keyed by unique 96-bit +values represented by 24 uppercase hexadecimal characters. Each value in the +objects dictionary is itself a dictionary, describing an individual object. + +Each object in the dictionary is a member of a class, which is identified by +the "isa" property of each object. A variety of classes are represented in a +project file. Objects can refer to other objects by ID, using the 24-character +hexadecimal object key. A project's objects form a tree, with a root object +of class PBXProject at the root. As an example, the PBXProject object serves +as parent to an XCConfigurationList object defining the build configurations +used in the project, a PBXGroup object serving as a container for all files +referenced in the project, and a list of target objects, each of which defines +a target in the project. There are several different types of target object, +such as PBXNativeTarget and PBXAggregateTarget. In this module, this +relationship is expressed by having each target type derive from an abstract +base named XCTarget. + +The project.pbxproj file's root dictionary also contains a property, sibling to +the "objects" dictionary, named "rootObject". The value of rootObject is a +24-character object key referring to the root PBXProject object in the +objects dictionary. + +In Xcode, every file used as input to a target or produced as a final product +of a target must appear somewhere in the hierarchy rooted at the PBXGroup +object referenced by the PBXProject's mainGroup property. A PBXGroup is +generally represented as a folder in the Xcode application. PBXGroups can +contain other PBXGroups as well as PBXFileReferences, which are pointers to +actual files. + +Each XCTarget contains a list of build phases, represented in this module by +the abstract base XCBuildPhase. Examples of concrete XCBuildPhase derivations +are PBXSourcesBuildPhase and PBXFrameworksBuildPhase, which correspond to the +"Compile Sources" and "Link Binary With Libraries" phases displayed in the +Xcode application. Files used as input to these phases (for example, source +files in the former case and libraries and frameworks in the latter) are +represented by PBXBuildFile objects, referenced by elements of "files" lists +in XCTarget objects. Each PBXBuildFile object refers to a PBXBuildFile +object as a "weak" reference: it does not "own" the PBXBuildFile, which is +owned by the root object's mainGroup or a descendant group. In most cases, the +layer of indirection between an XCBuildPhase and a PBXFileReference via a +PBXBuildFile appears extraneous, but there's actually one reason for this: +file-specific compiler flags are added to the PBXBuildFile object so as to +allow a single file to be a member of multiple targets while having distinct +compiler flags for each. These flags can be modified in the Xcode applciation +in the "Build" tab of a File Info window. + +When a project is open in the Xcode application, Xcode will rewrite it. As +such, this module is careful to adhere to the formatting used by Xcode, to +avoid insignificant changes appearing in the file when it is used in the +Xcode application. This will keep version control repositories happy, and +makes it possible to compare a project file used in Xcode to one generated by +this module to determine if any significant changes were made in the +application. + +Xcode has its own way of assigning 24-character identifiers to each object, +which is not duplicated here. Because the identifier only is only generated +once, when an object is created, and is then left unchanged, there is no need +to attempt to duplicate Xcode's behavior in this area. The generator is free +to select any identifier, even at random, to refer to the objects it creates, +and Xcode will retain those identifiers and use them when subsequently +rewriting the project file. However, the generator would choose new random +identifiers each time the project files are generated, leading to difficulties +comparing "used" project files to "pristine" ones produced by this module, +and causing the appearance of changes as every object identifier is changed +when updated projects are checked in to a version control repository. To +mitigate this problem, this module chooses identifiers in a more deterministic +way, by hashing a description of each object as well as its parent and ancestor +objects. This strategy should result in minimal "shift" in IDs as successive +generations of project files are produced. + +THIS MODULE + +This module introduces several classes, all derived from the XCObject class. +Nearly all of the "brains" are built into the XCObject class, which understands +how to create and modify objects, maintain the proper tree structure, compute +identifiers, and print objects. For the most part, classes derived from +XCObject need only provide a _schema class object, a dictionary that +expresses what properties objects of the class may contain. + +Given this structure, it's possible to build a minimal project file by creating +objects of the appropriate types and making the proper connections: + + config_list = XCConfigurationList() + group = PBXGroup() + project = PBXProject({'buildConfigurationList': config_list, + 'mainGroup': group}) + +With the project object set up, it can be added to an XCProjectFile object. +XCProjectFile is a pseudo-class in the sense that it is a concrete XCObject +subclass that does not actually correspond to a class type found in a project +file. Rather, it is used to represent the project file's root dictionary. +Printing an XCProjectFile will print the entire project file, including the +full "objects" dictionary. + + project_file = XCProjectFile({'rootObject': project}) + project_file.ComputeIDs() + project_file.Print() + +Xcode project files are always encoded in UTF-8. This module will accept +strings of either the str class or the unicode class. Strings of class str +are assumed to already be encoded in UTF-8. Obviously, if you're just using +ASCII, you won't encounter difficulties because ASCII is a UTF-8 subset. +Strings of class unicode are handled properly and encoded in UTF-8 when +a project file is output. +""" + +import gyp.common +import posixpath +import re +import struct +import sys + +# hashlib is supplied as of Python 2.5 as the replacement interface for sha +# and other secure hashes. In 2.6, sha is deprecated. Import hashlib if +# available, avoiding a deprecation warning under 2.6. Import sha otherwise, +# preserving 2.4 compatibility. +try: + import hashlib + _new_sha1 = hashlib.sha1 +except ImportError: + import sha + _new_sha1 = sha.new + + +# See XCObject._EncodeString. This pattern is used to determine when a string +# can be printed unquoted. Strings that match this pattern may be printed +# unquoted. Strings that do not match must be quoted and may be further +# transformed to be properly encoded. Note that this expression matches the +# characters listed with "+", for 1 or more occurrences: if a string is empty, +# it must not match this pattern, because it needs to be encoded as "". +_unquoted = re.compile('^[A-Za-z0-9$./_]+$') + +# Strings that match this pattern are quoted regardless of what _unquoted says. +# Oddly, Xcode will quote any string with a run of three or more underscores. +_quoted = re.compile('___') + +# This pattern should match any character that needs to be escaped by +# XCObject._EncodeString. See that function. +_escaped = re.compile('[\\\\"]|[\x00-\x1f]') + + +# Used by SourceTreeAndPathFromPath +_path_leading_variable = re.compile('^\$\((.*?)\)(/(.*))?$') + +def SourceTreeAndPathFromPath(input_path): + """Given input_path, returns a tuple with sourceTree and path values. + + Examples: + input_path (source_tree, output_path) + '$(VAR)/path' ('VAR', 'path') + '$(VAR)' ('VAR', None) + 'path' (None, 'path') + """ + + source_group_match = _path_leading_variable.match(input_path) + if source_group_match: + source_tree = source_group_match.group(1) + output_path = source_group_match.group(3) # This may be None. + else: + source_tree = None + output_path = input_path + + return (source_tree, output_path) + +def ConvertVariablesToShellSyntax(input_string): + return re.sub('\$\((.*?)\)', '${\\1}', input_string) + +class XCObject(object): + """The abstract base of all class types used in Xcode project files. + + Class variables: + _schema: A dictionary defining the properties of this class. The keys to + _schema are string property keys as used in project files. Values + are a list of four or five elements: + [ is_list, property_type, is_strong, is_required, default ] + is_list: True if the property described is a list, as opposed + to a single element. + property_type: The type to use as the value of the property, + or if is_list is True, the type to use for each + element of the value's list. property_type must + be an XCObject subclass, or one of the built-in + types str, int, or dict. + is_strong: If property_type is an XCObject subclass, is_strong + is True to assert that this class "owns," or serves + as parent, to the property value (or, if is_list is + True, values). is_strong must be False if + property_type is not an XCObject subclass. + is_required: True if the property is required for the class. + Note that is_required being True does not preclude + an empty string ("", in the case of property_type + str) or list ([], in the case of is_list True) from + being set for the property. + default: Optional. If is_requried is True, default may be set + to provide a default value for objects that do not supply + their own value. If is_required is True and default + is not provided, users of the class must supply their own + value for the property. + Note that although the values of the array are expressed in + boolean terms, subclasses provide values as integers to conserve + horizontal space. + _should_print_single_line: False in XCObject. Subclasses whose objects + should be written to the project file in the + alternate single-line format, such as + PBXFileReference and PBXBuildFile, should + set this to True. + _encode_transforms: Used by _EncodeString to encode unprintable characters. + The index into this list is the ordinal of the + character to transform; each value is a string + used to represent the character in the output. XCObject + provides an _encode_transforms list suitable for most + XCObject subclasses. + _alternate_encode_transforms: Provided for subclasses that wish to use + the alternate encoding rules. Xcode seems + to use these rules when printing objects in + single-line format. Subclasses that desire + this behavior should set _encode_transforms + to _alternate_encode_transforms. + _hashables: A list of XCObject subclasses that can be hashed by ComputeIDs + to construct this object's ID. Most classes that need custom + hashing behavior should do it by overriding Hashables, + but in some cases an object's parent may wish to push a + hashable value into its child, and it can do so by appending + to _hashables. + Attributes: + id: The object's identifier, a 24-character uppercase hexadecimal string. + Usually, objects being created should not set id until the entire + project file structure is built. At that point, UpdateIDs() should + be called on the root object to assign deterministic values for id to + each object in the tree. + parent: The object's parent. This is set by a parent XCObject when a child + object is added to it. + _properties: The object's property dictionary. An object's properties are + described by its class' _schema variable. + """ + + _schema = {} + _should_print_single_line = False + + # See _EncodeString. + _encode_transforms = [] + i = 0 + while i < ord(' '): + _encode_transforms.append('\\U%04x' % i) + i = i + 1 + _encode_transforms[7] = '\\a' + _encode_transforms[8] = '\\b' + _encode_transforms[9] = '\\t' + _encode_transforms[10] = '\\n' + _encode_transforms[11] = '\\v' + _encode_transforms[12] = '\\f' + _encode_transforms[13] = '\\n' + + _alternate_encode_transforms = list(_encode_transforms) + _alternate_encode_transforms[9] = chr(9) + _alternate_encode_transforms[10] = chr(10) + _alternate_encode_transforms[11] = chr(11) + + def __init__(self, properties=None, id=None, parent=None): + self.id = id + self.parent = parent + self._properties = {} + self._hashables = [] + self._SetDefaultsFromSchema() + self.UpdateProperties(properties) + + def __repr__(self): + try: + name = self.Name() + except NotImplementedError: + return '<%s at 0x%x>' % (self.__class__.__name__, id(self)) + return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self)) + + def Copy(self): + """Make a copy of this object. + + The new object will have its own copy of lists and dicts. Any XCObject + objects owned by this object (marked "strong") will be copied in the + new object, even those found in lists. If this object has any weak + references to other XCObjects, the same references are added to the new + object without making a copy. + """ + + that = self.__class__(id=self.id, parent=self.parent) + for key, value in self._properties.iteritems(): + is_strong = self._schema[key][2] + + if isinstance(value, XCObject): + if is_strong: + new_value = value.Copy() + new_value.parent = that + that._properties[key] = new_value + else: + that._properties[key] = value + elif isinstance(value, str) or isinstance(value, unicode) or \ + isinstance(value, int): + that._properties[key] = value + elif isinstance(value, list): + if is_strong: + # If is_strong is True, each element is an XCObject, so it's safe to + # call Copy. + that._properties[key] = [] + for item in value: + new_item = item.Copy() + new_item.parent = that + that._properties[key].append(new_item) + else: + that._properties[key] = value[:] + elif isinstance(value, dict): + # dicts are never strong. + if is_strong: + raise TypeError, 'Strong dict for key ' + key + ' in ' + \ + self.__class__.__name__ + else: + that._properties[key] = value.copy() + else: + raise TypeError, 'Unexpected type ' + value.__class__.__name__ + \ + ' for key ' + key + ' in ' + self.__class__.__name__ + + return that + + def Name(self): + """Return the name corresponding to an object. + + Not all objects necessarily need to be nameable, and not all that do have + a "name" property. Override as needed. + """ + + # If the schema indicates that "name" is required, try to access the + # property even if it doesn't exist. This will result in a KeyError + # being raised for the property that should be present, which seems more + # appropriate than NotImplementedError in this case. + if 'name' in self._properties or \ + ('name' in self._schema and self._schema['name'][3]): + return self._properties['name'] + + raise NotImplementedError, \ + self.__class__.__name__ + ' must implement Name' + + def Comment(self): + """Return a comment string for the object. + + Most objects just use their name as the comment, but PBXProject uses + different values. + + The returned comment is not escaped and does not have any comment marker + strings applied to it. + """ + + return self.Name() + + def Hashables(self): + hashables = [self.__class__.__name__] + + name = self.Name() + if name != None: + hashables.append(name) + + hashables.extend(self._hashables) + + return hashables + + def HashablesForChild(self): + return None + + def ComputeIDs(self, recursive=True, overwrite=True, seed_hash=None): + """Set "id" properties deterministically. + + An object's "id" property is set based on a hash of its class type and + name, as well as the class type and name of all ancestor objects. As + such, it is only advisable to call ComputeIDs once an entire project file + tree is built. + + If recursive is True, recurse into all descendant objects and update their + hashes. + + If overwrite is True, any existing value set in the "id" property will be + replaced. + """ + + def _HashUpdate(hash, data): + """Update hash with data's length and contents. + + If the hash were updated only with the value of data, it would be + possible for clowns to induce collisions by manipulating the names of + their objects. By adding the length, it's exceedingly less likely that + ID collisions will be encountered, intentionally or not. + """ + + hash.update(struct.pack('>i', len(data))) + hash.update(data) + + if seed_hash is None: + seed_hash = _new_sha1() + + hash = seed_hash.copy() + + hashables = self.Hashables() + assert len(hashables) > 0 + for hashable in hashables: + _HashUpdate(hash, hashable) + + if recursive: + hashables_for_child = self.HashablesForChild() + if hashables_for_child is None: + child_hash = hash + else: + assert len(hashables_for_child) > 0 + child_hash = seed_hash.copy() + for hashable in hashables_for_child: + _HashUpdate(child_hash, hashable) + + for child in self.Children(): + child.ComputeIDs(recursive, overwrite, child_hash) + + if overwrite or self.id is None: + # Xcode IDs are only 96 bits (24 hex characters), but a SHA-1 digest is + # is 160 bits. Instead of throwing out 64 bits of the digest, xor them + # into the portion that gets used. + assert hash.digest_size % 4 == 0 + digest_int_count = hash.digest_size / 4 + digest_ints = struct.unpack('>' + 'I' * digest_int_count, hash.digest()) + id_ints = [0, 0, 0] + for index in xrange(0, digest_int_count): + id_ints[index % 3] ^= digest_ints[index] + self.id = '%08X%08X%08X' % tuple(id_ints) + + def EnsureNoIDCollisions(self): + """Verifies that no two objects have the same ID. Checks all descendants. + """ + + ids = {} + descendants = self.Descendants() + for descendant in descendants: + if descendant.id in ids: + other = ids[descendant.id] + raise KeyError, \ + 'Duplicate ID %s, objects "%s" and "%s" in "%s"' % \ + (descendant.id, str(descendant._properties), + str(other._properties), self._properties['rootObject'].Name()) + ids[descendant.id] = descendant + + def Children(self): + """Returns a list of all of this object's owned (strong) children.""" + + children = [] + for property, attributes in self._schema.iteritems(): + (is_list, property_type, is_strong) = attributes[0:3] + if is_strong and property in self._properties: + if not is_list: + children.append(self._properties[property]) + else: + children.extend(self._properties[property]) + return children + + def Descendants(self): + """Returns a list of all of this object's descendants, including this + object. + """ + + children = self.Children() + descendants = [self] + for child in children: + descendants.extend(child.Descendants()) + return descendants + + def PBXProjectAncestor(self): + # The base case for recursion is defined at PBXProject.PBXProjectAncestor. + if self.parent: + return self.parent.PBXProjectAncestor() + return None + + def _EncodeComment(self, comment): + """Encodes a comment to be placed in the project file output, mimicing + Xcode behavior. + """ + + # This mimics Xcode behavior by wrapping the comment in "/*" and "*/". If + # the string already contains a "*/", it is turned into "(*)/". This keeps + # the file writer from outputting something that would be treated as the + # end of a comment in the middle of something intended to be entirely a + # comment. + + return '/* ' + comment.replace('*/', '(*)/') + ' */' + + def _EncodeTransform(self, match): + # This function works closely with _EncodeString. It will only be called + # by re.sub with match.group(0) containing a character matched by the + # the _escaped expression. + char = match.group(0) + + # Backslashes (\) and quotation marks (") are always replaced with a + # backslash-escaped version of the same. Everything else gets its + # replacement from the class' _encode_transforms array. + if char == '\\': + return '\\\\' + if char == '"': + return '\\"' + return self._encode_transforms[ord(char)] + + def _EncodeString(self, value): + """Encodes a string to be placed in the project file output, mimicing + Xcode behavior. + """ + + # Use quotation marks when any character outside of the range A-Z, a-z, 0-9, + # $ (dollar sign), . (period), and _ (underscore) is present. Also use + # quotation marks to represent empty strings. + # + # Escape " (double-quote) and \ (backslash) by preceding them with a + # backslash. + # + # Some characters below the printable ASCII range are encoded specially: + # 7 ^G BEL is encoded as "\a" + # 8 ^H BS is encoded as "\b" + # 11 ^K VT is encoded as "\v" + # 12 ^L NP is encoded as "\f" + # 127 ^? DEL is passed through as-is without escaping + # - In PBXFileReference and PBXBuildFile objects: + # 9 ^I HT is passed through as-is without escaping + # 10 ^J NL is passed through as-is without escaping + # 13 ^M CR is passed through as-is without escaping + # - In other objects: + # 9 ^I HT is encoded as "\t" + # 10 ^J NL is encoded as "\n" + # 13 ^M CR is encoded as "\n" rendering it indistinguishable from + # 10 ^J NL + # All other characters within the ASCII control character range (0 through + # 31 inclusive) are encoded as "\U001f" referring to the Unicode code point + # in hexadecimal. For example, character 14 (^N SO) is encoded as "\U000e". + # Characters above the ASCII range are passed through to the output encoded + # as UTF-8 without any escaping. These mappings are contained in the + # class' _encode_transforms list. + + if _unquoted.search(value) and not _quoted.search(value): + return value + + return '"' + _escaped.sub(self._EncodeTransform, value) + '"' + + def _XCPrint(self, file, tabs, line): + file.write('\t' * tabs + line) + + def _XCPrintableValue(self, tabs, value, flatten_list=False): + """Returns a representation of value that may be printed in a project file, + mimicing Xcode's behavior. + + _XCPrintableValue can handle str and int values, XCObjects (which are + made printable by returning their id property), and list and dict objects + composed of any of the above types. When printing a list or dict, and + _should_print_single_line is False, the tabs parameter is used to determine + how much to indent the lines corresponding to the items in the list or + dict. + + If flatten_list is True, single-element lists will be transformed into + strings. + """ + + printable = '' + comment = None + + if self._should_print_single_line: + sep = ' ' + element_tabs = '' + end_tabs = '' + else: + sep = '\n' + element_tabs = '\t' * (tabs + 1) + end_tabs = '\t' * tabs + + if isinstance(value, XCObject): + printable += value.id + comment = value.Comment() + elif isinstance(value, str): + printable += self._EncodeString(value) + elif isinstance(value, unicode): + printable += self._EncodeString(value.encode('utf-8')) + elif isinstance(value, int): + printable += str(value) + elif isinstance(value, list): + if flatten_list and len(value) <= 1: + if len(value) == 0: + printable += self._EncodeString('') + else: + printable += self._EncodeString(value[0]) + else: + printable = '(' + sep + for item in value: + printable += element_tabs + \ + self._XCPrintableValue(tabs + 1, item, flatten_list) + \ + ',' + sep + printable += end_tabs + ')' + elif isinstance(value, dict): + printable = '{' + sep + for item_key, item_value in sorted(value.iteritems()): + printable += element_tabs + \ + self._XCPrintableValue(tabs + 1, item_key, flatten_list) + ' = ' + \ + self._XCPrintableValue(tabs + 1, item_value, flatten_list) + ';' + \ + sep + printable += end_tabs + '}' + else: + raise TypeError, "Can't make " + value.__class__.__name__ + ' printable' + + if comment != None: + printable += ' ' + self._EncodeComment(comment) + + return printable + + def _XCKVPrint(self, file, tabs, key, value): + """Prints a key and value, members of an XCObject's _properties dictionary, + to file. + + tabs is an int identifying the indentation level. If the class' + _should_print_single_line variable is True, tabs is ignored and the + key-value pair will be followed by a space insead of a newline. + """ + + if self._should_print_single_line: + printable = '' + after_kv = ' ' + else: + printable = '\t' * tabs + after_kv = '\n' + + # Xcode usually prints remoteGlobalIDString values in PBXContainerItemProxy + # objects without comments. Sometimes it prints them with comments, but + # the majority of the time, it doesn't. To avoid unnecessary changes to + # the project file after Xcode opens it, don't write comments for + # remoteGlobalIDString. This is a sucky hack and it would certainly be + # cleaner to extend the schema to indicate whether or not a comment should + # be printed, but since this is the only case where the problem occurs and + # Xcode itself can't seem to make up its mind, the hack will suffice. + # + # Also see PBXContainerItemProxy._schema['remoteGlobalIDString']. + if key == 'remoteGlobalIDString' and isinstance(self, + PBXContainerItemProxy): + value_to_print = value.id + else: + value_to_print = value + + # PBXBuildFile's settings property is represented in the output as a dict, + # but a hack here has it represented as a string. Arrange to strip off the + # quotes so that it shows up in the output as expected. + if key == 'settings' and isinstance(self, PBXBuildFile): + strip_value_quotes = True + else: + strip_value_quotes = False + + # In another one-off, let's set flatten_list on buildSettings properties + # of XCBuildConfiguration objects, because that's how Xcode treats them. + if key == 'buildSettings' and isinstance(self, XCBuildConfiguration): + flatten_list = True + else: + flatten_list = False + + try: + printable_key = self._XCPrintableValue(tabs, key, flatten_list) + printable_value = self._XCPrintableValue(tabs, value_to_print, + flatten_list) + if strip_value_quotes and len(printable_value) > 1 and \ + printable_value[0] == '"' and printable_value[-1] == '"': + printable_value = printable_value[1:-1] + printable += printable_key + ' = ' + printable_value + ';' + after_kv + except TypeError, e: + gyp.common.ExceptionAppend(e, + 'while printing key "%s"' % key) + raise + + self._XCPrint(file, 0, printable) + + def Print(self, file=sys.stdout): + """Prints a reprentation of this object to file, adhering to Xcode output + formatting. + """ + + self.VerifyHasRequiredProperties() + + if self._should_print_single_line: + # When printing an object in a single line, Xcode doesn't put any space + # between the beginning of a dictionary (or presumably a list) and the + # first contained item, so you wind up with snippets like + # ...CDEF = {isa = PBXFileReference; fileRef = 0123... + # If it were me, I would have put a space in there after the opening + # curly, but I guess this is just another one of those inconsistencies + # between how Xcode prints PBXFileReference and PBXBuildFile objects as + # compared to other objects. Mimic Xcode's behavior here by using an + # empty string for sep. + sep = '' + end_tabs = 0 + else: + sep = '\n' + end_tabs = 2 + + # Start the object. For example, '\t\tPBXProject = {\n'. + self._XCPrint(file, 2, self._XCPrintableValue(2, self) + ' = {' + sep) + + # "isa" isn't in the _properties dictionary, it's an intrinsic property + # of the class which the object belongs to. Xcode always outputs "isa" + # as the first element of an object dictionary. + self._XCKVPrint(file, 3, 'isa', self.__class__.__name__) + + # The remaining elements of an object dictionary are sorted alphabetically. + for property, value in sorted(self._properties.iteritems()): + self._XCKVPrint(file, 3, property, value) + + # End the object. + self._XCPrint(file, end_tabs, '};\n') + + def UpdateProperties(self, properties, do_copy=False): + """Merge the supplied properties into the _properties dictionary. + + The input properties must adhere to the class schema or a KeyError or + TypeError exception will be raised. If adding an object of an XCObject + subclass and the schema indicates a strong relationship, the object's + parent will be set to this object. + + If do_copy is True, then lists, dicts, strong-owned XCObjects, and + strong-owned XCObjects in lists will be copied instead of having their + references added. + """ + + if properties is None: + return + + for property, value in properties.iteritems(): + # Make sure the property is in the schema. + if not property in self._schema: + raise KeyError, property + ' not in ' + self.__class__.__name__ + + # Make sure the property conforms to the schema. + (is_list, property_type, is_strong) = self._schema[property][0:3] + if is_list: + if value.__class__ != list: + raise TypeError, \ + property + ' of ' + self.__class__.__name__ + \ + ' must be list, not ' + value.__class__.__name__ + for item in value: + if not isinstance(item, property_type) and \ + not (item.__class__ == unicode and property_type == str): + # Accept unicode where str is specified. str is treated as + # UTF-8-encoded. + raise TypeError, \ + 'item of ' + property + ' of ' + self.__class__.__name__ + \ + ' must be ' + property_type.__name__ + ', not ' + \ + item.__class__.__name__ + elif not isinstance(value, property_type) and \ + not (value.__class__ == unicode and property_type == str): + # Accept unicode where str is specified. str is treated as + # UTF-8-encoded. + raise TypeError, \ + property + ' of ' + self.__class__.__name__ + ' must be ' + \ + property_type.__name__ + ', not ' + value.__class__.__name__ + + # Checks passed, perform the assignment. + if do_copy: + if isinstance(value, XCObject): + if is_strong: + self._properties[property] = value.Copy() + else: + self._properties[property] = value + elif isinstance(value, str) or isinstance(value, unicode) or \ + isinstance(value, int): + self._properties[property] = value + elif isinstance(value, list): + if is_strong: + # If is_strong is True, each element is an XCObject, so it's safe + # to call Copy. + self._properties[property] = [] + for item in value: + self._properties[property].append(item.Copy()) + else: + self._properties[property] = value[:] + elif isinstance(value, dict): + self._properties[property] = value.copy() + else: + raise TypeError, "Don't know how to copy a " + \ + value.__class__.__name__ + ' object for ' + \ + property + ' in ' + self.__class__.__name__ + else: + self._properties[property] = value + + # Set up the child's back-reference to this object. Don't use |value| + # any more because it may not be right if do_copy is true. + if is_strong: + if not is_list: + self._properties[property].parent = self + else: + for item in self._properties[property]: + item.parent = self + + def HasProperty(self, key): + return key in self._properties + + def GetProperty(self, key): + return self._properties[key] + + def SetProperty(self, key, value): + self.UpdateProperties({key: value}) + + def DelProperty(self, key): + if key in self._properties: + del self._properties[key] + + def AppendProperty(self, key, value): + # TODO(mark): Support ExtendProperty too (and make this call that)? + + # Schema validation. + if not key in self._schema: + raise KeyError, key + ' not in ' + self.__class__.__name__ + + (is_list, property_type, is_strong) = self._schema[key][0:3] + if not is_list: + raise TypeError, key + ' of ' + self.__class__.__name__ + ' must be list' + if not isinstance(value, property_type): + raise TypeError, 'item of ' + key + ' of ' + self.__class__.__name__ + \ + ' must be ' + property_type.__name__ + ', not ' + \ + value.__class__.__name__ + + # If the property doesn't exist yet, create a new empty list to receive the + # item. + if not key in self._properties: + self._properties[key] = [] + + # Set up the ownership link. + if is_strong: + value.parent = self + + # Store the item. + self._properties[key].append(value) + + def VerifyHasRequiredProperties(self): + """Ensure that all properties identified as required by the schema are + set. + """ + + # TODO(mark): A stronger verification mechanism is needed. Some + # subclasses need to perform validation beyond what the schema can enforce. + for property, attributes in self._schema.iteritems(): + (is_list, property_type, is_strong, is_required) = attributes[0:4] + if is_required and not property in self._properties: + raise KeyError, self.__class__.__name__ + ' requires ' + property + + def _SetDefaultsFromSchema(self): + """Assign object default values according to the schema. This will not + overwrite properties that have already been set.""" + + defaults = {} + for property, attributes in self._schema.iteritems(): + (is_list, property_type, is_strong, is_required) = attributes[0:4] + if is_required and len(attributes) >= 5 and \ + not property in self._properties: + default = attributes[4] + + defaults[property] = default + + if len(defaults) > 0: + # Use do_copy=True so that each new object gets its own copy of strong + # objects, lists, and dicts. + self.UpdateProperties(defaults, do_copy=True) + + +class XCHierarchicalElement(XCObject): + """Abstract base for PBXGroup and PBXFileReference. Not represented in a + project file.""" + + # TODO(mark): Do name and path belong here? Probably so. + # If path is set and name is not, name may have a default value. Name will + # be set to the basename of path, if the basename of path is different from + # the full value of path. If path is already just a leaf name, name will + # not be set. + _schema = XCObject._schema.copy() + _schema.update({ + 'comments': [0, str, 0, 0], + 'fileEncoding': [0, str, 0, 0], + 'includeInIndex': [0, int, 0, 0], + 'indentWidth': [0, int, 0, 0], + 'lineEnding': [0, int, 0, 0], + 'sourceTree': [0, str, 0, 1, ''], + 'tabWidth': [0, int, 0, 0], + 'usesTabs': [0, int, 0, 0], + 'wrapsLines': [0, int, 0, 0], + }) + + def __init__(self, properties=None, id=None, parent=None): + # super + XCObject.__init__(self, properties, id, parent) + if 'path' in self._properties and not 'name' in self._properties: + path = self._properties['path'] + name = posixpath.basename(path) + if name != '' and path != name: + self.SetProperty('name', name) + + if 'path' in self._properties and \ + (not 'sourceTree' in self._properties or \ + self._properties['sourceTree'] == ''): + # If the pathname begins with an Xcode variable like "$(SDKROOT)/", take + # the variable out and make the path be relative to that variable by + # assigning the variable name as the sourceTree. + (source_tree, path) = SourceTreeAndPathFromPath(self._properties['path']) + if source_tree != None: + self._properties['sourceTree'] = source_tree + if path != None: + self._properties['path'] = path + if source_tree != None and path is None and \ + not 'name' in self._properties: + # The path was of the form "$(SDKROOT)" with no path following it. + # This object is now relative to that variable, so it has no path + # attribute of its own. It does, however, keep a name. + del self._properties['path'] + self._properties['name'] = source_tree + + def Name(self): + if 'name' in self._properties: + return self._properties['name'] + elif 'path' in self._properties: + return self._properties['path'] + else: + # This happens in the case of the root PBXGroup. + return None + + def Hashables(self): + """Custom hashables for XCHierarchicalElements. + + XCHierarchicalElements are special. Generally, their hashes shouldn't + change if the paths don't change. The normal XCObject implementation of + Hashables adds a hashable for each object, which means that if + the hierarchical structure changes (possibly due to changes caused when + TakeOverOnlyChild runs and encounters slight changes in the hierarchy), + the hashes will change. For example, if a project file initially contains + a/b/f1 and a/b becomes collapsed into a/b, f1 will have a single parent + a/b. If someone later adds a/f2 to the project file, a/b can no longer be + collapsed, and f1 winds up with parent b and grandparent a. That would + be sufficient to change f1's hash. + + To counteract this problem, hashables for all XCHierarchicalElements except + for the main group (which has neither a name nor a path) are taken to be + just the set of path components. Because hashables are inherited from + parents, this provides assurance that a/b/f1 has the same set of hashables + whether its parent is b or a/b. + + The main group is a special case. As it is permitted to have no name or + path, it is permitted to use the standard XCObject hash mechanism. This + is not considered a problem because there can be only one main group. + """ + + if self == self.PBXProjectAncestor()._properties['mainGroup']: + # super + return XCObject.Hashables(self) + + hashables = [] + + # Put the name in first, ensuring that if TakeOverOnlyChild collapses + # children into a top-level group like "Source", the name always goes + # into the list of hashables without interfering with path components. + if 'name' in self._properties: + # Make it less likely for people to manipulate hashes by following the + # pattern of always pushing an object type value onto the list first. + hashables.append(self.__class__.__name__ + '.name') + hashables.append(self._properties['name']) + + # NOTE: This still has the problem that if an absolute path is encountered, + # including paths with a sourceTree, they'll still inherit their parents' + # hashables, even though the paths aren't relative to their parents. This + # is not expected to be much of a problem in practice. + path = self.PathFromSourceTreeAndPath() + if path != None: + components = path.split(posixpath.sep) + for component in components: + hashables.append(self.__class__.__name__ + '.path') + hashables.append(component) + + hashables.extend(self._hashables) + + return hashables + + def Compare(self, other): + # Allow comparison of these types. PBXGroup has the highest sort rank; + # PBXVariantGroup is treated as equal to PBXFileReference. + valid_class_types = { + PBXFileReference: 'file', + PBXGroup: 'group', + PBXVariantGroup: 'file', + } + self_type = valid_class_types[self.__class__] + other_type = valid_class_types[other.__class__] + + if self_type == other_type: + # If the two objects are of the same sort rank, compare their names. + return cmp(self.Name(), other.Name()) + + # Otherwise, sort groups before everything else. + if self_type == 'group': + return -1 + return 1 + + def CompareRootGroup(self, other): + # This function should be used only to compare direct children of the + # containing PBXProject's mainGroup. These groups should appear in the + # listed order. + # TODO(mark): "Build" is used by gyp.generator.xcode, perhaps the + # generator should have a way of influencing this list rather than having + # to hardcode for the generator here. + order = ['Source', 'Intermediates', 'Projects', 'Frameworks', 'Products', + 'Build'] + + # If the groups aren't in the listed order, do a name comparison. + # Otherwise, groups in the listed order should come before those that + # aren't. + self_name = self.Name() + other_name = other.Name() + self_in = isinstance(self, PBXGroup) and self_name in order + other_in = isinstance(self, PBXGroup) and other_name in order + if not self_in and not other_in: + return self.Compare(other) + if self_name in order and not other_name in order: + return -1 + if other_name in order and not self_name in order: + return 1 + + # If both groups are in the listed order, go by the defined order. + self_index = order.index(self_name) + other_index = order.index(other_name) + if self_index < other_index: + return -1 + if self_index > other_index: + return 1 + return 0 + + def PathFromSourceTreeAndPath(self): + # Turn the object's sourceTree and path properties into a single flat + # string of a form comparable to the path parameter. If there's a + # sourceTree property other than "", wrap it in $(...) for the + # comparison. + components = [] + if self._properties['sourceTree'] != '': + components.append('$(' + self._properties['sourceTree'] + ')') + if 'path' in self._properties: + components.append(self._properties['path']) + + if len(components) > 0: + return posixpath.join(*components) + + return None + + def FullPath(self): + # Returns a full path to self relative to the project file, or relative + # to some other source tree. Start with self, and walk up the chain of + # parents prepending their paths, if any, until no more parents are + # available (project-relative path) or until a path relative to some + # source tree is found. + xche = self + path = None + while isinstance(xche, XCHierarchicalElement) and \ + (path is None or \ + (not path.startswith('/') and not path.startswith('$'))): + this_path = xche.PathFromSourceTreeAndPath() + if this_path != None and path != None: + path = posixpath.join(this_path, path) + elif this_path != None: + path = this_path + xche = xche.parent + + return path + + +class PBXGroup(XCHierarchicalElement): + """ + Attributes: + _children_by_path: Maps pathnames of children of this PBXGroup to the + actual child XCHierarchicalElement objects. + _variant_children_by_name_and_path: Maps (name, path) tuples of + PBXVariantGroup children to the actual child PBXVariantGroup objects. + """ + + _schema = XCHierarchicalElement._schema.copy() + _schema.update({ + 'children': [1, XCHierarchicalElement, 1, 1, []], + 'name': [0, str, 0, 0], + 'path': [0, str, 0, 0], + }) + + def __init__(self, properties=None, id=None, parent=None): + # super + XCHierarchicalElement.__init__(self, properties, id, parent) + self._children_by_path = {} + self._variant_children_by_name_and_path = {} + for child in self._properties.get('children', []): + self._AddChildToDicts(child) + + def Hashables(self): + # super + hashables = XCHierarchicalElement.Hashables(self) + + # It is not sufficient to just rely on name and parent to build a unique + # hashable : a node could have two child PBXGroup sharing a common name. + # To add entropy the hashable is enhanced with the names of all its + # children. + for child in self._properties.get('children', []): + child_name = child.Name() + if child_name != None: + hashables.append(child_name) + + return hashables + + def HashablesForChild(self): + # To avoid a circular reference the hashables used to compute a child id do + # not include the child names. + return XCHierarchicalElement.Hashables(self) + + def _AddChildToDicts(self, child): + # Sets up this PBXGroup object's dicts to reference the child properly. + child_path = child.PathFromSourceTreeAndPath() + if child_path: + if child_path in self._children_by_path: + raise ValueError, 'Found multiple children with path ' + child_path + self._children_by_path[child_path] = child + + if isinstance(child, PBXVariantGroup): + child_name = child._properties.get('name', None) + key = (child_name, child_path) + if key in self._variant_children_by_name_and_path: + raise ValueError, 'Found multiple PBXVariantGroup children with ' + \ + 'name ' + str(child_name) + ' and path ' + \ + str(child_path) + self._variant_children_by_name_and_path[key] = child + + def AppendChild(self, child): + # Callers should use this instead of calling + # AppendProperty('children', child) directly because this function + # maintains the group's dicts. + self.AppendProperty('children', child) + self._AddChildToDicts(child) + + def GetChildByName(self, name): + # This is not currently optimized with a dict as GetChildByPath is because + # it has few callers. Most callers probably want GetChildByPath. This + # function is only useful to get children that have names but no paths, + # which is rare. The children of the main group ("Source", "Products", + # etc.) is pretty much the only case where this likely to come up. + # + # TODO(mark): Maybe this should raise an error if more than one child is + # present with the same name. + if not 'children' in self._properties: + return None + + for child in self._properties['children']: + if child.Name() == name: + return child + + return None + + def GetChildByPath(self, path): + if not path: + return None + + if path in self._children_by_path: + return self._children_by_path[path] + + return None + + def GetChildByRemoteObject(self, remote_object): + # This method is a little bit esoteric. Given a remote_object, which + # should be a PBXFileReference in another project file, this method will + # return this group's PBXReferenceProxy object serving as a local proxy + # for the remote PBXFileReference. + # + # This function might benefit from a dict optimization as GetChildByPath + # for some workloads, but profiling shows that it's not currently a + # problem. + if not 'children' in self._properties: + return None + + for child in self._properties['children']: + if not isinstance(child, PBXReferenceProxy): + continue + + container_proxy = child._properties['remoteRef'] + if container_proxy._properties['remoteGlobalIDString'] == remote_object: + return child + + return None + + def AddOrGetFileByPath(self, path, hierarchical): + """Returns an existing or new file reference corresponding to path. + + If hierarchical is True, this method will create or use the necessary + hierarchical group structure corresponding to path. Otherwise, it will + look in and create an item in the current group only. + + If an existing matching reference is found, it is returned, otherwise, a + new one will be created, added to the correct group, and returned. + + If path identifies a directory by virtue of carrying a trailing slash, + this method returns a PBXFileReference of "folder" type. If path + identifies a variant, by virtue of it identifying a file inside a directory + with an ".lproj" extension, this method returns a PBXVariantGroup + containing the variant named by path, and possibly other variants. For + all other paths, a "normal" PBXFileReference will be returned. + """ + + # Adding or getting a directory? Directories end with a trailing slash. + is_dir = False + if path.endswith('/'): + is_dir = True + path = posixpath.normpath(path) + if is_dir: + path = path + '/' + + # Adding or getting a variant? Variants are files inside directories + # with an ".lproj" extension. Xcode uses variants for localization. For + # a variant path/to/Language.lproj/MainMenu.nib, put a variant group named + # MainMenu.nib inside path/to, and give it a variant named Language. In + # this example, grandparent would be set to path/to and parent_root would + # be set to Language. + variant_name = None + parent = posixpath.dirname(path) + grandparent = posixpath.dirname(parent) + parent_basename = posixpath.basename(parent) + (parent_root, parent_ext) = posixpath.splitext(parent_basename) + if parent_ext == '.lproj': + variant_name = parent_root + if grandparent == '': + grandparent = None + + # Putting a directory inside a variant group is not currently supported. + assert not is_dir or variant_name is None + + path_split = path.split(posixpath.sep) + if len(path_split) == 1 or \ + ((is_dir or variant_name != None) and len(path_split) == 2) or \ + not hierarchical: + # The PBXFileReference or PBXVariantGroup will be added to or gotten from + # this PBXGroup, no recursion necessary. + if variant_name is None: + # Add or get a PBXFileReference. + file_ref = self.GetChildByPath(path) + if file_ref != None: + assert file_ref.__class__ == PBXFileReference + else: + file_ref = PBXFileReference({'path': path}) + self.AppendChild(file_ref) + else: + # Add or get a PBXVariantGroup. The variant group name is the same + # as the basename (MainMenu.nib in the example above). grandparent + # specifies the path to the variant group itself, and path_split[-2:] + # is the path of the specific variant relative to its group. + variant_group_name = posixpath.basename(path) + variant_group_ref = self.AddOrGetVariantGroupByNameAndPath( + variant_group_name, grandparent) + variant_path = posixpath.sep.join(path_split[-2:]) + variant_ref = variant_group_ref.GetChildByPath(variant_path) + if variant_ref != None: + assert variant_ref.__class__ == PBXFileReference + else: + variant_ref = PBXFileReference({'name': variant_name, + 'path': variant_path}) + variant_group_ref.AppendChild(variant_ref) + # The caller is interested in the variant group, not the specific + # variant file. + file_ref = variant_group_ref + return file_ref + else: + # Hierarchical recursion. Add or get a PBXGroup corresponding to the + # outermost path component, and then recurse into it, chopping off that + # path component. + next_dir = path_split[0] + group_ref = self.GetChildByPath(next_dir) + if group_ref != None: + assert group_ref.__class__ == PBXGroup + else: + group_ref = PBXGroup({'path': next_dir}) + self.AppendChild(group_ref) + return group_ref.AddOrGetFileByPath(posixpath.sep.join(path_split[1:]), + hierarchical) + + def AddOrGetVariantGroupByNameAndPath(self, name, path): + """Returns an existing or new PBXVariantGroup for name and path. + + If a PBXVariantGroup identified by the name and path arguments is already + present as a child of this object, it is returned. Otherwise, a new + PBXVariantGroup with the correct properties is created, added as a child, + and returned. + + This method will generally be called by AddOrGetFileByPath, which knows + when to create a variant group based on the structure of the pathnames + passed to it. + """ + + key = (name, path) + if key in self._variant_children_by_name_and_path: + variant_group_ref = self._variant_children_by_name_and_path[key] + assert variant_group_ref.__class__ == PBXVariantGroup + return variant_group_ref + + variant_group_properties = {'name': name} + if path != None: + variant_group_properties['path'] = path + variant_group_ref = PBXVariantGroup(variant_group_properties) + self.AppendChild(variant_group_ref) + + return variant_group_ref + + def TakeOverOnlyChild(self, recurse=False): + """If this PBXGroup has only one child and it's also a PBXGroup, take + it over by making all of its children this object's children. + + This function will continue to take over only children when those children + are groups. If there are three PBXGroups representing a, b, and c, with + c inside b and b inside a, and a and b have no other children, this will + result in a taking over both b and c, forming a PBXGroup for a/b/c. + + If recurse is True, this function will recurse into children and ask them + to collapse themselves by taking over only children as well. Assuming + an example hierarchy with files at a/b/c/d1, a/b/c/d2, and a/b/c/d3/e/f + (d1, d2, and f are files, the rest are groups), recursion will result in + a group for a/b/c containing a group for d3/e. + """ + + # At this stage, check that child class types are PBXGroup exactly, + # instead of using isinstance. The only subclass of PBXGroup, + # PBXVariantGroup, should not participate in reparenting in the same way: + # reparenting by merging different object types would be wrong. + while len(self._properties['children']) == 1 and \ + self._properties['children'][0].__class__ == PBXGroup: + # Loop to take over the innermost only-child group possible. + + child = self._properties['children'][0] + + # Assume the child's properties, including its children. Save a copy + # of this object's old properties, because they'll still be needed. + # This object retains its existing id and parent attributes. + old_properties = self._properties + self._properties = child._properties + self._children_by_path = child._children_by_path + + if not 'sourceTree' in self._properties or \ + self._properties['sourceTree'] == '': + # The child was relative to its parent. Fix up the path. Note that + # children with a sourceTree other than "" are not relative to + # their parents, so no path fix-up is needed in that case. + if 'path' in old_properties: + if 'path' in self._properties: + # Both the original parent and child have paths set. + self._properties['path'] = posixpath.join(old_properties['path'], + self._properties['path']) + else: + # Only the original parent has a path, use it. + self._properties['path'] = old_properties['path'] + if 'sourceTree' in old_properties: + # The original parent had a sourceTree set, use it. + self._properties['sourceTree'] = old_properties['sourceTree'] + + # If the original parent had a name set, keep using it. If the original + # parent didn't have a name but the child did, let the child's name + # live on. If the name attribute seems unnecessary now, get rid of it. + if 'name' in old_properties and old_properties['name'] != None and \ + old_properties['name'] != self.Name(): + self._properties['name'] = old_properties['name'] + if 'name' in self._properties and 'path' in self._properties and \ + self._properties['name'] == self._properties['path']: + del self._properties['name'] + + # Notify all children of their new parent. + for child in self._properties['children']: + child.parent = self + + # If asked to recurse, recurse. + if recurse: + for child in self._properties['children']: + if child.__class__ == PBXGroup: + child.TakeOverOnlyChild(recurse) + + def SortGroup(self): + self._properties['children'] = \ + sorted(self._properties['children'], cmp=lambda x,y: x.Compare(y)) + + # Recurse. + for child in self._properties['children']: + if isinstance(child, PBXGroup): + child.SortGroup() + + +class XCFileLikeElement(XCHierarchicalElement): + # Abstract base for objects that can be used as the fileRef property of + # PBXBuildFile. + + def PathHashables(self): + # A PBXBuildFile that refers to this object will call this method to + # obtain additional hashables specific to this XCFileLikeElement. Don't + # just use this object's hashables, they're not specific and unique enough + # on their own (without access to the parent hashables.) Instead, provide + # hashables that identify this object by path by getting its hashables as + # well as the hashables of ancestor XCHierarchicalElement objects. + + hashables = [] + xche = self + while xche != None and isinstance(xche, XCHierarchicalElement): + xche_hashables = xche.Hashables() + for index in xrange(0, len(xche_hashables)): + hashables.insert(index, xche_hashables[index]) + xche = xche.parent + return hashables + + +class XCContainerPortal(XCObject): + # Abstract base for objects that can be used as the containerPortal property + # of PBXContainerItemProxy. + pass + + +class XCRemoteObject(XCObject): + # Abstract base for objects that can be used as the remoteGlobalIDString + # property of PBXContainerItemProxy. + pass + + +class PBXFileReference(XCFileLikeElement, XCContainerPortal, XCRemoteObject): + _schema = XCFileLikeElement._schema.copy() + _schema.update({ + 'explicitFileType': [0, str, 0, 0], + 'lastKnownFileType': [0, str, 0, 0], + 'name': [0, str, 0, 0], + 'path': [0, str, 0, 1], + }) + + # Weird output rules for PBXFileReference. + _should_print_single_line = True + # super + _encode_transforms = XCFileLikeElement._alternate_encode_transforms + + def __init__(self, properties=None, id=None, parent=None): + # super + XCFileLikeElement.__init__(self, properties, id, parent) + if 'path' in self._properties and self._properties['path'].endswith('/'): + self._properties['path'] = self._properties['path'][:-1] + is_dir = True + else: + is_dir = False + + if 'path' in self._properties and \ + not 'lastKnownFileType' in self._properties and \ + not 'explicitFileType' in self._properties: + # TODO(mark): This is the replacement for a replacement for a quick hack. + # It is no longer incredibly sucky, but this list needs to be extended. + extension_map = { + 'a': 'archive.ar', + 'app': 'wrapper.application', + 'bdic': 'file', + 'bundle': 'wrapper.cfbundle', + 'c': 'sourcecode.c.c', + 'cc': 'sourcecode.cpp.cpp', + 'cpp': 'sourcecode.cpp.cpp', + 'css': 'text.css', + 'cxx': 'sourcecode.cpp.cpp', + 'dart': 'sourcecode', + 'dylib': 'compiled.mach-o.dylib', + 'framework': 'wrapper.framework', + 'gyp': 'sourcecode', + 'gypi': 'sourcecode', + 'h': 'sourcecode.c.h', + 'hxx': 'sourcecode.cpp.h', + 'icns': 'image.icns', + 'java': 'sourcecode.java', + 'js': 'sourcecode.javascript', + 'm': 'sourcecode.c.objc', + 'mm': 'sourcecode.cpp.objcpp', + 'nib': 'wrapper.nib', + 'o': 'compiled.mach-o.objfile', + 'pdf': 'image.pdf', + 'pl': 'text.script.perl', + 'plist': 'text.plist.xml', + 'pm': 'text.script.perl', + 'png': 'image.png', + 'py': 'text.script.python', + 'r': 'sourcecode.rez', + 'rez': 'sourcecode.rez', + 's': 'sourcecode.asm', + 'storyboard': 'file.storyboard', + 'strings': 'text.plist.strings', + 'ttf': 'file', + 'xcassets': 'folder.assetcatalog', + 'xcconfig': 'text.xcconfig', + 'xcdatamodel': 'wrapper.xcdatamodel', + 'xib': 'file.xib', + 'y': 'sourcecode.yacc', + } + + prop_map = { + 'dart': 'explicitFileType', + 'gyp': 'explicitFileType', + 'gypi': 'explicitFileType', + } + + if is_dir: + file_type = 'folder' + prop_name = 'lastKnownFileType' + else: + basename = posixpath.basename(self._properties['path']) + (root, ext) = posixpath.splitext(basename) + # Check the map using a lowercase extension. + # TODO(mark): Maybe it should try with the original case first and fall + # back to lowercase, in case there are any instances where case + # matters. There currently aren't. + if ext != '': + ext = ext[1:].lower() + + # TODO(mark): "text" is the default value, but "file" is appropriate + # for unrecognized files not containing text. Xcode seems to choose + # based on content. + file_type = extension_map.get(ext, 'text') + prop_name = prop_map.get(ext, 'lastKnownFileType') + + self._properties[prop_name] = file_type + + +class PBXVariantGroup(PBXGroup, XCFileLikeElement): + """PBXVariantGroup is used by Xcode to represent localizations.""" + # No additions to the schema relative to PBXGroup. + pass + + +# PBXReferenceProxy is also an XCFileLikeElement subclass. It is defined below +# because it uses PBXContainerItemProxy, defined below. + + +class XCBuildConfiguration(XCObject): + _schema = XCObject._schema.copy() + _schema.update({ + 'baseConfigurationReference': [0, PBXFileReference, 0, 0], + 'buildSettings': [0, dict, 0, 1, {}], + 'name': [0, str, 0, 1], + }) + + def HasBuildSetting(self, key): + return key in self._properties['buildSettings'] + + def GetBuildSetting(self, key): + return self._properties['buildSettings'][key] + + def SetBuildSetting(self, key, value): + # TODO(mark): If a list, copy? + self._properties['buildSettings'][key] = value + + def AppendBuildSetting(self, key, value): + if not key in self._properties['buildSettings']: + self._properties['buildSettings'][key] = [] + self._properties['buildSettings'][key].append(value) + + def DelBuildSetting(self, key): + if key in self._properties['buildSettings']: + del self._properties['buildSettings'][key] + + def SetBaseConfiguration(self, value): + self._properties['baseConfigurationReference'] = value + +class XCConfigurationList(XCObject): + # _configs is the default list of configurations. + _configs = [ XCBuildConfiguration({'name': 'Debug'}), + XCBuildConfiguration({'name': 'Release'}) ] + + _schema = XCObject._schema.copy() + _schema.update({ + 'buildConfigurations': [1, XCBuildConfiguration, 1, 1, _configs], + 'defaultConfigurationIsVisible': [0, int, 0, 1, 1], + 'defaultConfigurationName': [0, str, 0, 1, 'Release'], + }) + + def Name(self): + return 'Build configuration list for ' + \ + self.parent.__class__.__name__ + ' "' + self.parent.Name() + '"' + + def ConfigurationNamed(self, name): + """Convenience accessor to obtain an XCBuildConfiguration by name.""" + for configuration in self._properties['buildConfigurations']: + if configuration._properties['name'] == name: + return configuration + + raise KeyError, name + + def DefaultConfiguration(self): + """Convenience accessor to obtain the default XCBuildConfiguration.""" + return self.ConfigurationNamed(self._properties['defaultConfigurationName']) + + def HasBuildSetting(self, key): + """Determines the state of a build setting in all XCBuildConfiguration + child objects. + + If all child objects have key in their build settings, and the value is the + same in all child objects, returns 1. + + If no child objects have the key in their build settings, returns 0. + + If some, but not all, child objects have the key in their build settings, + or if any children have different values for the key, returns -1. + """ + + has = None + value = None + for configuration in self._properties['buildConfigurations']: + configuration_has = configuration.HasBuildSetting(key) + if has is None: + has = configuration_has + elif has != configuration_has: + return -1 + + if configuration_has: + configuration_value = configuration.GetBuildSetting(key) + if value is None: + value = configuration_value + elif value != configuration_value: + return -1 + + if not has: + return 0 + + return 1 + + def GetBuildSetting(self, key): + """Gets the build setting for key. + + All child XCConfiguration objects must have the same value set for the + setting, or a ValueError will be raised. + """ + + # TODO(mark): This is wrong for build settings that are lists. The list + # contents should be compared (and a list copy returned?) + + value = None + for configuration in self._properties['buildConfigurations']: + configuration_value = configuration.GetBuildSetting(key) + if value is None: + value = configuration_value + else: + if value != configuration_value: + raise ValueError, 'Variant values for ' + key + + return value + + def SetBuildSetting(self, key, value): + """Sets the build setting for key to value in all child + XCBuildConfiguration objects. + """ + + for configuration in self._properties['buildConfigurations']: + configuration.SetBuildSetting(key, value) + + def AppendBuildSetting(self, key, value): + """Appends value to the build setting for key, which is treated as a list, + in all child XCBuildConfiguration objects. + """ + + for configuration in self._properties['buildConfigurations']: + configuration.AppendBuildSetting(key, value) + + def DelBuildSetting(self, key): + """Deletes the build setting key from all child XCBuildConfiguration + objects. + """ + + for configuration in self._properties['buildConfigurations']: + configuration.DelBuildSetting(key) + + def SetBaseConfiguration(self, value): + """Sets the build configuration in all child XCBuildConfiguration objects. + """ + + for configuration in self._properties['buildConfigurations']: + configuration.SetBaseConfiguration(value) + + +class PBXBuildFile(XCObject): + _schema = XCObject._schema.copy() + _schema.update({ + 'fileRef': [0, XCFileLikeElement, 0, 1], + 'settings': [0, str, 0, 0], # hack, it's a dict + }) + + # Weird output rules for PBXBuildFile. + _should_print_single_line = True + _encode_transforms = XCObject._alternate_encode_transforms + + def Name(self): + # Example: "main.cc in Sources" + return self._properties['fileRef'].Name() + ' in ' + self.parent.Name() + + def Hashables(self): + # super + hashables = XCObject.Hashables(self) + + # It is not sufficient to just rely on Name() to get the + # XCFileLikeElement's name, because that is not a complete pathname. + # PathHashables returns hashables unique enough that no two + # PBXBuildFiles should wind up with the same set of hashables, unless + # someone adds the same file multiple times to the same target. That + # would be considered invalid anyway. + hashables.extend(self._properties['fileRef'].PathHashables()) + + return hashables + + +class XCBuildPhase(XCObject): + """Abstract base for build phase classes. Not represented in a project + file. + + Attributes: + _files_by_path: A dict mapping each path of a child in the files list by + path (keys) to the corresponding PBXBuildFile children (values). + _files_by_xcfilelikeelement: A dict mapping each XCFileLikeElement (keys) + to the corresponding PBXBuildFile children (values). + """ + + # TODO(mark): Some build phase types, like PBXShellScriptBuildPhase, don't + # actually have a "files" list. XCBuildPhase should not have "files" but + # another abstract subclass of it should provide this, and concrete build + # phase types that do have "files" lists should be derived from that new + # abstract subclass. XCBuildPhase should only provide buildActionMask and + # runOnlyForDeploymentPostprocessing, and not files or the various + # file-related methods and attributes. + + _schema = XCObject._schema.copy() + _schema.update({ + 'buildActionMask': [0, int, 0, 1, 0x7fffffff], + 'files': [1, PBXBuildFile, 1, 1, []], + 'runOnlyForDeploymentPostprocessing': [0, int, 0, 1, 0], + }) + + def __init__(self, properties=None, id=None, parent=None): + # super + XCObject.__init__(self, properties, id, parent) + + self._files_by_path = {} + self._files_by_xcfilelikeelement = {} + for pbxbuildfile in self._properties.get('files', []): + self._AddBuildFileToDicts(pbxbuildfile) + + def FileGroup(self, path): + # Subclasses must override this by returning a two-element tuple. The + # first item in the tuple should be the PBXGroup to which "path" should be + # added, either as a child or deeper descendant. The second item should + # be a boolean indicating whether files should be added into hierarchical + # groups or one single flat group. + raise NotImplementedError, \ + self.__class__.__name__ + ' must implement FileGroup' + + def _AddPathToDict(self, pbxbuildfile, path): + """Adds path to the dict tracking paths belonging to this build phase. + + If the path is already a member of this build phase, raises an exception. + """ + + if path in self._files_by_path: + raise ValueError, 'Found multiple build files with path ' + path + self._files_by_path[path] = pbxbuildfile + + def _AddBuildFileToDicts(self, pbxbuildfile, path=None): + """Maintains the _files_by_path and _files_by_xcfilelikeelement dicts. + + If path is specified, then it is the path that is being added to the + phase, and pbxbuildfile must contain either a PBXFileReference directly + referencing that path, or it must contain a PBXVariantGroup that itself + contains a PBXFileReference referencing the path. + + If path is not specified, either the PBXFileReference's path or the paths + of all children of the PBXVariantGroup are taken as being added to the + phase. + + If the path is already present in the phase, raises an exception. + + If the PBXFileReference or PBXVariantGroup referenced by pbxbuildfile + are already present in the phase, referenced by a different PBXBuildFile + object, raises an exception. This does not raise an exception when + a PBXFileReference or PBXVariantGroup reappear and are referenced by the + same PBXBuildFile that has already introduced them, because in the case + of PBXVariantGroup objects, they may correspond to multiple paths that are + not all added simultaneously. When this situation occurs, the path needs + to be added to _files_by_path, but nothing needs to change in + _files_by_xcfilelikeelement, and the caller should have avoided adding + the PBXBuildFile if it is already present in the list of children. + """ + + xcfilelikeelement = pbxbuildfile._properties['fileRef'] + + paths = [] + if path != None: + # It's best when the caller provides the path. + if isinstance(xcfilelikeelement, PBXVariantGroup): + paths.append(path) + else: + # If the caller didn't provide a path, there can be either multiple + # paths (PBXVariantGroup) or one. + if isinstance(xcfilelikeelement, PBXVariantGroup): + for variant in xcfilelikeelement._properties['children']: + paths.append(variant.FullPath()) + else: + paths.append(xcfilelikeelement.FullPath()) + + # Add the paths first, because if something's going to raise, the + # messages provided by _AddPathToDict are more useful owing to its + # having access to a real pathname and not just an object's Name(). + for a_path in paths: + self._AddPathToDict(pbxbuildfile, a_path) + + # If another PBXBuildFile references this XCFileLikeElement, there's a + # problem. + if xcfilelikeelement in self._files_by_xcfilelikeelement and \ + self._files_by_xcfilelikeelement[xcfilelikeelement] != pbxbuildfile: + raise ValueError, 'Found multiple build files for ' + \ + xcfilelikeelement.Name() + self._files_by_xcfilelikeelement[xcfilelikeelement] = pbxbuildfile + + def AppendBuildFile(self, pbxbuildfile, path=None): + # Callers should use this instead of calling + # AppendProperty('files', pbxbuildfile) directly because this function + # maintains the object's dicts. Better yet, callers can just call AddFile + # with a pathname and not worry about building their own PBXBuildFile + # objects. + self.AppendProperty('files', pbxbuildfile) + self._AddBuildFileToDicts(pbxbuildfile, path) + + def AddFile(self, path, settings=None): + (file_group, hierarchical) = self.FileGroup(path) + file_ref = file_group.AddOrGetFileByPath(path, hierarchical) + + if file_ref in self._files_by_xcfilelikeelement and \ + isinstance(file_ref, PBXVariantGroup): + # There's already a PBXBuildFile in this phase corresponding to the + # PBXVariantGroup. path just provides a new variant that belongs to + # the group. Add the path to the dict. + pbxbuildfile = self._files_by_xcfilelikeelement[file_ref] + self._AddBuildFileToDicts(pbxbuildfile, path) + else: + # Add a new PBXBuildFile to get file_ref into the phase. + if settings is None: + pbxbuildfile = PBXBuildFile({'fileRef': file_ref}) + else: + pbxbuildfile = PBXBuildFile({'fileRef': file_ref, 'settings': settings}) + self.AppendBuildFile(pbxbuildfile, path) + + +class PBXHeadersBuildPhase(XCBuildPhase): + # No additions to the schema relative to XCBuildPhase. + + def Name(self): + return 'Headers' + + def FileGroup(self, path): + return self.PBXProjectAncestor().RootGroupForPath(path) + + +class PBXResourcesBuildPhase(XCBuildPhase): + # No additions to the schema relative to XCBuildPhase. + + def Name(self): + return 'Resources' + + def FileGroup(self, path): + return self.PBXProjectAncestor().RootGroupForPath(path) + + +class PBXSourcesBuildPhase(XCBuildPhase): + # No additions to the schema relative to XCBuildPhase. + + def Name(self): + return 'Sources' + + def FileGroup(self, path): + return self.PBXProjectAncestor().RootGroupForPath(path) + + +class PBXFrameworksBuildPhase(XCBuildPhase): + # No additions to the schema relative to XCBuildPhase. + + def Name(self): + return 'Frameworks' + + def FileGroup(self, path): + (root, ext) = posixpath.splitext(path) + if ext != '': + ext = ext[1:].lower() + if ext == 'o': + # .o files are added to Xcode Frameworks phases, but conceptually aren't + # frameworks, they're more like sources or intermediates. Redirect them + # to show up in one of those other groups. + return self.PBXProjectAncestor().RootGroupForPath(path) + else: + return (self.PBXProjectAncestor().FrameworksGroup(), False) + + +class PBXShellScriptBuildPhase(XCBuildPhase): + _schema = XCBuildPhase._schema.copy() + _schema.update({ + 'inputPaths': [1, str, 0, 1, []], + 'name': [0, str, 0, 0], + 'outputPaths': [1, str, 0, 1, []], + 'shellPath': [0, str, 0, 1, '/bin/sh'], + 'shellScript': [0, str, 0, 1], + 'showEnvVarsInLog': [0, int, 0, 0], + }) + + def Name(self): + if 'name' in self._properties: + return self._properties['name'] + + return 'ShellScript' + + +class PBXCopyFilesBuildPhase(XCBuildPhase): + _schema = XCBuildPhase._schema.copy() + _schema.update({ + 'dstPath': [0, str, 0, 1], + 'dstSubfolderSpec': [0, int, 0, 1], + 'name': [0, str, 0, 0], + }) + + # path_tree_re matches "$(DIR)/path" or just "$(DIR)". Match group 1 is + # "DIR", match group 3 is "path" or None. + path_tree_re = re.compile('^\\$\\((.*)\\)(/(.*)|)$') + + # path_tree_to_subfolder maps names of Xcode variables to the associated + # dstSubfolderSpec property value used in a PBXCopyFilesBuildPhase object. + path_tree_to_subfolder = { + 'BUILT_PRODUCTS_DIR': 16, # Products Directory + # Other types that can be chosen via the Xcode UI. + # TODO(mark): Map Xcode variable names to these. + # : 1, # Wrapper + # : 6, # Executables: 6 + # : 7, # Resources + # : 15, # Java Resources + # : 10, # Frameworks + # : 11, # Shared Frameworks + # : 12, # Shared Support + # : 13, # PlugIns + } + + def Name(self): + if 'name' in self._properties: + return self._properties['name'] + + return 'CopyFiles' + + def FileGroup(self, path): + return self.PBXProjectAncestor().RootGroupForPath(path) + + def SetDestination(self, path): + """Set the dstSubfolderSpec and dstPath properties from path. + + path may be specified in the same notation used for XCHierarchicalElements, + specifically, "$(DIR)/path". + """ + + path_tree_match = self.path_tree_re.search(path) + if path_tree_match: + # Everything else needs to be relative to an Xcode variable. + path_tree = path_tree_match.group(1) + relative_path = path_tree_match.group(3) + + if path_tree in self.path_tree_to_subfolder: + subfolder = self.path_tree_to_subfolder[path_tree] + if relative_path is None: + relative_path = '' + else: + # The path starts with an unrecognized Xcode variable + # name like $(SRCROOT). Xcode will still handle this + # as an "absolute path" that starts with the variable. + subfolder = 0 + relative_path = path + elif path.startswith('/'): + # Special case. Absolute paths are in dstSubfolderSpec 0. + subfolder = 0 + relative_path = path[1:] + else: + raise ValueError, 'Can\'t use path %s in a %s' % \ + (path, self.__class__.__name__) + + self._properties['dstPath'] = relative_path + self._properties['dstSubfolderSpec'] = subfolder + + +class PBXBuildRule(XCObject): + _schema = XCObject._schema.copy() + _schema.update({ + 'compilerSpec': [0, str, 0, 1], + 'filePatterns': [0, str, 0, 0], + 'fileType': [0, str, 0, 1], + 'isEditable': [0, int, 0, 1, 1], + 'outputFiles': [1, str, 0, 1, []], + 'script': [0, str, 0, 0], + }) + + def Name(self): + # Not very inspired, but it's what Xcode uses. + return self.__class__.__name__ + + def Hashables(self): + # super + hashables = XCObject.Hashables(self) + + # Use the hashables of the weak objects that this object refers to. + hashables.append(self._properties['fileType']) + if 'filePatterns' in self._properties: + hashables.append(self._properties['filePatterns']) + return hashables + + +class PBXContainerItemProxy(XCObject): + # When referencing an item in this project file, containerPortal is the + # PBXProject root object of this project file. When referencing an item in + # another project file, containerPortal is a PBXFileReference identifying + # the other project file. + # + # When serving as a proxy to an XCTarget (in this project file or another), + # proxyType is 1. When serving as a proxy to a PBXFileReference (in another + # project file), proxyType is 2. Type 2 is used for references to the + # producs of the other project file's targets. + # + # Xcode is weird about remoteGlobalIDString. Usually, it's printed without + # a comment, indicating that it's tracked internally simply as a string, but + # sometimes it's printed with a comment (usually when the object is initially + # created), indicating that it's tracked as a project file object at least + # sometimes. This module always tracks it as an object, but contains a hack + # to prevent it from printing the comment in the project file output. See + # _XCKVPrint. + _schema = XCObject._schema.copy() + _schema.update({ + 'containerPortal': [0, XCContainerPortal, 0, 1], + 'proxyType': [0, int, 0, 1], + 'remoteGlobalIDString': [0, XCRemoteObject, 0, 1], + 'remoteInfo': [0, str, 0, 1], + }) + + def __repr__(self): + props = self._properties + name = '%s.gyp:%s' % (props['containerPortal'].Name(), props['remoteInfo']) + return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self)) + + def Name(self): + # Admittedly not the best name, but it's what Xcode uses. + return self.__class__.__name__ + + def Hashables(self): + # super + hashables = XCObject.Hashables(self) + + # Use the hashables of the weak objects that this object refers to. + hashables.extend(self._properties['containerPortal'].Hashables()) + hashables.extend(self._properties['remoteGlobalIDString'].Hashables()) + return hashables + + +class PBXTargetDependency(XCObject): + # The "target" property accepts an XCTarget object, and obviously not + # NoneType. But XCTarget is defined below, so it can't be put into the + # schema yet. The definition of PBXTargetDependency can't be moved below + # XCTarget because XCTarget's own schema references PBXTargetDependency. + # Python doesn't deal well with this circular relationship, and doesn't have + # a real way to do forward declarations. To work around, the type of + # the "target" property is reset below, after XCTarget is defined. + # + # At least one of "name" and "target" is required. + _schema = XCObject._schema.copy() + _schema.update({ + 'name': [0, str, 0, 0], + 'target': [0, None.__class__, 0, 0], + 'targetProxy': [0, PBXContainerItemProxy, 1, 1], + }) + + def __repr__(self): + name = self._properties.get('name') or self._properties['target'].Name() + return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self)) + + def Name(self): + # Admittedly not the best name, but it's what Xcode uses. + return self.__class__.__name__ + + def Hashables(self): + # super + hashables = XCObject.Hashables(self) + + # Use the hashables of the weak objects that this object refers to. + hashables.extend(self._properties['targetProxy'].Hashables()) + return hashables + + +class PBXReferenceProxy(XCFileLikeElement): + _schema = XCFileLikeElement._schema.copy() + _schema.update({ + 'fileType': [0, str, 0, 1], + 'path': [0, str, 0, 1], + 'remoteRef': [0, PBXContainerItemProxy, 1, 1], + }) + + +class XCTarget(XCRemoteObject): + # An XCTarget is really just an XCObject, the XCRemoteObject thing is just + # to allow PBXProject to be used in the remoteGlobalIDString property of + # PBXContainerItemProxy. + # + # Setting a "name" property at instantiation may also affect "productName", + # which may in turn affect the "PRODUCT_NAME" build setting in children of + # "buildConfigurationList". See __init__ below. + _schema = XCRemoteObject._schema.copy() + _schema.update({ + 'buildConfigurationList': [0, XCConfigurationList, 1, 1, + XCConfigurationList()], + 'buildPhases': [1, XCBuildPhase, 1, 1, []], + 'dependencies': [1, PBXTargetDependency, 1, 1, []], + 'name': [0, str, 0, 1], + 'productName': [0, str, 0, 1], + }) + + def __init__(self, properties=None, id=None, parent=None, + force_outdir=None, force_prefix=None, force_extension=None): + # super + XCRemoteObject.__init__(self, properties, id, parent) + + # Set up additional defaults not expressed in the schema. If a "name" + # property was supplied, set "productName" if it is not present. Also set + # the "PRODUCT_NAME" build setting in each configuration, but only if + # the setting is not present in any build configuration. + if 'name' in self._properties: + if not 'productName' in self._properties: + self.SetProperty('productName', self._properties['name']) + + if 'productName' in self._properties: + if 'buildConfigurationList' in self._properties: + configs = self._properties['buildConfigurationList'] + if configs.HasBuildSetting('PRODUCT_NAME') == 0: + configs.SetBuildSetting('PRODUCT_NAME', + self._properties['productName']) + configs.SetBuildSetting('COMBINE_HIDPI_IMAGES', 'YES') + + def AddDependency(self, other): + pbxproject = self.PBXProjectAncestor() + other_pbxproject = other.PBXProjectAncestor() + if pbxproject == other_pbxproject: + # Add a dependency to another target in the same project file. + container = PBXContainerItemProxy({'containerPortal': pbxproject, + 'proxyType': 1, + 'remoteGlobalIDString': other, + 'remoteInfo': other.Name()}) + dependency = PBXTargetDependency({'target': other, + 'targetProxy': container}) + self.AppendProperty('dependencies', dependency) + else: + # Add a dependency to a target in a different project file. + other_project_ref = \ + pbxproject.AddOrGetProjectReference(other_pbxproject)[1] + container = PBXContainerItemProxy({ + 'containerPortal': other_project_ref, + 'proxyType': 1, + 'remoteGlobalIDString': other, + 'remoteInfo': other.Name(), + }) + dependency = PBXTargetDependency({'name': other.Name(), + 'targetProxy': container}) + self.AppendProperty('dependencies', dependency) + + # Proxy all of these through to the build configuration list. + + def ConfigurationNamed(self, name): + return self._properties['buildConfigurationList'].ConfigurationNamed(name) + + def DefaultConfiguration(self): + return self._properties['buildConfigurationList'].DefaultConfiguration() + + def HasBuildSetting(self, key): + return self._properties['buildConfigurationList'].HasBuildSetting(key) + + def GetBuildSetting(self, key): + return self._properties['buildConfigurationList'].GetBuildSetting(key) + + def SetBuildSetting(self, key, value): + return self._properties['buildConfigurationList'].SetBuildSetting(key, \ + value) + + def AppendBuildSetting(self, key, value): + return self._properties['buildConfigurationList'].AppendBuildSetting(key, \ + value) + + def DelBuildSetting(self, key): + return self._properties['buildConfigurationList'].DelBuildSetting(key) + + +# Redefine the type of the "target" property. See PBXTargetDependency._schema +# above. +PBXTargetDependency._schema['target'][1] = XCTarget + + +class PBXNativeTarget(XCTarget): + # buildPhases is overridden in the schema to be able to set defaults. + # + # NOTE: Contrary to most objects, it is advisable to set parent when + # constructing PBXNativeTarget. A parent of an XCTarget must be a PBXProject + # object. A parent reference is required for a PBXNativeTarget during + # construction to be able to set up the target defaults for productReference, + # because a PBXBuildFile object must be created for the target and it must + # be added to the PBXProject's mainGroup hierarchy. + _schema = XCTarget._schema.copy() + _schema.update({ + 'buildPhases': [1, XCBuildPhase, 1, 1, + [PBXSourcesBuildPhase(), PBXFrameworksBuildPhase()]], + 'buildRules': [1, PBXBuildRule, 1, 1, []], + 'productReference': [0, PBXFileReference, 0, 1], + 'productType': [0, str, 0, 1], + }) + + # Mapping from Xcode product-types to settings. The settings are: + # filetype : used for explicitFileType in the project file + # prefix : the prefix for the file name + # suffix : the suffix for the filen ame + _product_filetypes = { + 'com.apple.product-type.application': ['wrapper.application', + '', '.app'], + 'com.apple.product-type.bundle': ['wrapper.cfbundle', + '', '.bundle'], + 'com.apple.product-type.framework': ['wrapper.framework', + '', '.framework'], + 'com.apple.product-type.library.dynamic': ['compiled.mach-o.dylib', + 'lib', '.dylib'], + 'com.apple.product-type.library.static': ['archive.ar', + 'lib', '.a'], + 'com.apple.product-type.tool': ['compiled.mach-o.executable', + '', ''], + 'com.apple.product-type.bundle.unit-test': ['wrapper.cfbundle', + '', '.xctest'], + 'com.googlecode.gyp.xcode.bundle': ['compiled.mach-o.dylib', + '', '.so'], + } + + def __init__(self, properties=None, id=None, parent=None, + force_outdir=None, force_prefix=None, force_extension=None): + # super + XCTarget.__init__(self, properties, id, parent) + + if 'productName' in self._properties and \ + 'productType' in self._properties and \ + not 'productReference' in self._properties and \ + self._properties['productType'] in self._product_filetypes: + products_group = None + pbxproject = self.PBXProjectAncestor() + if pbxproject != None: + products_group = pbxproject.ProductsGroup() + + if products_group != None: + (filetype, prefix, suffix) = \ + self._product_filetypes[self._properties['productType']] + # Xcode does not have a distinct type for loadable modules that are + # pure BSD targets (not in a bundle wrapper). GYP allows such modules + # to be specified by setting a target type to loadable_module without + # having mac_bundle set. These are mapped to the pseudo-product type + # com.googlecode.gyp.xcode.bundle. + # + # By picking up this special type and converting it to a dynamic + # library (com.apple.product-type.library.dynamic) with fix-ups, + # single-file loadable modules can be produced. + # + # MACH_O_TYPE is changed to mh_bundle to produce the proper file type + # (as opposed to mh_dylib). In order for linking to succeed, + # DYLIB_CURRENT_VERSION and DYLIB_COMPATIBILITY_VERSION must be + # cleared. They are meaningless for type mh_bundle. + # + # Finally, the .so extension is forcibly applied over the default + # (.dylib), unless another forced extension is already selected. + # .dylib is plainly wrong, and .bundle is used by loadable_modules in + # bundle wrappers (com.apple.product-type.bundle). .so seems an odd + # choice because it's used as the extension on many other systems that + # don't distinguish between linkable shared libraries and non-linkable + # loadable modules, but there's precedent: Python loadable modules on + # Mac OS X use an .so extension. + if self._properties['productType'] == 'com.googlecode.gyp.xcode.bundle': + self._properties['productType'] = \ + 'com.apple.product-type.library.dynamic' + self.SetBuildSetting('MACH_O_TYPE', 'mh_bundle') + self.SetBuildSetting('DYLIB_CURRENT_VERSION', '') + self.SetBuildSetting('DYLIB_COMPATIBILITY_VERSION', '') + if force_extension is None: + force_extension = suffix[1:] + + if self._properties['productType'] == \ + 'com.apple.product-type-bundle.unit.test': + if force_extension is None: + force_extension = suffix[1:] + + if force_extension is not None: + # If it's a wrapper (bundle), set WRAPPER_EXTENSION. + if filetype.startswith('wrapper.'): + self.SetBuildSetting('WRAPPER_EXTENSION', force_extension) + else: + # Extension override. + suffix = '.' + force_extension + self.SetBuildSetting('EXECUTABLE_EXTENSION', force_extension) + + if filetype.startswith('compiled.mach-o.executable'): + product_name = self._properties['productName'] + product_name += suffix + suffix = '' + self.SetProperty('productName', product_name) + self.SetBuildSetting('PRODUCT_NAME', product_name) + + # Xcode handles most prefixes based on the target type, however there + # are exceptions. If a "BSD Dynamic Library" target is added in the + # Xcode UI, Xcode sets EXECUTABLE_PREFIX. This check duplicates that + # behavior. + if force_prefix is not None: + prefix = force_prefix + if filetype.startswith('wrapper.'): + self.SetBuildSetting('WRAPPER_PREFIX', prefix) + else: + self.SetBuildSetting('EXECUTABLE_PREFIX', prefix) + + if force_outdir is not None: + self.SetBuildSetting('TARGET_BUILD_DIR', force_outdir) + + # TODO(tvl): Remove the below hack. + # http://code.google.com/p/gyp/issues/detail?id=122 + + # Some targets include the prefix in the target_name. These targets + # really should just add a product_name setting that doesn't include + # the prefix. For example: + # target_name = 'libevent', product_name = 'event' + # This check cleans up for them. + product_name = self._properties['productName'] + prefix_len = len(prefix) + if prefix_len and (product_name[:prefix_len] == prefix): + product_name = product_name[prefix_len:] + self.SetProperty('productName', product_name) + self.SetBuildSetting('PRODUCT_NAME', product_name) + + ref_props = { + 'explicitFileType': filetype, + 'includeInIndex': 0, + 'path': prefix + product_name + suffix, + 'sourceTree': 'BUILT_PRODUCTS_DIR', + } + file_ref = PBXFileReference(ref_props) + products_group.AppendChild(file_ref) + self.SetProperty('productReference', file_ref) + + def GetBuildPhaseByType(self, type): + if not 'buildPhases' in self._properties: + return None + + the_phase = None + for phase in self._properties['buildPhases']: + if isinstance(phase, type): + # Some phases may be present in multiples in a well-formed project file, + # but phases like PBXSourcesBuildPhase may only be present singly, and + # this function is intended as an aid to GetBuildPhaseByType. Loop + # over the entire list of phases and assert if more than one of the + # desired type is found. + assert the_phase is None + the_phase = phase + + return the_phase + + def HeadersPhase(self): + headers_phase = self.GetBuildPhaseByType(PBXHeadersBuildPhase) + if headers_phase is None: + headers_phase = PBXHeadersBuildPhase() + + # The headers phase should come before the resources, sources, and + # frameworks phases, if any. + insert_at = len(self._properties['buildPhases']) + for index in xrange(0, len(self._properties['buildPhases'])): + phase = self._properties['buildPhases'][index] + if isinstance(phase, PBXResourcesBuildPhase) or \ + isinstance(phase, PBXSourcesBuildPhase) or \ + isinstance(phase, PBXFrameworksBuildPhase): + insert_at = index + break + + self._properties['buildPhases'].insert(insert_at, headers_phase) + headers_phase.parent = self + + return headers_phase + + def ResourcesPhase(self): + resources_phase = self.GetBuildPhaseByType(PBXResourcesBuildPhase) + if resources_phase is None: + resources_phase = PBXResourcesBuildPhase() + + # The resources phase should come before the sources and frameworks + # phases, if any. + insert_at = len(self._properties['buildPhases']) + for index in xrange(0, len(self._properties['buildPhases'])): + phase = self._properties['buildPhases'][index] + if isinstance(phase, PBXSourcesBuildPhase) or \ + isinstance(phase, PBXFrameworksBuildPhase): + insert_at = index + break + + self._properties['buildPhases'].insert(insert_at, resources_phase) + resources_phase.parent = self + + return resources_phase + + def SourcesPhase(self): + sources_phase = self.GetBuildPhaseByType(PBXSourcesBuildPhase) + if sources_phase is None: + sources_phase = PBXSourcesBuildPhase() + self.AppendProperty('buildPhases', sources_phase) + + return sources_phase + + def FrameworksPhase(self): + frameworks_phase = self.GetBuildPhaseByType(PBXFrameworksBuildPhase) + if frameworks_phase is None: + frameworks_phase = PBXFrameworksBuildPhase() + self.AppendProperty('buildPhases', frameworks_phase) + + return frameworks_phase + + def AddDependency(self, other): + # super + XCTarget.AddDependency(self, other) + + static_library_type = 'com.apple.product-type.library.static' + shared_library_type = 'com.apple.product-type.library.dynamic' + framework_type = 'com.apple.product-type.framework' + if isinstance(other, PBXNativeTarget) and \ + 'productType' in self._properties and \ + self._properties['productType'] != static_library_type and \ + 'productType' in other._properties and \ + (other._properties['productType'] == static_library_type or \ + ((other._properties['productType'] == shared_library_type or \ + other._properties['productType'] == framework_type) and \ + ((not other.HasBuildSetting('MACH_O_TYPE')) or + other.GetBuildSetting('MACH_O_TYPE') != 'mh_bundle'))): + + file_ref = other.GetProperty('productReference') + + pbxproject = self.PBXProjectAncestor() + other_pbxproject = other.PBXProjectAncestor() + if pbxproject != other_pbxproject: + other_project_product_group = \ + pbxproject.AddOrGetProjectReference(other_pbxproject)[0] + file_ref = other_project_product_group.GetChildByRemoteObject(file_ref) + + self.FrameworksPhase().AppendProperty('files', + PBXBuildFile({'fileRef': file_ref})) + + +class PBXAggregateTarget(XCTarget): + pass + + +class PBXProject(XCContainerPortal): + # A PBXProject is really just an XCObject, the XCContainerPortal thing is + # just to allow PBXProject to be used in the containerPortal property of + # PBXContainerItemProxy. + """ + + Attributes: + path: "sample.xcodeproj". TODO(mark) Document me! + _other_pbxprojects: A dictionary, keyed by other PBXProject objects. Each + value is a reference to the dict in the + projectReferences list associated with the keyed + PBXProject. + """ + + _schema = XCContainerPortal._schema.copy() + _schema.update({ + 'attributes': [0, dict, 0, 0], + 'buildConfigurationList': [0, XCConfigurationList, 1, 1, + XCConfigurationList()], + 'compatibilityVersion': [0, str, 0, 1, 'Xcode 3.2'], + 'hasScannedForEncodings': [0, int, 0, 1, 1], + 'mainGroup': [0, PBXGroup, 1, 1, PBXGroup()], + 'projectDirPath': [0, str, 0, 1, ''], + 'projectReferences': [1, dict, 0, 0], + 'projectRoot': [0, str, 0, 1, ''], + 'targets': [1, XCTarget, 1, 1, []], + }) + + def __init__(self, properties=None, id=None, parent=None, path=None): + self.path = path + self._other_pbxprojects = {} + # super + return XCContainerPortal.__init__(self, properties, id, parent) + + def Name(self): + name = self.path + if name[-10:] == '.xcodeproj': + name = name[:-10] + return posixpath.basename(name) + + def Path(self): + return self.path + + def Comment(self): + return 'Project object' + + def Children(self): + # super + children = XCContainerPortal.Children(self) + + # Add children that the schema doesn't know about. Maybe there's a more + # elegant way around this, but this is the only case where we need to own + # objects in a dictionary (that is itself in a list), and three lines for + # a one-off isn't that big a deal. + if 'projectReferences' in self._properties: + for reference in self._properties['projectReferences']: + children.append(reference['ProductGroup']) + + return children + + def PBXProjectAncestor(self): + return self + + def _GroupByName(self, name): + if not 'mainGroup' in self._properties: + self.SetProperty('mainGroup', PBXGroup()) + + main_group = self._properties['mainGroup'] + group = main_group.GetChildByName(name) + if group is None: + group = PBXGroup({'name': name}) + main_group.AppendChild(group) + + return group + + # SourceGroup and ProductsGroup are created by default in Xcode's own + # templates. + def SourceGroup(self): + return self._GroupByName('Source') + + def ProductsGroup(self): + return self._GroupByName('Products') + + # IntermediatesGroup is used to collect source-like files that are generated + # by rules or script phases and are placed in intermediate directories such + # as DerivedSources. + def IntermediatesGroup(self): + return self._GroupByName('Intermediates') + + # FrameworksGroup and ProjectsGroup are top-level groups used to collect + # frameworks and projects. + def FrameworksGroup(self): + return self._GroupByName('Frameworks') + + def ProjectsGroup(self): + return self._GroupByName('Projects') + + def RootGroupForPath(self, path): + """Returns a PBXGroup child of this object to which path should be added. + + This method is intended to choose between SourceGroup and + IntermediatesGroup on the basis of whether path is present in a source + directory or an intermediates directory. For the purposes of this + determination, any path located within a derived file directory such as + PROJECT_DERIVED_FILE_DIR is treated as being in an intermediates + directory. + + The returned value is a two-element tuple. The first element is the + PBXGroup, and the second element specifies whether that group should be + organized hierarchically (True) or as a single flat list (False). + """ + + # TODO(mark): make this a class variable and bind to self on call? + # Also, this list is nowhere near exhaustive. + # INTERMEDIATE_DIR and SHARED_INTERMEDIATE_DIR are used by + # gyp.generator.xcode. There should probably be some way for that module + # to push the names in, rather than having to hard-code them here. + source_tree_groups = { + 'DERIVED_FILE_DIR': (self.IntermediatesGroup, True), + 'INTERMEDIATE_DIR': (self.IntermediatesGroup, True), + 'PROJECT_DERIVED_FILE_DIR': (self.IntermediatesGroup, True), + 'SHARED_INTERMEDIATE_DIR': (self.IntermediatesGroup, True), + } + + (source_tree, path) = SourceTreeAndPathFromPath(path) + if source_tree != None and source_tree in source_tree_groups: + (group_func, hierarchical) = source_tree_groups[source_tree] + group = group_func() + return (group, hierarchical) + + # TODO(mark): make additional choices based on file extension. + + return (self.SourceGroup(), True) + + def AddOrGetFileInRootGroup(self, path): + """Returns a PBXFileReference corresponding to path in the correct group + according to RootGroupForPath's heuristics. + + If an existing PBXFileReference for path exists, it will be returned. + Otherwise, one will be created and returned. + """ + + (group, hierarchical) = self.RootGroupForPath(path) + return group.AddOrGetFileByPath(path, hierarchical) + + def RootGroupsTakeOverOnlyChildren(self, recurse=False): + """Calls TakeOverOnlyChild for all groups in the main group.""" + + for group in self._properties['mainGroup']._properties['children']: + if isinstance(group, PBXGroup): + group.TakeOverOnlyChild(recurse) + + def SortGroups(self): + # Sort the children of the mainGroup (like "Source" and "Products") + # according to their defined order. + self._properties['mainGroup']._properties['children'] = \ + sorted(self._properties['mainGroup']._properties['children'], + cmp=lambda x,y: x.CompareRootGroup(y)) + + # Sort everything else by putting group before files, and going + # alphabetically by name within sections of groups and files. SortGroup + # is recursive. + for group in self._properties['mainGroup']._properties['children']: + if not isinstance(group, PBXGroup): + continue + + if group.Name() == 'Products': + # The Products group is a special case. Instead of sorting + # alphabetically, sort things in the order of the targets that + # produce the products. To do this, just build up a new list of + # products based on the targets. + products = [] + for target in self._properties['targets']: + if not isinstance(target, PBXNativeTarget): + continue + product = target._properties['productReference'] + # Make sure that the product is already in the products group. + assert product in group._properties['children'] + products.append(product) + + # Make sure that this process doesn't miss anything that was already + # in the products group. + assert len(products) == len(group._properties['children']) + group._properties['children'] = products + else: + group.SortGroup() + + def AddOrGetProjectReference(self, other_pbxproject): + """Add a reference to another project file (via PBXProject object) to this + one. + + Returns [ProductGroup, ProjectRef]. ProductGroup is a PBXGroup object in + this project file that contains a PBXReferenceProxy object for each + product of each PBXNativeTarget in the other project file. ProjectRef is + a PBXFileReference to the other project file. + + If this project file already references the other project file, the + existing ProductGroup and ProjectRef are returned. The ProductGroup will + still be updated if necessary. + """ + + if not 'projectReferences' in self._properties: + self._properties['projectReferences'] = [] + + product_group = None + project_ref = None + + if not other_pbxproject in self._other_pbxprojects: + # This project file isn't yet linked to the other one. Establish the + # link. + product_group = PBXGroup({'name': 'Products'}) + + # ProductGroup is strong. + product_group.parent = self + + # There's nothing unique about this PBXGroup, and if left alone, it will + # wind up with the same set of hashables as all other PBXGroup objects + # owned by the projectReferences list. Add the hashables of the + # remote PBXProject that it's related to. + product_group._hashables.extend(other_pbxproject.Hashables()) + + # The other project reports its path as relative to the same directory + # that this project's path is relative to. The other project's path + # is not necessarily already relative to this project. Figure out the + # pathname that this project needs to use to refer to the other one. + this_path = posixpath.dirname(self.Path()) + projectDirPath = self.GetProperty('projectDirPath') + if projectDirPath: + if posixpath.isabs(projectDirPath[0]): + this_path = projectDirPath + else: + this_path = posixpath.join(this_path, projectDirPath) + other_path = gyp.common.RelativePath(other_pbxproject.Path(), this_path) + + # ProjectRef is weak (it's owned by the mainGroup hierarchy). + project_ref = PBXFileReference({ + 'lastKnownFileType': 'wrapper.pb-project', + 'path': other_path, + 'sourceTree': 'SOURCE_ROOT', + }) + self.ProjectsGroup().AppendChild(project_ref) + + ref_dict = {'ProductGroup': product_group, 'ProjectRef': project_ref} + self._other_pbxprojects[other_pbxproject] = ref_dict + self.AppendProperty('projectReferences', ref_dict) + + # Xcode seems to sort this list case-insensitively + self._properties['projectReferences'] = \ + sorted(self._properties['projectReferences'], cmp=lambda x,y: + cmp(x['ProjectRef'].Name().lower(), + y['ProjectRef'].Name().lower())) + else: + # The link already exists. Pull out the relevnt data. + project_ref_dict = self._other_pbxprojects[other_pbxproject] + product_group = project_ref_dict['ProductGroup'] + project_ref = project_ref_dict['ProjectRef'] + + self._SetUpProductReferences(other_pbxproject, product_group, project_ref) + + return [product_group, project_ref] + + def _SetUpProductReferences(self, other_pbxproject, product_group, + project_ref): + # TODO(mark): This only adds references to products in other_pbxproject + # when they don't exist in this pbxproject. Perhaps it should also + # remove references from this pbxproject that are no longer present in + # other_pbxproject. Perhaps it should update various properties if they + # change. + for target in other_pbxproject._properties['targets']: + if not isinstance(target, PBXNativeTarget): + continue + + other_fileref = target._properties['productReference'] + if product_group.GetChildByRemoteObject(other_fileref) is None: + # Xcode sets remoteInfo to the name of the target and not the name + # of its product, despite this proxy being a reference to the product. + container_item = PBXContainerItemProxy({ + 'containerPortal': project_ref, + 'proxyType': 2, + 'remoteGlobalIDString': other_fileref, + 'remoteInfo': target.Name() + }) + # TODO(mark): Does sourceTree get copied straight over from the other + # project? Can the other project ever have lastKnownFileType here + # instead of explicitFileType? (Use it if so?) Can path ever be + # unset? (I don't think so.) Can other_fileref have name set, and + # does it impact the PBXReferenceProxy if so? These are the questions + # that perhaps will be answered one day. + reference_proxy = PBXReferenceProxy({ + 'fileType': other_fileref._properties['explicitFileType'], + 'path': other_fileref._properties['path'], + 'sourceTree': other_fileref._properties['sourceTree'], + 'remoteRef': container_item, + }) + + product_group.AppendChild(reference_proxy) + + def SortRemoteProductReferences(self): + # For each remote project file, sort the associated ProductGroup in the + # same order that the targets are sorted in the remote project file. This + # is the sort order used by Xcode. + + def CompareProducts(x, y, remote_products): + # x and y are PBXReferenceProxy objects. Go through their associated + # PBXContainerItem to get the remote PBXFileReference, which will be + # present in the remote_products list. + x_remote = x._properties['remoteRef']._properties['remoteGlobalIDString'] + y_remote = y._properties['remoteRef']._properties['remoteGlobalIDString'] + x_index = remote_products.index(x_remote) + y_index = remote_products.index(y_remote) + + # Use the order of each remote PBXFileReference in remote_products to + # determine the sort order. + return cmp(x_index, y_index) + + for other_pbxproject, ref_dict in self._other_pbxprojects.iteritems(): + # Build up a list of products in the remote project file, ordered the + # same as the targets that produce them. + remote_products = [] + for target in other_pbxproject._properties['targets']: + if not isinstance(target, PBXNativeTarget): + continue + remote_products.append(target._properties['productReference']) + + # Sort the PBXReferenceProxy children according to the list of remote + # products. + product_group = ref_dict['ProductGroup'] + product_group._properties['children'] = sorted( + product_group._properties['children'], + cmp=lambda x, y: CompareProducts(x, y, remote_products)) + + +class XCProjectFile(XCObject): + _schema = XCObject._schema.copy() + _schema.update({ + 'archiveVersion': [0, int, 0, 1, 1], + 'classes': [0, dict, 0, 1, {}], + 'objectVersion': [0, int, 0, 1, 46], + 'rootObject': [0, PBXProject, 1, 1], + }) + + def SetXcodeVersion(self, version): + version_to_object_version = { + '2.4': 45, + '3.0': 45, + '3.1': 45, + '3.2': 46, + } + if not version in version_to_object_version: + supported_str = ', '.join(sorted(version_to_object_version.keys())) + raise Exception( + 'Unsupported Xcode version %s (supported: %s)' % + ( version, supported_str ) ) + compatibility_version = 'Xcode %s' % version + self._properties['rootObject'].SetProperty('compatibilityVersion', + compatibility_version) + self.SetProperty('objectVersion', version_to_object_version[version]); + + def ComputeIDs(self, recursive=True, overwrite=True, hash=None): + # Although XCProjectFile is implemented here as an XCObject, it's not a + # proper object in the Xcode sense, and it certainly doesn't have its own + # ID. Pass through an attempt to update IDs to the real root object. + if recursive: + self._properties['rootObject'].ComputeIDs(recursive, overwrite, hash) + + def Print(self, file=sys.stdout): + self.VerifyHasRequiredProperties() + + # Add the special "objects" property, which will be caught and handled + # separately during printing. This structure allows a fairly standard + # loop do the normal printing. + self._properties['objects'] = {} + self._XCPrint(file, 0, '// !$*UTF8*$!\n') + if self._should_print_single_line: + self._XCPrint(file, 0, '{ ') + else: + self._XCPrint(file, 0, '{\n') + for property, value in sorted(self._properties.iteritems(), + cmp=lambda x, y: cmp(x, y)): + if property == 'objects': + self._PrintObjects(file) + else: + self._XCKVPrint(file, 1, property, value) + self._XCPrint(file, 0, '}\n') + del self._properties['objects'] + + def _PrintObjects(self, file): + if self._should_print_single_line: + self._XCPrint(file, 0, 'objects = {') + else: + self._XCPrint(file, 1, 'objects = {\n') + + objects_by_class = {} + for object in self.Descendants(): + if object == self: + continue + class_name = object.__class__.__name__ + if not class_name in objects_by_class: + objects_by_class[class_name] = [] + objects_by_class[class_name].append(object) + + for class_name in sorted(objects_by_class): + self._XCPrint(file, 0, '\n') + self._XCPrint(file, 0, '/* Begin ' + class_name + ' section */\n') + for object in sorted(objects_by_class[class_name], + cmp=lambda x, y: cmp(x.id, y.id)): + object.Print(file) + self._XCPrint(file, 0, '/* End ' + class_name + ' section */\n') + + if self._should_print_single_line: + self._XCPrint(file, 0, '}; ') + else: + self._XCPrint(file, 1, '};\n') diff --git a/deps/gyp/pylib/gyp/xml_fix.py b/deps/gyp/pylib/gyp/xml_fix.py new file mode 100644 index 000000000..5de848158 --- /dev/null +++ b/deps/gyp/pylib/gyp/xml_fix.py @@ -0,0 +1,69 @@ +# Copyright (c) 2011 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Applies a fix to CR LF TAB handling in xml.dom. + +Fixes this: http://code.google.com/p/chromium/issues/detail?id=76293 +Working around this: http://bugs.python.org/issue5752 +TODO(bradnelson): Consider dropping this when we drop XP support. +""" + + +import xml.dom.minidom + + +def _Replacement_write_data(writer, data, is_attrib=False): + """Writes datachars to writer.""" + data = data.replace("&", "&").replace("<", "<") + data = data.replace("\"", """).replace(">", ">") + if is_attrib: + data = data.replace( + "\r", " ").replace( + "\n", " ").replace( + "\t", " ") + writer.write(data) + + +def _Replacement_writexml(self, writer, indent="", addindent="", newl=""): + # indent = current indentation + # addindent = indentation to add to higher levels + # newl = newline string + writer.write(indent+"<" + self.tagName) + + attrs = self._get_attributes() + a_names = attrs.keys() + a_names.sort() + + for a_name in a_names: + writer.write(" %s=\"" % a_name) + _Replacement_write_data(writer, attrs[a_name].value, is_attrib=True) + writer.write("\"") + if self.childNodes: + writer.write(">%s" % newl) + for node in self.childNodes: + node.writexml(writer, indent + addindent, addindent, newl) + writer.write("%s%s" % (indent, self.tagName, newl)) + else: + writer.write("/>%s" % newl) + + +class XmlFix(object): + """Object to manage temporary patching of xml.dom.minidom.""" + + def __init__(self): + # Preserve current xml.dom.minidom functions. + self.write_data = xml.dom.minidom._write_data + self.writexml = xml.dom.minidom.Element.writexml + # Inject replacement versions of a function and a method. + xml.dom.minidom._write_data = _Replacement_write_data + xml.dom.minidom.Element.writexml = _Replacement_writexml + + def Cleanup(self): + if self.write_data: + xml.dom.minidom._write_data = self.write_data + xml.dom.minidom.Element.writexml = self.writexml + self.write_data = None + + def __del__(self): + self.Cleanup() diff --git a/deps/gyp/setup.py b/deps/gyp/setup.py new file mode 100755 index 000000000..75a42558d --- /dev/null +++ b/deps/gyp/setup.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Copyright (c) 2009 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from setuptools import setup + +setup( + name='gyp', + version='0.1', + description='Generate Your Projects', + author='Chromium Authors', + author_email='chromium-dev@googlegroups.com', + url='http://code.google.com/p/gyp', + package_dir = {'': 'pylib'}, + packages=['gyp', 'gyp.generator'], + entry_points = {'console_scripts': ['gyp=gyp:script_main'] } +) diff --git a/deps/run_gyp b/deps/run_gyp new file mode 100755 index 000000000..f25d50a5d --- /dev/null +++ b/deps/run_gyp @@ -0,0 +1,8 @@ +#!/usr/bin/env python +import sys +import os.path +sys.path.insert(1, os.path.join(os.path.dirname(sys.argv[0]), 'gyp', 'pylib')) +import gyp + +if __name__ == '__main__': + sys.exit(gyp.script_main()) diff --git a/docker/linux/Dockerfile b/docker/linux/Dockerfile new file mode 100644 index 000000000..0d23fe1e7 --- /dev/null +++ b/docker/linux/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:12.04 + +RUN apt-get update -y && \ + apt-get install -y build-essential git-core python-pip python-software-properties software-properties-common && \ + rm -rf /var/lib/apt/lists/* + +RUN add-apt-repository --yes ppa:ubuntu-toolchain-r/test && \ + add-apt-repository --yes ppa:boost-latest/ppa && \ + apt-get update -y && \ + apt-get -y install gcc-4.8 g++-4.8 curl zlib1g-dev automake gdb libtool xutils-dev make cmake pkg-config python-pip libboost1.55-dev libcurl4-openssl-dev libpng-dev libsqlite3-dev mesa-utils libxi-dev x11proto-randr-dev x11proto-xext-dev libxrandr-dev x11proto-xf86vidmode-dev libxxf86vm-dev libxcursor-dev libxinerama-dev xvfb llvm-3.4 && \ + pip install awscli + +RUN apt-get install -y imagemagick + +RUN useradd -ms /bin/bash mapbox + +USER mapbox +ENV HOME /home/mapbox +WORKDIR /home/mapbox diff --git a/docker/linux/run-clang.sh b/docker/linux/run-clang.sh new file mode 100644 index 000000000..cb9f6f417 --- /dev/null +++ b/docker/linux/run-clang.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +docker build \ + -t mapbox/gl-native:linux \ + docker/linux + +docker run \ + -i \ + -e "CXX=clang++" \ + -v `pwd`:/home/mapbox/build \ + -t mapbox/gl-native:linux \ + build/docker/linux/test.sh diff --git a/docker/linux/run-gcc.sh b/docker/linux/run-gcc.sh new file mode 100755 index 000000000..093771f1a --- /dev/null +++ b/docker/linux/run-gcc.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +docker build \ + -t mapbox/gl-native:linux \ + docker/linux + +docker run \ + -i \ + -e "CXX=g++" \ + -v `pwd`:/home/mapbox/build \ + -t mapbox/gl-native:linux \ + build/docker/linux/test.sh diff --git a/gyp/android.gyp b/gyp/android.gyp new file mode 100644 index 000000000..0a09edb6c --- /dev/null +++ b/gyp/android.gyp @@ -0,0 +1,5 @@ +{ + 'includes': [ + '../android/mapboxgl-app.gypi', + ], +} diff --git a/gyp/asset-fs.gypi b/gyp/asset-fs.gypi new file mode 100644 index 000000000..e84fabb62 --- /dev/null +++ b/gyp/asset-fs.gypi @@ -0,0 +1,70 @@ +{ + 'targets': [ + { 'target_name': 'asset-fs', + 'product_name': 'mbgl-asset-fs', + 'type': 'static_library', + 'standalone_static_library': 1, + 'hard_dependency': 1, + + 'sources': [ + '../platform/default/asset_request_fs.cpp', + ], + + 'include_dirs': [ + '../include', + '../src', + ], + + 'variables': { + 'cflags_cc': [ + '<@(libuv_cflags)', + '<@(boost_cflags)', + ], + 'ldflags': [ + '<@(libuv_ldflags)', + ], + 'libraries': [ + '<@(libuv_static_libs)', + ], + 'defines': [ + '-DMBGL_ASSET_FS' + ], + }, + + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ], + }, + }, { + 'cflags_cc': [ '<@(cflags_cc)' ], + }], + ], + + 'direct_dependent_settings': { + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'OTHER_CFLAGS': [ '<@(defines)' ], + 'OTHER_CPLUSPLUSFLAGS': [ '<@(defines)' ], + } + }, { + 'cflags': [ '<@(defines)' ], + 'cflags_cc': [ '<@(defines)' ], + }] + ], + }, + + 'link_settings': { + 'conditions': [ + ['OS == "mac"', { + 'libraries': [ '<@(libraries)' ], + 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] } + }, { + 'libraries': [ '<@(libraries)', '<@(ldflags)' ], + }] + ], + }, + }, + ], +} diff --git a/gyp/asset-zip.gypi b/gyp/asset-zip.gypi new file mode 100644 index 000000000..e8854734e --- /dev/null +++ b/gyp/asset-zip.gypi @@ -0,0 +1,80 @@ +{ + 'targets': [ + { 'target_name': 'asset-zip', + 'product_name': 'mbgl-asset-zip', + 'type': 'static_library', + 'standalone_static_library': 1, + 'hard_dependency': 1, + + 'sources': [ + '../platform/default/asset_request_zip.cpp', + '../platform/default/uv_zip.c', + ], + + 'include_dirs': [ + '../include', + '../src', + ], + + 'variables': { + 'cflags': [ + '<@(libuv_cflags)', + '<@(libzip_cflags)', + ], + 'cflags_cc': [ + '<@(libuv_cflags)', + '<@(libzip_cflags)', + '<@(boost_cflags)', + ], + 'ldflags': [ + '<@(libuv_ldflags)', + '<@(libzip_ldflags)', + ], + 'libraries': [ + '<@(libuv_static_libs)', + '<@(libzip_static_libs)', + ], + 'defines': [ + '-DMBGL_ASSET_ZIP' + ], + }, + + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'OTHER_CFLAGS': [ '<@(cflags)' ], + 'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ], + }, + }, { + 'cflags': [ '<@(cflags)' ], + 'cflags_cc': [ '<@(cflags_cc)' ], + }], + ], + + 'direct_dependent_settings': { + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'OTHER_CFLAGS': [ '<@(defines)' ], + 'OTHER_CPLUSPLUSFLAGS': [ '<@(defines)' ], + } + }, { + 'cflags': [ '<@(defines)' ], + 'cflags_cc': [ '<@(defines)' ], + }] + ], + }, + + 'link_settings': { + 'conditions': [ + ['OS == "mac"', { + 'libraries': [ '<@(libraries)' ], + 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] } + }, { + 'libraries': [ '<@(libraries)', '<@(ldflags)' ], + }] + ], + }, + }, + ], +} diff --git a/gyp/cache-sqlite.gypi b/gyp/cache-sqlite.gypi new file mode 100644 index 000000000..704dc490e --- /dev/null +++ b/gyp/cache-sqlite.gypi @@ -0,0 +1,63 @@ +{ + 'targets': [ + { 'target_name': 'cache-sqlite', + 'product_name': 'mbgl-cache-sqlite', + 'type': 'static_library', + 'standalone_static_library': 1, + 'hard_dependency': 1, + + 'sources': [ + '../platform/default/sqlite_cache.cpp', + '../platform/default/sqlite3.hpp', + '../platform/default/sqlite3.cpp', + ], + + 'include_dirs': [ + '../include', + '../src', + ], + + 'variables': { + 'cflags_cc': [ + '<@(libuv_cflags)', + '<@(sqlite_cflags)', + ], + 'ldflags': [ + '<@(libuv_ldflags)', + '<@(sqlite_ldflags)', + '<@(zlib_ldflags)', + ], + 'libraries': [ + '<@(libuv_static_libs)', + '<@(sqlite_static_libs)', + '<@(zlib_static_libs)', + ], + }, + + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ], + }, + }, { + 'cflags_cc': [ '<@(cflags_cc)' ], + }], + ], + + 'link_settings': { + 'conditions': [ + ['OS == "mac"', { + 'libraries': [ '<@(libraries)' ], + 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] } + }, { + 'libraries': [ '<@(libraries)', '<@(ldflags)' ], + }] + ], + }, + + 'direct_dependent_settings': { + 'include_dirs': [ '../include' ], + }, + }, + ], +} diff --git a/gyp/certificates.gypi b/gyp/certificates.gypi new file mode 100644 index 000000000..1d0c2acf8 --- /dev/null +++ b/gyp/certificates.gypi @@ -0,0 +1,12 @@ +{ + 'targets': [ + { 'target_name': 'copy_certificate_bundle', + 'type': 'none', + 'hard_dependency': 1, + 'copies': [{ + 'files': [ '../common/ca-bundle.crt' ], + 'destination': '<(PRODUCT_DIR)' + }], + }, + ] +} diff --git a/gyp/common.gypi b/gyp/common.gypi new file mode 100644 index 000000000..b44f69868 --- /dev/null +++ b/gyp/common.gypi @@ -0,0 +1,105 @@ +{ + 'variables': { + 'install_prefix%': '', + }, + 'target_defaults': { + 'default_configuration': 'Release', + 'conditions': [ + ['OS=="mac"', { + 'xcode_settings': { + 'CLANG_CXX_LIBRARY': 'libc++', + 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0', + 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', + 'GCC_ENABLE_CPP_RTTI': 'YES', + 'OTHER_CPLUSPLUSFLAGS': [ + '-std=c++1y', + '-Werror', + '-Wall', + '-Wextra', + '-Wshadow', + '-Wno-variadic-macros', + '-frtti', + '-fexceptions', + '${CFLAGS}', + ], + 'GCC_WARN_PEDANTIC': 'YES', + 'GCC_WARN_UNINITIALIZED_AUTOS': 'YES_AGGRESSIVE', + 'MACOSX_DEPLOYMENT_TARGET': '10.9', + }, + }, { + 'cflags_cc': [ + '-std=c++14', + '-Werror', + '-Wall', + '-Wextra', + '-Wshadow', + '-Wno-variadic-macros', + '-Wno-error=unused-parameter', + '-Wno-c++1y-extensions', + '-frtti', + '-fexceptions', + '${CFLAGS}', + ], + }], + ['OS=="linux"', { + 'cflags_cc': [ + '-Wno-unknown-pragmas', # We are using '#pragma mark', but it is only available on Darwin. + ], + }], + ], + 'target_conditions': [ + ['_type == "static_library"', { + 'conditions': [ + ['OS=="mac"', { + 'xcode_settings': { + 'OTHER_CPLUSPLUSFLAGS': [ '-fPIC' ], + 'SKIP_INSTALL': 'YES', + }, + }, { + 'cflags_cc': [ '-fPIC' ], + }], + ['host == "ios"', { + 'xcode_settings': { + 'SDKROOT': 'iphoneos', + 'SUPPORTED_PLATFORMS': 'iphonesimulator iphoneos', + 'IPHONEOS_DEPLOYMENT_TARGET': '7.0', + 'TARGETED_DEVICE_FAMILY': '1,2', + 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0', + 'CODE_SIGN_IDENTITY': 'iPhone Developer', + }, + 'configurations': { + 'Release': { + 'xcode_settings': { + 'ARCHS': [ "armv7", "armv7s", "arm64", "i386", "x86_64" ], + }, + }, + }, + }], + ], + }], + ], + 'configurations': { + 'Debug': { + 'cflags_cc': [ '-g', '-O0', '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common' ], + 'defines': [ 'DEBUG' ], + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '0', + 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES', + 'DEAD_CODE_STRIPPING': 'NO', + 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'NO', + 'OTHER_CPLUSPLUSFLAGS': [ '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common'] + } + }, + 'Release': { + 'cflags_cc': [ '-g', '-O3' ], + 'defines': [ 'NDEBUG' ], + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '3', + 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES', + 'DEAD_CODE_STRIPPING': 'NO', + 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'NO' + } + }, + }, + } +} diff --git a/gyp/core.gypi b/gyp/core.gypi new file mode 100644 index 000000000..f9b361032 --- /dev/null +++ b/gyp/core.gypi @@ -0,0 +1,79 @@ +{ + 'targets': [ + { 'target_name': 'core', + 'product_name': 'mbgl-core', + 'type': 'static_library', + 'standalone_static_library': 1, + 'hard_dependency': 1, + 'dependencies': [ + 'shaders', + 'version', + ], + + 'sources': [ + ' +#include + +// Forward definition of JNI types +typedef class _jclass* jclass; +typedef class _jstring* jstring; +typedef class _jobject* jobject; +typedef class _jlongArray* jlongArray; +typedef struct _jmethodID* jmethodID; +typedef struct _jfieldID* jfieldID; + +struct _JavaVM; +typedef _JavaVM JavaVM; + +struct _JNIEnv; +typedef _JNIEnv JNIEnv; + +namespace mbgl { +namespace android { + +extern JavaVM* theJVM; + +extern std::string cachePath; +extern std::string dataPath; +extern std::string apkPath; +extern std::string androidRelease; + +extern jmethodID onInvalidateId; +extern jmethodID onMapChangedId; +extern jmethodID onFpsChangedId; + +extern jclass latLngClass; +extern jmethodID latLngConstructorId; +extern jfieldID latLngLatitudeId; +extern jfieldID latLngLongitudeId; + +extern jclass latLngZoomClass; +extern jmethodID latLngZoomConstructorId; +extern jfieldID latLngZoomLatitudeId; +extern jfieldID latLngZoomLongitudeId; +extern jfieldID latLngZoomZoomId; + +extern jclass markerClass; +extern jmethodID markerConstructorId; +extern jfieldID markerPositionId; +extern jfieldID markerSpriteId; + +extern jclass polylineClass; +extern jmethodID polylineConstructorId; +extern jfieldID polylineAlphaId; +extern jfieldID polylineVisibleId; +extern jfieldID polylineColorId; +extern jfieldID polylineWidthId; +extern jfieldID polylinePointsId; + +extern jclass polygonClass; +extern jmethodID polygonConstructorId; +extern jfieldID polygonAlphaId; +extern jfieldID polygonVisibleId; +extern jfieldID polygonFillColorId; +extern jfieldID polygonStrokeColorId; +extern jfieldID polygonStrokeWidthId; +extern jfieldID polygonPointsId; +extern jfieldID polygonHolesId; + +extern jclass runtimeExceptionClass; +extern jclass nullPointerExceptionClass; + +extern jmethodID listToArrayId; + +extern jclass arrayListClass; +extern jmethodID arrayListConstructorId; +extern jmethodID arrayListAddId; + +extern jclass projectedMetersClass; +extern jmethodID projectedMetersConstructorId; +extern jfieldID projectedMetersNorthingId; +extern jfieldID projectedMetersEastingId; + +extern jclass pointFClass; +extern jmethodID pointFConstructorId; +extern jfieldID pointFXId; +extern jfieldID pointFYId; + +extern jclass httpContextClass; +extern jmethodID httpContextGetInstanceId; +extern jmethodID httpContextCreateRequestId; + +extern jclass httpRequestClass; +extern jmethodID httpRequestStartId; +extern jmethodID httpRequestCancelId; + +extern bool throw_jni_error(JNIEnv *env, const char *msg); +extern bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName); +extern void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach); +extern std::string std_string_from_jstring(JNIEnv *env, jstring jstr); +extern jstring std_string_to_jstring(JNIEnv *env, std::string str); +extern std::vector std_vector_string_from_jobject(JNIEnv *env, jobject jlist); +extern jobject std_vector_string_to_jobject(JNIEnv *env, std::vector vector); +extern jlongArray std_vector_uint_to_jobject(JNIEnv *env, std::vector vector); + +} +} + +#endif diff --git a/include/mbgl/android/native_map_view.hpp b/include/mbgl/android/native_map_view.hpp new file mode 100644 index 000000000..3ae3d6ed9 --- /dev/null +++ b/include/mbgl/android/native_map_view.hpp @@ -0,0 +1,101 @@ +#ifndef MBGL_ANDROID_NATIVE_MAP_VIEW +#define MBGL_ANDROID_NATIVE_MAP_VIEW + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace mbgl { +namespace android { + +class NativeMapView : public mbgl::View, private mbgl::util::noncopyable { +public: + NativeMapView(JNIEnv *env, jobject obj, float pixelRatio, int availableProcessors, size_t totalMemory); + virtual ~NativeMapView(); + + float getPixelRatio() const override; + std::array getSize() const override; + std::array getFramebufferSize() const override; + void activate() override; + void deactivate() override; + void notify() override; + void invalidate() override; + void swap() override; + + void notifyMapChange(mbgl::MapChange) override; + + mbgl::Map &getMap(); + mbgl::DefaultFileSource &getFileSource(); + + void initializeDisplay(); + void terminateDisplay(); + + void initializeContext(); + void terminateContext(); + + void createSurface(ANativeWindow *window); + void destroySurface(); + + void resume(); + void pause(); + + void enableFps(bool enable); + void updateFps(); + + void onInvalidate(); + + void resizeView(int width, int height); + void resizeFramebuffer(int width, int height); + +private: + EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs); + + bool inEmulator(); + +private: + JavaVM *vm = nullptr; + jobject obj = nullptr; + + ANativeWindow *window = nullptr; + EGLDisplay display = EGL_NO_DISPLAY; + EGLSurface surface = EGL_NO_SURFACE; + EGLContext context = EGL_NO_CONTEXT; + + EGLConfig config = nullptr; + EGLint format = -1; + + std::string styleUrl; + std::string apiKey; + + bool firstTime = false; + + bool fpsEnabled = false; + double fps = 0.0; + + int width = 0; + int height = 0; + int fbWidth = 0; + int fbHeight = 0; + const float pixelRatio; + + int availableProcessors = 0; + size_t totalMemory = 0; + + // Ensure these are initialised last + mbgl::SQLiteCache fileCache; + mbgl::DefaultFileSource fileSource; + mbgl::Map map; + + std::atomic_flag clean = ATOMIC_FLAG_INIT; +}; +} +} + +#endif diff --git a/include/mbgl/annotation/point_annotation.hpp b/include/mbgl/annotation/point_annotation.hpp new file mode 100644 index 000000000..17b6fe536 --- /dev/null +++ b/include/mbgl/annotation/point_annotation.hpp @@ -0,0 +1,22 @@ +#ifndef MBGL_ANNOTATION_POINT_ANNOTATION +#define MBGL_ANNOTATION_POINT_ANNOTATION + +#include + +#include + +namespace mbgl { + +class PointAnnotation { +public: + inline PointAnnotation(const LatLng& position_, const std::string& icon_ = "") + : position(position_), icon(icon_) { + } + + const LatLng position; + const std::string icon; +}; + +} + +#endif diff --git a/include/mbgl/annotation/shape_annotation.hpp b/include/mbgl/annotation/shape_annotation.hpp new file mode 100644 index 000000000..a35b86726 --- /dev/null +++ b/include/mbgl/annotation/shape_annotation.hpp @@ -0,0 +1,24 @@ +#ifndef MBGL_ANNOTATION_SHAPE_ANNOTATION +#define MBGL_ANNOTATION_SHAPE_ANNOTATION + +#include +#include +#include + +#include + +namespace mbgl { + +class ShapeAnnotation { +public: + inline ShapeAnnotation(const AnnotationSegments& segments_, const StyleProperties& styleProperties_) + : segments(segments_), styleProperties(styleProperties_) { + } + + const AnnotationSegments segments; + const StyleProperties styleProperties; +}; + +} + +#endif diff --git a/include/mbgl/annotation/sprite_image.hpp b/include/mbgl/annotation/sprite_image.hpp new file mode 100644 index 000000000..7d8ea0501 --- /dev/null +++ b/include/mbgl/annotation/sprite_image.hpp @@ -0,0 +1,40 @@ +#ifndef MBGL_ANNOTATIONS_SPRITE_IMAGE +#define MBGL_ANNOTATIONS_SPRITE_IMAGE + +#include +#include + +#include +#include +#include + +namespace mbgl { + +class SpriteImage : private util::noncopyable { +public: + SpriteImage( + uint16_t width, uint16_t height, float pixelRatio, std::string&& data, bool sdf = false); + + // Logical dimensions of the sprite image. + const uint16_t width; + const uint16_t height; + + // Pixel ratio of the sprite image. + const float pixelRatio; + + // Physical dimensions of the sprite image. + const uint16_t pixelWidth; + const uint16_t pixelHeight; + + // A string of an RGBA8 representation of the sprite. It must have exactly + // (width * ratio) * (height * ratio) * 4 (RGBA) bytes. The scan lines may + // not have gaps between them (i.e. stride == 0). + const std::string data; + + // Whether this image should be interpreted as a signed distance field icon. + const bool sdf; +}; + +} + +#endif diff --git a/include/mbgl/ios/MGLAccountManager.h b/include/mbgl/ios/MGLAccountManager.h new file mode 100644 index 000000000..9bfb3b497 --- /dev/null +++ b/include/mbgl/ios/MGLAccountManager.h @@ -0,0 +1,31 @@ +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The MGLAccountManager object provides a global way to set a Mapbox API access token, as well as other settings used framework-wide. */ +@interface MGLAccountManager : NSObject + +/** @name Authorizing Access */ + +/** Set the Mapbox API access token for the framework. +* +* You can set an access token on MGLAccountManager or on an individual map view. The same token is used throughout the framework. +* @param accessToken The Mapbox API access token. */ ++ (void)setAccessToken:(nullable NSString *)accessToken; + +/** Retreive the Mapbox API access token for the framework. +* +* You can set an access token on MGLAccountManager or on an individual map view. The same token is used throughout the framework. +* @return accessToken The Mapbox API access token. */ ++ (nullable NSString *)accessToken; + +/** @name Providing User Metrics Opt-Out */ + ++ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut __attribute__((unavailable("Set MGLMapboxMetricsEnabledSettingShownInApp in Info.plist."))); + +/** Whether in-app user metrics opt-out is configured. If set to the default value of `NO`, a user opt-out preference is expected in a `Settings.bundle` that shows in the application's section within the system Settings app. */ ++ (BOOL)mapboxMetricsEnabledSettingShownInApp; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLAnnotation.h b/include/mbgl/ios/MGLAnnotation.h new file mode 100644 index 000000000..18388d848 --- /dev/null +++ b/include/mbgl/ios/MGLAnnotation.h @@ -0,0 +1,33 @@ +#import + +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The `MGLAnnotation` protocol is used to provide annotation-related information to a map view. To use this protocol, you adopt it in any custom objects that store or represent annotation data. Each object then serves as the source of information about a single map annotation and provides critical information, such as the annotation’s location on the map. Annotation objects do not provide the visual representation of the annotation but typically coordinate (in conjunction with the map view’s delegate) the creation of an appropriate objects to handle the display. +* +* An object that adopts this protocol must implement the `coordinate` property. The other methods of this protocol are optional. */ +@protocol MGLAnnotation + +/** @name Position Attributes */ + +/** The center point (specified as a map coordinate) of the annotation. (required) (read-only) */ +@property (nonatomic, readonly) CLLocationCoordinate2D coordinate; + +@optional + +/** @name Title Attributes */ + +/** The string containing the annotation’s title. +* +* Although this property is optional, if you support the selection of annotations in your map view, you are expected to provide this property. This string is displayed in the callout for the associated annotation. */ +@property (nonatomic, readonly, copy, nullable) NSString *title; + +/** The string containing the annotation’s subtitle. +* +* This string is displayed in the callout for the associated annotation. */ +@property (nonatomic, readonly, copy, nullable) NSString *subtitle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLAnnotationImage.h b/include/mbgl/ios/MGLAnnotationImage.h new file mode 100644 index 000000000..9707fca8f --- /dev/null +++ b/include/mbgl/ios/MGLAnnotationImage.h @@ -0,0 +1,16 @@ +#import + +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLAnnotationImage : NSObject + +@property (nonatomic, readonly) UIImage *image; +@property (nonatomic, readonly) NSString *reuseIdentifier; + ++ (instancetype)annotationImageWithImage:(UIImage *)image reuseIdentifier:(NSString *)reuseIdentifier; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLGeometry.h b/include/mbgl/ios/MGLGeometry.h new file mode 100644 index 000000000..6226af1d0 --- /dev/null +++ b/include/mbgl/ios/MGLGeometry.h @@ -0,0 +1,85 @@ +#pragma once + +#import "MGLTypes.h" + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Defines the area spanned by an MGLCoordinateBounds. */ +typedef struct { + CLLocationDegrees latitudeDelta; + CLLocationDegrees longitudeDelta; +} MGLCoordinateSpan; + +/** Creates a new MGLCoordinateSpan from the given latitudinal and longitudinal deltas. */ +NS_INLINE MGLCoordinateSpan MGLCoordinateSpanMake(CLLocationDegrees latitudeDelta, CLLocationDegrees longitudeDelta) { + MGLCoordinateSpan span; + span.latitudeDelta = latitudeDelta; + span.longitudeDelta = longitudeDelta; + return span; +} + +/** Returns `YES` if the two coordinate spans represent the same latitudinal change and the same longitudinal change. */ +NS_INLINE BOOL MGLCoordinateSpanEqualToCoordinateSpan(MGLCoordinateSpan span1, MGLCoordinateSpan span2) { + return (span1.latitudeDelta == span2.latitudeDelta && + span1.longitudeDelta == span2.longitudeDelta); +} + +/** An area of zero width and zero height. */ +extern const MGLCoordinateSpan MGLCoordinateSpanZero; + +/** A rectangular area as measured on a two-dimensional map projection. */ +typedef struct { + CLLocationCoordinate2D sw; + CLLocationCoordinate2D ne; +} MGLCoordinateBounds; + +/** Creates a new MGLCoordinateBounds structure from the given southwest and northeast coordinates. */ +NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsMake(CLLocationCoordinate2D sw, CLLocationCoordinate2D ne) { + MGLCoordinateBounds bounds; + bounds.sw = sw; + bounds.ne = ne; + return bounds; +} + +/** Returns `YES` if the two coordinate bounds are equal to each other. */ +NS_INLINE BOOL MGLCoordinateBoundsEqualToCoordinateBounds(MGLCoordinateBounds bounds1, MGLCoordinateBounds bounds2) { + return (bounds1.sw.latitude == bounds2.sw.latitude && + bounds1.sw.longitude == bounds2.sw.longitude && + bounds1.ne.latitude == bounds2.ne.latitude && + bounds1.ne.longitude == bounds2.ne.longitude); +} + +/** Returns the area spanned by the coordinate bounds. */ +NS_INLINE MGLCoordinateSpan MGLCoordinateBoundsGetCoordinateSpan(MGLCoordinateBounds bounds) { + return MGLCoordinateSpanMake(bounds.ne.latitude - bounds.sw.latitude, + bounds.ne.longitude - bounds.sw.longitude); +} + +/** Returns a coordinate bounds with southwest and northeast coordinates that are offset from those of the source bounds. */ +NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsOffset(MGLCoordinateBounds bounds, MGLCoordinateSpan offset) { + MGLCoordinateBounds offsetBounds = bounds; + offsetBounds.sw.latitude += offset.latitudeDelta; + offsetBounds.sw.longitude += offset.longitudeDelta; + offsetBounds.ne.latitude += offset.latitudeDelta; + offsetBounds.ne.longitude += offset.longitudeDelta; + return offsetBounds; +} + +/** Returns `YES` if the coordinate bounds covers no area. +* +* Note that a bounds may be empty but have a non-zero coordinate span (e.g., when its northeast point lies due north of its southwest point). */ +NS_INLINE BOOL MGLCoordinateBoundsIsEmpty(MGLCoordinateBounds bounds) { + MGLCoordinateSpan span = MGLCoordinateBoundsGetCoordinateSpan(bounds); + return span.latitudeDelta == 0 || span.longitudeDelta == 0; +} + +/** Returns a formatted string for the given coordinate bounds. */ +NS_INLINE NSString *MGLStringFromCoordinateBounds(MGLCoordinateBounds bounds) { + return [NSString stringWithFormat:@"{{%.1f, %.1f}, {%.1f, %.1f}}", + bounds.sw.latitude, bounds.sw.longitude, + bounds.ne.latitude, bounds.ne.longitude]; +} + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLMapView+IBAdditions.h b/include/mbgl/ios/MGLMapView+IBAdditions.h new file mode 100644 index 000000000..693457413 --- /dev/null +++ b/include/mbgl/ios/MGLMapView+IBAdditions.h @@ -0,0 +1,37 @@ +#import "MGLMapView.h" +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLMapView (IBAdditions) + +// Core properties that can be manipulated in the Attributes inspector in +// Interface Builder. These redeclarations merely add the IBInspectable keyword. +// They appear here to ensure that they appear above the convenience properties; +// inspectables declared in MGLMapView.h are always sorted before those in +// MGLMapView+IBAdditions.h, due to ASCII sort order. + +@property (nonatomic, nullable) IBInspectable NSString *styleID; + +// Convenience properties related to the initial viewport. These properties +// are not meant to be used outside of Interface Builder. latitude and longitude +// are backed by properties of type CLLocationDegrees, but these declarations +// must use the type double because Interface Builder is unaware that +// CLLocationDegrees is a typedef for double. + +@property (nonatomic) IBInspectable double latitude; +@property (nonatomic) IBInspectable double longitude; +@property (nonatomic) IBInspectable double zoomLevel; + +// Renamed properties. Interface Builder derives the display name of each +// inspectable from the runtime name, but runtime names don’t always make sense +// in UI. + +@property (nonatomic) IBInspectable BOOL allowsZooming; +@property (nonatomic) IBInspectable BOOL allowsScrolling; +@property (nonatomic) IBInspectable BOOL allowsRotating; +@property (nonatomic) IBInspectable BOOL showsUserLocation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h new file mode 100644 index 000000000..2b9a3d291 --- /dev/null +++ b/include/mbgl/ios/MGLMapView.h @@ -0,0 +1,548 @@ +#import "MGLGeometry.h" + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class MGLAnnotationImage; +@class MGLUserLocation; +@class MGLPolyline; +@class MGLPolygon; +@class MGLShape; + +@protocol MGLMapViewDelegate; +@protocol MGLAnnotation; + +/** An MGLMapView object provides an embeddable map interface, similar to the one provided by Apple's MapKit. You use this class to display map information and to manipulate the map contents from your application. You can center the map on a given coordinate, specify the size of the area you want to display, and style the features of the map to fit your application's use case. +* +* Use of MGLMapView requires a Mapbox API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/account/apps/). If you instantiate an MGLMapView from Interface Builder, rendering of the map won't begin until the accessToken property has been set. +* +* @warning Please note that you are responsible for getting permission to use the map data, and for ensuring your use adheres to the relevant terms of use. */ +IB_DESIGNABLE +@interface MGLMapView : UIView + +#pragma mark - Initializing a Map View + +/** @name Initializing a Map View */ + +/** Initializes and returns a newly allocated map view with the specified frame and the default style. +* @param frame The frame for the view, measured in points. +* @return An initialized map view. */ +- (instancetype)initWithFrame:(CGRect)frame; +- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken __attribute__((unavailable("Use -initWithFrame:. Set MGLMapboxAccessToken in the Info.plist or call +[MGLAccountManager setAccessToken:]."))); + +/** Initializes and returns a newly allocated map view with the specified frame and style URL. +* @param frame The frame for the view, measured in points. +* @param styleURL The map style URL to use. Can be either an HTTP/HTTPS URL or a Mapbox map ID style URL (`mapbox://`). Specify `nil` for the default style. +* @return An initialized map view. */ +- (instancetype)initWithFrame:(CGRect)frame styleURL:(nullable NSURL *)styleURL; +- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(nullable NSURL *)styleURL __attribute__((unavailable("Use -initWithFrame:styleURL:. Set MGLMapboxAccessToken in the Info.plist or call +[MGLAccountManager setAccessToken:]."))); + +#pragma mark - Authorizing Access + +/** @name Authorizing Access */ + +@property (nonatomic, nullable) NSString *accessToken __attribute__((unavailable("Use +[MGLAccountManager accessToken] and +[MGLAccountManager setAccessToken:]."))); + +#pragma mark - Managing Constraints + +/** @name Managing Constraints */ + +#pragma mark - Accessing Map Properties + +/** @name Accessing Map Properties */ + +/** A Boolean value that determines whether the user may zoom the map. +* +* This property controls only user interactions with the map. If you set the value of this property to `NO`, you may still change the map zoom programmatically. +* +* The default value of this property is `YES`. */ +@property(nonatomic, getter=isZoomEnabled) BOOL zoomEnabled; + +/** A Boolean value that determines whether the user may scroll around the map. +* +* This property controls only user interactions with the map. If you set the value of this property to `NO`, you may still change the map location programmatically. +* +* The default value of this property is `YES`. */ +@property(nonatomic, getter=isScrollEnabled) BOOL scrollEnabled; + +/** A Boolean value that determines whether the user may rotate the map. +* +* This property controls only user interactions with the map. If you set the value of this property to `NO`, you may still rotate the map programmatically. +* +* The default value of this property is `YES`. */ +@property(nonatomic, getter=isRotateEnabled) BOOL rotateEnabled; + +/** The compass image view shown in the upper-right when the map is rotated. */ +@property (nonatomic, readonly) UIImageView *compassView; + +/** The Mapbox logo image view shown in the lower-left of the map. */ +@property (nonatomic, readonly) UIImageView *logoView; + +/** The button shown in the lower-right of the map which when pressed displays the map attribution information. */ +@property (nonatomic, readonly) UIButton *attributionButton; + +#pragma mark - Accessing the Delegate + +/** @name Accessing the Delegate */ + +// TODO +@property(nonatomic, weak, nullable) IBOutlet id delegate; + +#pragma mark - Manipulating the Visible Portion of the Map + +/** @name Manipulating the Visible Portion of the Map */ + +/** The map coordinate at the center of the map view. +* +* Changing the value in this property centers the map on the new coordinate without changing the current zoom level. +* +* Changing the value of this property updates the map view immediately. If you want to animate the change, use the setCenterCoordinate:animated: method instead. */ +@property (nonatomic) CLLocationCoordinate2D centerCoordinate; + +/** Changes the center coordinate of the map and optionally animates the change. +* @param coordinate The new center coordinate for the map. +* @param animated Specify `YES` if you want the map view to scroll to the new location or `NO` if you want the map to display the new location immediately. +* +* Changing the center coordinate centers the map on the new coordinate without changing the current zoom level. */ +- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated; + +/** The zoom level of the map view. +* +* Changing the value in this property zooms the map in or out without changing the center coordinate. At zoom level 0, tiles cover the entire world map; at zoom level 1, tiles cover 1/4 of the world; at zoom level 2, tiles cover 1/16 of the world, and so on. +* +* Changing the value of this property updates the map view immediately. If you want to animate the change, use the setZoomLevel:animated: method instead. */ +@property (nonatomic) double zoomLevel; + +/** Changes the zoom level of the map and optionally animates the change. +* @param zoomLevel The new zoom level for the map. +* @param animated Specify `YES` if you want the map view to animate the change to the new zoom level or `NO` if you want the map to display the new zoom level immediately. +* +* Changing the zoom level scales the map without changing the current center coordinate. At zoom level 0, tiles cover the entire world map; at zoom level 1, tiles cover 1/4 of the world; at zoom level 2, tiles cover 1/16 of the world, and so on. */ +- (void)setZoomLevel:(double)zoomLevel animated:(BOOL)animated; + +/** Changes the center coordinate and zoom level of the and optionally animates the change. +* @param centerCoordinate The new center coordinate for the map. +* @param zoomLevel The new zoom level for the map. +* @param animated Specify `YES` if you want the map view to animate scrolling and zooming to the new location or `NO` if you want the map to display the new location immediately. */ +- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel animated:(BOOL)animated; + +/** The coordinate bounds visible in the receiver’s viewport. +* +* Changing the value of this property updates the receiver immediately. If you want to animate the change, call `setVisibleCoordinateBounds:animated:` instead. */ +@property (nonatomic) MGLCoordinateBounds visibleCoordinateBounds; + +/** Changes the receiver’s viewport to fit the given coordinate bounds, optionally animating the change. +* @param bounds The bounds that the viewport will show in its entirety. +* @param animated Specify `YES` to animate the change by smoothly scrolling and zooming or `NO` to immediately display the given bounds. */ +- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds animated:(BOOL)animated; + +/** Changes the receiver’s viewport to fit the given coordinate bounds and optionally some additional padding on each side. +* @param bounds The bounds that the viewport will show in its entirety. +* @param insets The minimum padding (in screen points) that will be visible around the given coordinate bounds. +* @param animated Specify `YES` to animate the change by smoothly scrolling and zooming or `NO` to immediately display the given bounds. */ +- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated; + +/** Changes the receiver’s viewport to fit all of the given coordinates and optionally some additional padding on each side. +* @param coordinates The coordinates that the viewport will show. +* @param count The number of coordinates. This number must not be greater than the number of elements in `coordinates`. +* @param insets The minimum padding (in screen points) that will be visible around the given coordinate bounds. +* @param animated Specify `YES` to animate the change by smoothly scrolling and zooming or `NO` to immediately display the given bounds. */ +- (void)setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated; + +/** Sets the visible region so that the map displays the specified annotations. +* +* Calling this method updates the value in the visibleCoordinateBounds property and potentially other properties to reflect the new map region. +* @param annotations The annotations that you want to be visible in the map. +* @param animated `YES` if you want the map region change to be animated, or `NO` if you want the map to display the new region immediately without animations. */ +- (void)showAnnotations:(NS_ARRAY_OF(id ) *)annotations animated:(BOOL)animated; + +/** The heading of the map (measured in degrees) relative to true north. +* +* The value `0` means that the top edge of the map view corresponds to true north. The value `90` means the top of the map is pointing due east. The value `180` means the top of the map points due south, and so on. */ +@property (nonatomic) CLLocationDirection direction; + +/** Changes the heading of the map and optionally animates the changes. +* @param direction The heading of the map (measured in degrees) relative to true north. +* @param animated Specify `YES` if you want the map view to animate the change to the new heading or `NO` if you want the map to display the new heading immediately. +* +* Changing the heading rotates the map without changing the current center coordinate or zoom level. */ +- (void)setDirection:(CLLocationDirection)direction animated:(BOOL)animated; + +/** Resets the map rotation to a northern heading. */ +- (IBAction)resetNorth; + +#pragma mark - Converting Map Coordinates + +/** @name Converting Map Coordinates */ + +/** Converts a point in the specified view’s coordinate system to a map coordinate. +* @param point The point you want to convert. +* @param view The view that serves as the reference coordinate system for the `point` parameter. +* @return The map coordinate at the specified point. */ +- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(nullable UIView *)view; + +/** Converts a map coordinate to a point in the specified view. +* @param coordinate The map coordinate for which you want to find the corresponding point. +* @param view The view in whose coordinate system you want to locate the specified map coordinate. If this parameter is `nil`, the returned point is specified in the window’s coordinate system. If `view` is not `nil`, it must belong to the same window as the map view. +* @return The point (in the appropriate view or window coordinate system) corresponding to the specified latitude and longitude value. */ +- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(nullable UIView *)view; + +/** Returns the distance spanned by one pixel at the specified latitude and current zoom level. +* +* The distance between pixels decreases as the latitude approaches the poles. This relationship parallels the relationship between longitudinal coordinates at different latitudes. +* +* @param latitude The latitude for which to return the value. +* @return The distance (in meters) spanned by a single pixel. */ +- (CLLocationDistance)metersPerPixelAtLatitude:(CLLocationDegrees)latitude; + +#pragma mark - Styling the Map + +/** @name Styling the Map */ + +/** Mapbox ID of the style currently displayed in the receiver, or `nil` if the style does not have an ID. +* +* The style may lack an ID if it is located at an HTTP, HTTPS, or local file URL. Use `styleURL` to get the URL in these cases. +* +* To display the default style, set this property to `nil`. */ +@property (nonatomic, nullable) NSString *styleID; +@property (nonatomic, nullable) NSString *mapID __attribute__((unavailable("Use styleID."))); + +/** URLs of the styles bundled with the library. */ +@property (nonatomic, readonly) NS_ARRAY_OF(NSURL *) *bundledStyleURLs; + +/** URL of the style currently displayed in the receiver. +* +* The URL may be a full HTTP or HTTPS URL or a Mapbox URL indicating the style’s map ID (`mapbox://`). +* +* To display the default style, set this property to `nil`. */ +@property (nonatomic, null_resettable) NSURL *styleURL; + +/** Currently active style classes, represented as an array of string identifiers. */ +@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses; + +/** Returns a Boolean value indicating whether the style class with the given identifier is currently active. + @param styleClass The style class to query for. + @return Whether the style class is currently active. */ +- (BOOL)hasStyleClass:(NSString *)styleClass; + +/** Activates the style class with the given identifier. + @param styleClass The style class to activate. */ +- (void)addStyleClass:(NSString *)styleClass; + +/** Deactivates the style class with the given identifier. + @param styleClass The style class to deactivate. */ +- (void)removeStyleClass:(NSString *)styleClass; + +#pragma mark - Annotating the Map + +/** @name Annotating the Map */ + +/** The complete list of annotations associated with the receiver. (read-only) +* +* The objects in this array must adopt the MGLAnnotation protocol. If no annotations are associated with the map view, the value of this property is `nil`. */ +@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id ) *annotations; + +/** Adds the specified annotation to the map view. +* @param annotation The annotation object to add to the receiver. This object must conform to the MGLAnnotation protocol. The map view retains the specified object. */ +- (void)addAnnotation:(id )annotation; + +/** Adds an array of annotation objects to the map view. +* @param annotations An array of annotation objects. Each object in the array must conform to the MGLAnnotation protocol. The map view retains the individual annotation objects. */ +- (void)addAnnotations:(NS_ARRAY_OF(id ) *)annotations; + +/** Removes the specified annotation object from the map view. +* +* Removing an annotation object disassociates it from the map view entirely, preventing it from being displayed on the map. Thus, you would typically call this method only when you want to hide or delete a given annotation. +* +* @param annotation The annotation object to remove. This object must conform to the MGLAnnotation protocol. */ +- (void)removeAnnotation:(id )annotation; + +/** Removes an array of annotation objects from the map view. +* +* Removing annotation objects disassociates them from the map view entirely, preventing them from being displayed on the map. Thus, you would typically call this method only when you want to hide or delete the specified annotations. +* +* @param annotations The array of annotations to remove. Objects in the array must conform to the MGLAnnotation protocol. */ +- (void)removeAnnotations:(NS_ARRAY_OF(id ) *)annotations; + +/** Returns a reusable annotation image object located by its identifier. +* +* For performance reasons, you should generally reuse MGLAnnotationImage objects for annotations in your map views. Dequeueing saves time and memory during performance-critical operations such as scrolling. +* +* @param identifier A string identifying the annotation image to be reused. This string is the same one you specify when initially returning the annotation image object using the mapView:imageForAnnotation: method. +* @return An annotation image object with the specified identifier, or `nil` if no such object exists in the reuse queue. */ +- (nullable MGLAnnotationImage *)dequeueReusableAnnotationImageWithIdentifier:(NSString *)identifier; + +#pragma mark - Managing Annotation Selections + +/** @name Managing Annotation Selections */ + +/** The annotations that are currently selected. +* +* Assigning a new array to this property selects only the first annotation in the array. */ +@property (nonatomic, copy) NS_ARRAY_OF(id ) *selectedAnnotations; + +/** Selects the specified annotation and displays a callout view for it. +* +* If the specified annotation is not onscreen, this method has no effect. +* +* @param annotation The annotation object to select. +* @param animated If `YES`, the callout view is animated into position. */ +- (void)selectAnnotation:(id )annotation animated:(BOOL)animated; + +/** Deselects the specified annotation and hides its callout view. +* @param annotation The annotation object to deselect. +* @param animated If `YES`, the callout view is animated offscreen. */ +- (void)deselectAnnotation:(id )annotation animated:(BOOL)animated; + +#pragma mark - Displaying the User's Location + +/** @name Displaying the User's Location */ + +/** A Boolean value indicating whether the map may display the user location. +* +* This property does not indicate whether the user’s position is actually visible on the map, only whether the map view is allowed to display it. To determine whether the user’s position is visible, use the userLocationVisible property. The default value of this property is `NO`. +* +* Setting this property to `YES` causes the map view to use the Core Location framework to find the current location. As long as this property is `YES`, the map view continues to track the user’s location and update it periodically. +* +* On iOS 8 and above, your app must specify a value for `NSLocationWhenInUseUsageDescription` or `NSLocationAlwaysUsageDescription` in its `Info.plist` to satisfy the requirements of the underlying Core Location framework when enabling this property. */ +@property (nonatomic, assign) BOOL showsUserLocation; + +/** A Boolean value indicating whether the device’s current location is visible in the map view. (read-only) */ +@property (nonatomic, assign, readonly, getter=isUserLocationVisible) BOOL userLocationVisible; + +/** Returns the annotation object indicating the user’s current location. */ +@property (nonatomic, readonly, nullable) MGLUserLocation *userLocation; + +/** The mode used to track the user location. */ +@property (nonatomic, assign) MGLUserTrackingMode userTrackingMode; + +/** Whether the map view should display a heading calibration alert when necessary. The default value is `YES`. */ +@property (nonatomic, assign) BOOL displayHeadingCalibration; + +#pragma mark - Debugging + +/** @name Debugging */ + +/** A Boolean value that determines whether map debugging information is shown. +* +* The default value of this property is `NO`. */ +@property (nonatomic, getter=isDebugActive) BOOL debugActive; + +/** Toggle the current value of debugActive. */ +- (void)toggleDebug; + +/** Empties the in-memory tile cache. */ +- (void)emptyMemoryCache; + +/** Resets the map to the minimum zoom level, a center coordinate of (0, 0), and a northern heading. */ +- (void)resetPosition; + +@end + +#pragma mark - MGLMapViewDelegate + +/** The MGLMapViewDelegate protocol defines a set of optional methods that you can use to receive map-related update messages. Because many map operations require the MGLMapView class to load data asynchronously, the map view calls these methods to notify your application when specific operations complete. The map view also uses these methods to request annotation marker symbology and to manage interactions with those markers. */ +@protocol MGLMapViewDelegate + +@optional + +#pragma mark - Managing the Display of Annotations + +/** @name Managing the Display of Annotations */ + +- (nullable NSString *)mapView:(MGLMapView *)mapView symbolNameForAnnotation:(id )annotation __attribute__((unavailable("Use -mapView:imageForAnnotation:."))); + +/** Returns an image object to use for the marker for the specified point annotation object. +* @param mapView The map view that requested the annotation image. +* @param annotation The object representing the annotation that is about to be displayed. +* @return The image object to display for the specified annotation or `nil` if you want to display the default marker image. */ +- (nullable MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id )annotation; + +/** Returns the alpha value to use when rendering a shape annotation. Defaults to `1.0`. +* @param mapView The map view rendering the shape annotation. +* @param annotation The annotation being rendered. +* @return An alpha value between `0` and `1.0`. */ +- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation; + +/** Returns the stroke color to use when rendering a shape annotation. Defaults to black. +* @param mapView The map view rendering the shape annotation. +* @param annotation The annotation being rendered. +* @return A color to use for the shape outline. */ +- (UIColor *)mapView:(MGLMapView *)mapView strokeColorForShapeAnnotation:(MGLShape *)annotation; + +/** Returns the fill color to use when rendering a polygon annotation. Defaults to blue. +* @param mapView The map view rendering the polygon annotation. +* @param annotation The annotation being rendered. +* @return A color to use for the polygon interior. */ +- (UIColor *)mapView:(MGLMapView *)mapView fillColorForPolygonAnnotation:(MGLPolygon *)annotation; + +/** Returns the line width to use when rendering a polyline annotation. Defaults to `3.0`. +* @param mapView The map view rendering the polygon annotation. +* @param annotation The annotation being rendered. +* @return A line width for the polyline. */ +- (CGFloat)mapView:(MGLMapView *)mapView lineWidthForPolylineAnnotation:(MGLPolyline *)annotation; + +/** Returns a Boolean value indicating whether the annotation is able to display extra information in a callout bubble. +* +* If the value returned is `YES`, a standard callout bubble is shown when the user taps a selected annotation. The callout uses the title and subtitle text from the associated annotation object. If there is no title text, though, the annotation will not show a callout. The callout also displays any custom callout views returned by the delegate for the left and right callout accessory views. +* +* If the value returned is `NO`, the value of the title and subtitle strings are ignored. +* +* @param mapView The map view that requested the annotation callout ability. +* @param annotation The object representing the annotation. +* @return A Boolean indicating whether the annotation should show a callout. */ +- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id )annotation; + +/** Return the view to display on the left side of the standard callout bubble. +* +* The default value is treated as if `nil`. The left callout view is typically used to display information about the annotation or to link to custom information provided by your application. +* +* If the view you specify is also a descendant of the `UIControl` class, you can use the map view’s delegate to receive notifications when your control is tapped. If it does not descend from `UIControl`, your view is responsible for handling any touch events within its bounds. +* +* @param mapView The map view presenting the annotation callout. +* @param annotation The object representing the annotation with the callout. +* @return The accessory view to display. */ +- (nullable UIView *)mapView:(MGLMapView *)mapView leftCalloutAccessoryViewForAnnotation:(id )annotation; + +/** Return the view to display on the right side of the standard callout bubble. +* +* The default value is treated is if `nil`. The right callout view is typically used to link to more detailed information about the annotation. A common view to specify for this property is `UIButton` object whose type is set to `UIButtonTypeDetailDisclosure`. +* +* If the view you specify is also a descendant of the `UIControl` class, you can use the map view’s delegate to receive notifications when your control is tapped. If it does not descend from `UIControl`, your view is responsible for handling any touch events within its bounds. +* +* @param mapView The map view presenting the annotation callout. +* @param annotation The object representing the annotation with the callout. +* @return The accessory view to display. */ +- (nullable UIView *)mapView:(MGLMapView *)mapView rightCalloutAccessoryViewForAnnotation:(id )annotation; + +#pragma mark - Responding to Map Position Changes + +// Responding to Map Position Changes + +/** Tells the delegate that the region displayed by the map view is about to change. + * + * This method is called whenever the currently displayed map region will start changing. + * @param mapView The map view whose visible region will change. + * @param animated Whether the change will cause an animated effect on the map. */ +- (void)mapView:(MGLMapView *)mapView regionWillChangeAnimated:(BOOL)animated; + +/** Tells the delegate that the region displayed by the map view is changing. + * + * This method is called whenever the currently displayed map region changes. During movement, this method may be called many times to report updates to the map position. Therefore, your implementation of this method should be as lightweight as possible to avoid affecting performance. + * @param mapView The map view whose visible region is changing. */ +- (void)mapViewRegionIsChanging:(MGLMapView *)mapView; + +/** Tells the delegate that the region displayed by the map view just changed. + * + * This method is called whenever the currently displayed map region has finished changing. + * @param mapView The map view whose visible region changed. + * @param animated Whether the change caused an animated effect on the map. */ +- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated; + +#pragma mark - Loading the Map Data + +// Loading the Map Data + +// TODO +- (void)mapViewWillStartLoadingMap:(MGLMapView *)mapView; + +// TODO +- (void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView; + +// TODO +- (void)mapViewDidFailLoadingMap:(MGLMapView *)mapView withError:(NSError *)error; + +// TODO +- (void)mapViewWillStartRenderingMap:(MGLMapView *)mapView; + +// TODO +- (void)mapViewDidFinishRenderingMap:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered; + +// TODO +- (void)mapViewWillStartRenderingFrame:(MGLMapView *)mapView; + +// TODO +- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered; + +#pragma mark - Tracking the User Location + +/** @name Tracking the User Location */ + +/** Tells the delegate that the map view will begin tracking the user’s location. +* +* This method is called when the value of the showsUserLocation property changes to `YES`. +* +* @param mapView The map view that is tracking the user’s location. */ +- (void)mapViewWillStartLocatingUser:(MGLMapView *)mapView; + +/** Tells the delegate that the map view has stopped tracking the user’s location. +* +* This method is called when the value of the showsUserLocation property changes to `NO`. +* +* @param mapView The map view that is tracking the user’s location. */ +- (void)mapViewDidStopLocatingUser:(MGLMapView *)mapView; + +/** Tells the delegate that the location of the user was updated. +* +* While the showsUserLocation property is set to `YES`, this method is called whenever a new location update is received by the map view. This method is also called if the map view’s user tracking mode is set to MGLUserTrackingModeFollowWithHeading and the heading changes, or if it is set to MGLUserTrackingModeFollowWithCourse and the course changes. +* +* This method is not called if the application is currently running in the background. If you want to receive location updates while running in the background, you must use the Core Location framework. +* +* @param mapView The map view that is tracking the user’s location. +* @param userLocation The location object representing the user’s latest location. This property may be `nil`. */ +- (void)mapView:(MGLMapView *)mapView didUpdateUserLocation:(nullable MGLUserLocation *)userLocation; + +/** Tells the delegate that an attempt to locate the user’s position failed. +* @param mapView The map view that is tracking the user’s location. +* @param error An error object containing the reason why location tracking failed. */ +- (void)mapView:(MGLMapView *)mapView didFailToLocateUserWithError:(NSError *)error; + +/** Tells the delegate that the map view’s user tracking mode has changed. +* +* This method is called after the map view asynchronously changes to reflect the new user tracking mode, for example by beginning to zoom or rotate. +* +* @param mapView The map view that changed its tracking mode. +* @param mode The new tracking mode. +* @param animated Whether the change caused an animated effect on the map. */ +- (void)mapView:(MGLMapView *)mapView didChangeUserTrackingMode:(MGLUserTrackingMode)mode animated:(BOOL)animated; + +#pragma mark - Managing Annotations + +/** @name Managing Annotations */ + +/* Tells the delegate that the user tapped one of the annotation's accessory buttons. +* +* Accessory views contain custom content and are positioned on either side of the annotation title text. If a view you specify is a descendant of the `UIControl` class, the map view calls this method as a convenience whenever the user taps your view. You can use this method to respond to taps and perform any actions associated with that control. For example, if your control displayed additional information about the annotation, you could use this method to present a modal panel with that information. +* +* If your custom accessory views are not descendants of the `UIControl` class, the map view does not call this method. +* +* @param mapView The map view containing the specified annotation. +* @param annotation The annotation whose button was tapped. +* @param control The control that was tapped. */ +- (void)mapView:(MGLMapView *)mapView annotation:(id )annotation calloutAccessoryControlTapped:(UIControl *)control; + +#pragma mark - Selecting Annotations + +/** @name Selecting Annotations */ + +/* Tells the delegate that one of its annotations was selected. +* +* You can use this method to track changes in the selection state of annotations. +* +* @param mapView The map view containing the annotation. +* @param annotation The annotation that was selected. */ +- (void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id )annotation; + +/* Tells the delegate that one of its annotations was deselected. +* +* You can use this method to track changes in the selection state of annotations. +* +* @param mapView The map view containing the annotation. +* @param annotation The annotation that was deselected. */ +- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id )annotation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLMultiPoint.h b/include/mbgl/ios/MGLMultiPoint.h new file mode 100644 index 000000000..1fc7ef6dc --- /dev/null +++ b/include/mbgl/ios/MGLMultiPoint.h @@ -0,0 +1,21 @@ +#import +#import + +#import "MGLShape.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The `MGLMultiPoint` class is an abstract superclass used to define shapes composed of multiple points. You should not create instances of this class directly. Instead, you should create instances of the `MGLPolyline` or `MGLPolygon` classes. However, you can use the method and properties of this class to access information about the specific points associated with the line or polygon. */ +@interface MGLMultiPoint : MGLShape + +/** The number of points associated with the shape. (read-only) */ +@property (nonatomic, readonly) NSUInteger pointCount; + +/** Retrieves one or more coordinates associated with the shape. +* @param coords On input, you must provide a C array of structures large enough to hold the desired number of coordinates. On output, this structure contains the requested coordinate data. +* @param range The range of points you want. The `location` field indicates the first point you are requesting, with `0` being the first point, `1` being the second point, and so on. The `length` field indicates the number of points you want. The array in _`coords`_ must be large enough to accommodate the number of requested coordinates. */ +- (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLOverlay.h b/include/mbgl/ios/MGLOverlay.h new file mode 100644 index 000000000..eee362d57 --- /dev/null +++ b/include/mbgl/ios/MGLOverlay.h @@ -0,0 +1,35 @@ +#import +#import + +#import "MGLAnnotation.h" +#import "MGLGeometry.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The `MGLOverlay` protocol defines a specific type of annotation that represents both a point and an area on a map. Overlay objects are essentially data objects that contain the geographic data needed to represent the map area. For example, overlays can take the form of common shapes such as rectangles and circles. They can also describe polygons and other complex shapes. +* +* You use overlays to layer more sophisticated content on top of a map view. For example, you could use an overlay to show the boundaries of a national park or trace a bus route along city streets. The Mapbox iOS SDK defines several concrete classes that conform to this protocol and define standard shapes. +* +* Because overlays are also annotations, they have similar usage pattern to annotations. When added to a map view using the `addOverlay:` method, that view detects whenever the overlay’s defined region intersects the visible portion of the map. At that point, the map view asks its delegate to provide a special overlay view to draw the visual representation of the overlay. If you add an overlay to a map view as an annotation instead, it is treated as an annotation with a single point. */ +@protocol MGLOverlay + +/* The approximate center point of the overlay area. (required) (read-only) +* +* This point is typically set to the center point of the map’s bounding rectangle. It is used as the anchor point for any callouts displayed for the annotation. */ +@property (nonatomic, readonly) CLLocationCoordinate2D coordinate; + +/** The cooordinate rectangle that encompasses the overlay. (required) (read-only) +* +* This property contains the smallest rectangle that completely encompasses the overlay. Implementers of this protocol must set this area when implementing their overlay class, and after setting it, you must not change it. */ +@property (nonatomic, readonly) MGLCoordinateBounds overlayBounds; + +/** Returns a Boolean indicating whether the specified rectangle intersects the receiver’s shape. +* +* You can implement this method to provide more specific bounds checking for an overlay. If you do not implement it, the bounding rectangle is used to detect intersections. +* @param overlayBounds The rectangle to intersect with the receiver’s area. +* @return `YES` if any part of the map rectangle intersects the receiver’s shape or `NO` if it does not. */ +- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLPointAnnotation.h b/include/mbgl/ios/MGLPointAnnotation.h new file mode 100644 index 000000000..ed5000275 --- /dev/null +++ b/include/mbgl/ios/MGLPointAnnotation.h @@ -0,0 +1,16 @@ +#import +#import + +#import "MGLShape.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The `MGLPointAnnotation` class defines a concrete annotation object located at a specified point. You can use this class, rather than define your own, in situations where all you want to do is associate a point on the map with a title. */ +@interface MGLPointAnnotation : MGLShape + +/** The coordinate point of the annotation, specified as a latitude and longitude. */ +@property (nonatomic, assign) CLLocationCoordinate2D coordinate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLPolygon.h b/include/mbgl/ios/MGLPolygon.h new file mode 100644 index 000000000..c2fef6de6 --- /dev/null +++ b/include/mbgl/ios/MGLPolygon.h @@ -0,0 +1,21 @@ +#import +#import + +#import "MGLMultiPoint.h" +#import "MGLOverlay.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The `MGLPolygon` class represents a shape consisting of one or more points that define a closed polygon. The points are connected end-to-end in the order they are provided. The first and last points are connected to each other to create the closed shape. */ +@interface MGLPolygon : MGLMultiPoint + +/** Creates and returns an `MGLPolygon` object from the specified set of coordinates. +* @param coords The array of coordinates defining the shape. The data in this array is copied to the new object. +* @param count The number of items in the _`coords`_ array. +* @return A new polygon object. */ ++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords + count:(NSUInteger)count; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLPolyline.h b/include/mbgl/ios/MGLPolyline.h new file mode 100644 index 000000000..7cbbadeca --- /dev/null +++ b/include/mbgl/ios/MGLPolyline.h @@ -0,0 +1,21 @@ +#import +#import + +#import "MGLMultiPoint.h" +#import "MGLOverlay.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The `MGLPolyline` class represents a shape consisting of one or more points that define connecting line segments. The points are connected end-to-end in the order they are provided. The first and last points are not connected to each other. */ +@interface MGLPolyline : MGLMultiPoint + +/** Creates and returns an `MGLPolygon` object from the specified set of coordinates. +* @param coords The array of coordinates defining the shape. The data in this array is copied to the new object. +* @param count The number of items in the _`coords`_ array. +* @return A new polyline object. */ ++ (instancetype)polylineWithCoordinates:(CLLocationCoordinate2D *)coords + count:(NSUInteger)count; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLShape.h b/include/mbgl/ios/MGLShape.h new file mode 100644 index 000000000..afc2dbb5a --- /dev/null +++ b/include/mbgl/ios/MGLShape.h @@ -0,0 +1,18 @@ +#import + +#import "MGLAnnotation.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The `MGLShape` class is an abstract class that defines the basic properties for all shape-based annotation objects. This class must be subclassed and cannot be used as is. Subclasses are responsible for defining the geometry of the shape and providing an appropriate value for the coordinate property inherited from the `MGLAnnotation` protocol. */ +@interface MGLShape : NSObject + +/** The title of the shape annotation. The default value of this property is `nil`. */ +@property (nonatomic, copy, nullable) NSString *title; + +/** The subtitle of the shape annotation. The default value of this property is `nil`. */ +@property (nonatomic, copy, nullable) NSString *subtitle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLTypes.h b/include/mbgl/ios/MGLTypes.h new file mode 100644 index 000000000..f36fc3f44 --- /dev/null +++ b/include/mbgl/ios/MGLTypes.h @@ -0,0 +1,49 @@ +#import + +#pragma once + +#if !__has_feature(nullability) + #define NS_ASSUME_NONNULL_BEGIN + #define NS_ASSUME_NONNULL_END + #define nullable + #define nonnull + #define null_resettable +#endif + +NS_ASSUME_NONNULL_BEGIN + +extern NSString * const MGLErrorDomain; + +/** The mode used to track the user location on the map. */ +typedef NS_ENUM(NSUInteger, MGLUserTrackingMode) { + /** The map does not follow the user location. */ + MGLUserTrackingModeNone = 0, + /** The map follows the user location. */ + MGLUserTrackingModeFollow, + /** The map follows the user location and rotates when the heading changes. */ + MGLUserTrackingModeFollowWithHeading, + /** The map follows the user location and rotates when the course changes. */ + MGLUserTrackingModeFollowWithCourse, +}; + +NS_ASSUME_NONNULL_END + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wvariadic-macros" + #if __has_feature(objc_generics) + /** Inserts a type specifier for a pointer to a lightweight generic with the given collection and object classes. Use a `*` for any non-`id` object classes but no `*` for the collection class. */ + #define NS_ARRAY_OF(ObjectClass...) NSArray + #define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray + #define NS_SET_OF(ObjectClass...) NSSet + #define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet + #define NS_DICTIONARY_OF(ObjectClass...) NSDictionary + #define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary + #else + #define NS_ARRAY_OF(ObjectClass...) NSArray + #define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray + #define NS_SET_OF(ObjectClass...) NSSet + #define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet + #define NS_DICTIONARY_OF(ObjectClass...) NSDictionary + #define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary + #endif +#pragma clang diagnostic pop diff --git a/include/mbgl/ios/MGLUserLocation.h b/include/mbgl/ios/MGLUserLocation.h new file mode 100644 index 000000000..2eea51590 --- /dev/null +++ b/include/mbgl/ios/MGLUserLocation.h @@ -0,0 +1,33 @@ +#import "MGLAnnotation.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The MGLUserLocation class defines a specific type of annotation that identifies the user’s current location. You do not create instances of this class directly. Instead, you retrieve an existing MGLUserLocation object from the userLocation property of the map view displayed in your application. */ +@interface MGLUserLocation : NSObject + +/** @name Determining the User’s Position */ + +/** The current location of the device. (read-only) +* +* This property contains `nil` if the map view is not currently showing the user location or if the user’s location has not yet been determined. */ +@property (nonatomic, readonly, nullable) CLLocation *location; + +/** A Boolean value indicating whether the user’s location is currently being updated. (read-only) */ +@property (nonatomic, readonly, getter=isUpdating) BOOL updating; + +/** The heading of the user location. (read-only) +* +* This property is `nil` if the user location tracking mode is not `MGLUserTrackingModeFollowWithHeading`. */ +@property (nonatomic, readonly, nullable) CLHeading *heading; + +/** @name Accessing the User Annotation Text */ + +/** The title to display for the user location annotation. */ +@property (nonatomic, copy) NSString *title; + +/** The subtitle to display for the user location annotation. */ +@property (nonatomic, copy, nullable) NSString *subtitle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/Mapbox.h b/include/mbgl/ios/Mapbox.h new file mode 100644 index 000000000..401a62e82 --- /dev/null +++ b/include/mbgl/ios/Mapbox.h @@ -0,0 +1,13 @@ +#import "MGLAccountManager.h" +#import "MGLAnnotation.h" +#import "MGLAnnotationImage.h" +#import "MGLGeometry.h" +#import "MGLMapView.h" +#import "MGLMultiPoint.h" +#import "MGLOverlay.h" +#import "MGLPointAnnotation.h" +#import "MGLPolygon.h" +#import "MGLPolyline.h" +#import "MGLShape.h" +#import "MGLTypes.h" +#import "MGLUserLocation.h" diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp new file mode 100644 index 000000000..ebd79620d --- /dev/null +++ b/include/mbgl/map/map.hpp @@ -0,0 +1,191 @@ +#ifndef MBGL_MAP_MAP +#define MBGL_MAP_MAP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace mbgl { + +class FileSource; +class View; +class MapData; +class MapContext; +class StillImage; +class SpriteImage; +class Transform; +class PointAnnotation; +class ShapeAnnotation; + +namespace util { +template class Thread; +} + +enum class AnnotationType : uint8_t { + Any = 0, + Point = 1 << 0, + Shape = 1 << 1, +}; + +struct EdgeInsets { + double top = 0; + double left = 0; + double bottom = 0; + double right = 0; +}; + +using AnnotationIDs = std::vector; +using AnnotationSegment = std::vector; +using AnnotationSegments = std::vector; + +class Map : private util::noncopyable { + friend class View; + +public: + explicit Map(View&, FileSource&, + MapMode mode = MapMode::Continuous); + ~Map(); + + // Pauses the render thread. The render thread will stop running but will not be terminated and will not lose state until resumed. + void pause(); + + // Resumes a paused render thread + void resume(); + + // Register a callback that will get called (on the render thread) when all resources have + // been loaded and a complete render occurs. + using StillImageCallback = std::function)>; + void renderStill(StillImageCallback callback); + + // Triggers a synchronous render. + void renderSync(); + + // Nudges transitions one step, possibly notifying of the need for a rerender, if any. + void nudgeTransitions(); + + // Notifies the Map thread that the state has changed and an update might be necessary. + void update(Update update); + + // Styling + void addClass(const std::string&); + void removeClass(const std::string&); + bool hasClass(const std::string&) const; + void setClasses(const std::vector&); + std::vector getClasses() const; + + void setDefaultTransitionDuration(const Duration& = Duration::zero()); + Duration getDefaultTransitionDuration() const; + + void setDefaultTransitionDelay(const Duration& = Duration::zero()); + Duration getDefaultTransitionDelay() const; + + void setStyleURL(const std::string& url); + void setStyleJSON(const std::string& json, const std::string& base = ""); + std::string getStyleURL() const; + std::string getStyleJSON() const; + + // Transition + void cancelTransitions(); + void setGestureInProgress(bool); + + // Position + void moveBy(double dx, double dy, const Duration& = Duration::zero()); + void setLatLng(LatLng latLng, const Duration& = Duration::zero()); + LatLng getLatLng() const; + void resetPosition(); + + // Scale + void scaleBy(double ds, double cx = -1, double cy = -1, const Duration& = Duration::zero()); + void setScale(double scale, double cx = -1, double cy = -1, const Duration& = Duration::zero()); + double getScale() const; + void setZoom(double zoom, const Duration& = Duration::zero()); + double getZoom() const; + void setLatLngZoom(LatLng latLng, double zoom, const Duration& = Duration::zero()); + void fitBounds(LatLngBounds bounds, EdgeInsets padding, const Duration& duration = Duration::zero()); + void fitBounds(AnnotationSegment segment, EdgeInsets padding, const Duration& duration = Duration::zero()); + void resetZoom(); + double getMinZoom() const; + double getMaxZoom() const; + + // Rotation + void rotateBy(double sx, double sy, double ex, double ey, const Duration& = Duration::zero()); + void setBearing(double degrees, const Duration& = Duration::zero()); + void setBearing(double degrees, double cx, double cy); + double getBearing() const; + void resetNorth(); + + // Size + uint16_t getWidth() const; + uint16_t getHeight() const; + + // Projection + void getWorldBoundsMeters(ProjectedMeters &sw, ProjectedMeters &ne) const; + void getWorldBoundsLatLng(LatLng &sw, LatLng &ne) const; + double getMetersPerPixelAtLatitude(const double lat, const double zoom) const; + const ProjectedMeters projectedMetersForLatLng(const LatLng latLng) const; + const LatLng latLngForProjectedMeters(const ProjectedMeters projectedMeters) const; + const vec2 pixelForLatLng(const LatLng latLng) const; + const LatLng latLngForPixel(const vec2 pixel) const; + + // Annotations + void setDefaultPointAnnotationSymbol(const std::string&); + double getTopOffsetPixelsForAnnotationSymbol(const std::string&); + + uint32_t addPointAnnotation(const PointAnnotation&); + AnnotationIDs addPointAnnotations(const std::vector&); + + uint32_t addShapeAnnotation(const ShapeAnnotation&); + AnnotationIDs addShapeAnnotations(const std::vector&); + + void removeAnnotation(uint32_t); + void removeAnnotations(const AnnotationIDs&); + + AnnotationIDs getAnnotationsInBounds(const LatLngBounds&, const AnnotationType& = AnnotationType::Any); + LatLngBounds getBoundsForAnnotations(const AnnotationIDs&); + + // Sprites + void setSprite(const std::string&, std::shared_ptr); + void removeSprite(const std::string&); + + // Memory + void setSourceTileCacheSize(size_t); + void onLowMemory(); + + // Debug + void setDebug(bool value); + void toggleDebug(); + bool getDebug() const; + void setNeedsRepaint(); + void setCollisionDebug(bool value); + void toggleCollisionDebug(); + bool getCollisionDebug() const; + bool isFullyLoaded() const; + +private: + View& view; + const std::unique_ptr transform; + const std::unique_ptr data; + const std::unique_ptr> context; + + enum class RenderState { + never, + partial, + fully + }; + + RenderState renderState = RenderState::never; + bool paused = false; +}; + +} + +#endif diff --git a/include/mbgl/map/mode.hpp b/include/mbgl/map/mode.hpp new file mode 100644 index 000000000..4ade870d9 --- /dev/null +++ b/include/mbgl/map/mode.hpp @@ -0,0 +1,15 @@ +#ifndef MBGL_MAP_MODE +#define MBGL_MAP_MODE + +#include + +namespace mbgl { + +enum class MapMode : uint8_t { + Continuous, // continually updating map + Still, // a once-off still image +}; + +} + +#endif \ No newline at end of file diff --git a/include/mbgl/map/still_image.hpp b/include/mbgl/map/still_image.hpp new file mode 100644 index 000000000..b9ce0620f --- /dev/null +++ b/include/mbgl/map/still_image.hpp @@ -0,0 +1,21 @@ +#ifndef MBGL_MAP_STILL_IMAGE +#define MBGL_MAP_STILL_IMAGE + +#include + +#include +#include + +namespace mbgl { + +class StillImage : util::noncopyable { +public: + uint16_t width = 0; + uint16_t height = 0; + using Pixel = uint32_t; + std::unique_ptr pixels; +}; + +} + +#endif diff --git a/include/mbgl/map/update.hpp b/include/mbgl/map/update.hpp new file mode 100644 index 000000000..fe9250efc --- /dev/null +++ b/include/mbgl/map/update.hpp @@ -0,0 +1,33 @@ +#ifndef MBGL_MAP_UPDATE +#define MBGL_MAP_UPDATE + +#include + +namespace mbgl { + +enum class Update : uint32_t { + Nothing = 0, + Dimensions = 1 << 1, + DefaultTransition = 1 << 2, + Classes = 1 << 3, + Zoom = 1 << 4, + RenderStill = 1 << 5, + Repaint = 1 << 6, +}; + +inline Update operator| (const Update& lhs, const Update& rhs) { + return Update(static_cast(lhs) | static_cast(rhs)); +} + +inline Update& operator|=(Update& lhs, const Update& rhs) { + lhs = lhs | rhs; + return lhs; +} + +inline bool operator& (const Update& lhs, const Update& rhs) { + return static_cast(lhs) & static_cast(rhs); +} + +} // namespace mbgl + +#endif // MBGL_MAP_UPDATE diff --git a/include/mbgl/map/view.hpp b/include/mbgl/map/view.hpp new file mode 100644 index 000000000..3086d51aa --- /dev/null +++ b/include/mbgl/map/view.hpp @@ -0,0 +1,82 @@ +#ifndef MBGL_MAP_VIEW +#define MBGL_MAP_VIEW + +#include +#include + +#include + +namespace mbgl { + +class Map; +class StillImage; + +enum MapChange : uint8_t { + MapChangeRegionWillChange = 0, + MapChangeRegionWillChangeAnimated = 1, + MapChangeRegionIsChanging = 2, + MapChangeRegionDidChange = 3, + MapChangeRegionDidChangeAnimated = 4, + MapChangeWillStartLoadingMap = 5, + MapChangeDidFinishLoadingMap = 6, + MapChangeDidFailLoadingMap = 7, + MapChangeWillStartRenderingFrame = 8, + MapChangeDidFinishRenderingFrame = 9, + MapChangeDidFinishRenderingFrameFullyRendered = 10, + MapChangeWillStartRenderingMap = 11, + MapChangeDidFinishRenderingMap = 12, + MapChangeDidFinishRenderingMapFullyRendered = 13, +}; + +class View { +public: + // Called from the main thread directly after initialization. Must always return the same value, + // i.e. it may not change over time. + virtual float getPixelRatio() const = 0; + + // Called from the main thread when the View signaled a dimension change. Must return the + // logical dimension of this map in pixels. + virtual std::array getSize() const = 0; + + // Called from the main thread for every frame that is being rendered. Must return the absolute + // dimensions of the current framebuffer. Typically, this is the logical width scaled by the + // pixel ratio, but in case the view was moved to display with a different pixel ratio, it can + // also be different from that rule. + virtual std::array getFramebufferSize() const = 0; + + // Called from the main thread when this View is associated with a Map object. + virtual void initialize(Map *map_); + + // Called from the render thread. Makes the GL context active in the current + // thread. This is typically just called once at the beginning of the + // renderer setup since the render thread doesn't switch the contexts. + virtual void activate() = 0; + + // Called from the render thread. Makes the GL context inactive in the current + // thread. This is called once just before the rendering thread terminates. + virtual void deactivate() = 0; + + virtual void notify() = 0; + + // Called from the render thread. The implementation must trigger a rerender. + // (map->renderSync() from the main thread must be called as a result of this) + virtual void invalidate() = 0; + + // Called from the render thread after the render is complete. + virtual void swap() = 0; + + // Reads the pixel data from the current framebuffer. If your View implementation + // doesn't support reading from the framebuffer, return a null pointer. + virtual std::unique_ptr readStillImage(); + + // Notifies a watcher of map x/y/scale/rotation changes. + // Must only be called from the same thread that caused the change. + // Must not be called from the render thread. + virtual void notifyMapChange(MapChange change); + +protected: + mbgl::Map *map = nullptr; +}; +} + +#endif diff --git a/include/mbgl/mbgl.hpp b/include/mbgl/mbgl.hpp new file mode 100644 index 000000000..90abd4e11 --- /dev/null +++ b/include/mbgl/mbgl.hpp @@ -0,0 +1,7 @@ +#ifndef MBGL_MAIN +#define MBGL_MAIN + +#include "map/map.hpp" +#include "map/view.hpp" + +#endif diff --git a/include/mbgl/platform/darwin/reachability.h b/include/mbgl/platform/darwin/reachability.h new file mode 100644 index 000000000..78e302eaf --- /dev/null +++ b/include/mbgl/platform/darwin/reachability.h @@ -0,0 +1,95 @@ +/* + Copyright (c) 2011, Tony Million. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import + + +/** + * Create NS_ENUM macro if it does not exist on the targeted version of iOS or OS X. + * + * @see http://nshipster.com/ns_enum-ns_options/ + **/ +#ifndef NS_ENUM +#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type +#endif + +extern NSString *const kMGLReachabilityChangedNotification; + +typedef NS_ENUM(NSInteger, NetworkStatus) { + // Apple NetworkStatus Compatible Names. + NotReachable = 0, + ReachableViaWiFi = 2, + ReachableViaWWAN = 1 +}; + +@class MGLReachability; + +typedef void (^NetworkReachable)(MGLReachability * reachability); +typedef void (^NetworkUnreachable)(MGLReachability * reachability); + + +@interface MGLReachability : NSObject + +@property (nonatomic, copy) NetworkReachable reachableBlock; +@property (nonatomic, copy) NetworkUnreachable unreachableBlock; + +@property (nonatomic, assign) BOOL reachableOnWWAN; + + ++(instancetype)reachabilityWithHostname:(NSString*)hostname; +// This is identical to the function above, but is here to maintain +//compatibility with Apples original code. (see .m) ++(instancetype)reachabilityWithHostName:(NSString*)hostname; ++(instancetype)reachabilityForInternetConnection; ++(instancetype)reachabilityWithAddress:(void *)hostAddress; ++(instancetype)reachabilityForLocalWiFi; + +-(instancetype)initWithReachabilityRef:(SCNetworkReachabilityRef)ref; + +-(BOOL)startNotifier; +-(void)stopNotifier; + +-(BOOL)isReachable; +-(BOOL)isReachableViaWWAN; +-(BOOL)isReachableViaWiFi; + +// WWAN may be available, but not active until a connection has been established. +// WiFi may require a connection for VPN on Demand. +-(BOOL)isConnectionRequired; // Identical DDG variant. +-(BOOL)connectionRequired; // Apple's routine. +// Dynamic, on demand connection? +-(BOOL)isConnectionOnDemand; +// Is user intervention required? +-(BOOL)isInterventionRequired; + +-(NetworkStatus)currentReachabilityStatus; +-(SCNetworkReachabilityFlags)reachabilityFlags; +-(NSString*)currentReachabilityString; +-(NSString*)currentReachabilityFlags; + +@end diff --git a/include/mbgl/platform/darwin/settings_nsuserdefaults.hpp b/include/mbgl/platform/darwin/settings_nsuserdefaults.hpp new file mode 100644 index 000000000..6c91fd302 --- /dev/null +++ b/include/mbgl/platform/darwin/settings_nsuserdefaults.hpp @@ -0,0 +1,29 @@ +#ifndef MBGL_COMMON_SETTINGS_NSUSERDEFAULTS +#define MBGL_COMMON_SETTINGS_NSUSERDEFAULTS + +#import + +namespace mbgl { + +class Settings_NSUserDefaults { +public: + Settings_NSUserDefaults(); + void load(); + void save(); + void clear(); + +public: + double longitude = 0; + double latitude = 0; + double zoom = 0; + double bearing = 0; + + MGLUserTrackingMode userTrackingMode = MGLUserTrackingModeNone; + bool showsUserLocation = false; + + bool debug = false; +}; + +} + +#endif diff --git a/include/mbgl/platform/default/glfw_view.hpp b/include/mbgl/platform/default/glfw_view.hpp new file mode 100644 index 000000000..ec9908073 --- /dev/null +++ b/include/mbgl/platform/default/glfw_view.hpp @@ -0,0 +1,89 @@ +#ifndef MBGL_COMMON_GLFW_VIEW +#define MBGL_COMMON_GLFW_VIEW + +#include + +#ifdef MBGL_USE_GLES2 +#define GLFW_INCLUDE_ES2 +#endif +#include + +#include + +class GLFWView : public mbgl::View { +public: + GLFWView(bool fullscreen = false, bool benchmark = false); + ~GLFWView(); + + float getPixelRatio() const override; + std::array getSize() const override; + std::array getFramebufferSize() const override; + + void initialize(mbgl::Map *map) override; + void activate() override; + void deactivate() override; + void notify() override; + void invalidate() override; + void swap() override; + + static void onKey(GLFWwindow *window, int key, int scancode, int action, int mods); + static void onScroll(GLFWwindow *window, double xoffset, double yoffset); + static void onWindowResize(GLFWwindow *window, int width, int height); + static void onFramebufferResize(GLFWwindow *window, int width, int height); + static void onMouseClick(GLFWwindow *window, int button, int action, int modifiers); + static void onMouseMove(GLFWwindow *window, double x, double y); + + // Callback called when the user presses the key mapped to style change. + // The expected action is to set a new style, different to the current one. + void setChangeStyleCallback(std::function callback); + + void setShouldClose(); + + void setWindowTitle(const std::string&); + + void run(); + void report(float duration); + +private: + mbgl::LatLng makeRandomPoint() const; + static std::shared_ptr + makeSpriteImage(int width, int height, float pixelRatio); + + void addRandomPointAnnotations(int count); + void addRandomShapeAnnotations(int count); + void addRandomCustomPointAnnotations(int count); + + void clearAnnotations(); + void popAnnotation(); + + mbgl::AnnotationIDs annotationIDs; + std::vector spriteIDs; + +private: + bool fullscreen = false; + const bool benchmark = false; + bool tracking = false; + bool rotating = false; + + // Frame timer + int frames = 0; + float frameTime = 0; + double lastReported = 0; + + int width = 1024; + int height = 768; + int fbWidth; + int fbHeight; + float pixelRatio; + + double lastX = 0, lastY = 0; + + double lastClick = -1; + + std::function changeStyleCallback; + + GLFWwindow *window = nullptr; + std::atomic_flag clean = ATOMIC_FLAG_INIT; +}; + +#endif diff --git a/include/mbgl/platform/default/headless_display.hpp b/include/mbgl/platform/default/headless_display.hpp new file mode 100644 index 000000000..bf67e3c3b --- /dev/null +++ b/include/mbgl/platform/default/headless_display.hpp @@ -0,0 +1,25 @@ +#ifndef MBGL_COMMON_HEADLESS_DISPLAY +#define MBGL_COMMON_HEADLESS_DISPLAY + +#include + +namespace mbgl { + +class HeadlessDisplay { +public: + HeadlessDisplay(); + ~HeadlessDisplay(); + +#if MBGL_USE_CGL + CGLPixelFormatObj pixelFormat; +#endif + +#if MBGL_USE_GLX + Display *xDisplay = nullptr; + GLXFBConfig *fbConfigs = nullptr; +#endif +}; + +} + +#endif diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp new file mode 100644 index 000000000..ce0ff2a68 --- /dev/null +++ b/include/mbgl/platform/default/headless_view.hpp @@ -0,0 +1,78 @@ +#ifndef MBGL_COMMON_HEADLESS_VIEW +#define MBGL_COMMON_HEADLESS_VIEW + +#ifdef __APPLE__ +#define MBGL_USE_CGL 1 +#else +#define GL_GLEXT_PROTOTYPES +#define MBGL_USE_GLX 1 +typedef struct _XDisplay Display; +typedef struct __GLXcontextRec* GLXContext; +typedef struct __GLXFBConfigRec* GLXFBConfig; +typedef long unsigned int XID; +typedef XID GLXPbuffer; +#endif + +#include +#include + +#include +#include + +namespace mbgl { + +class HeadlessDisplay; + +class HeadlessView : public View { +public: + HeadlessView(float pixelRatio, uint16_t width = 256, uint16_t height = 256); + HeadlessView(std::shared_ptr display, float pixelRatio, uint16_t width = 256, uint16_t height = 256); + ~HeadlessView(); + + float getPixelRatio() const override; + std::array getSize() const override; + std::array getFramebufferSize() const override; + + void activate() override; + void deactivate() override; + void notify() override; + void invalidate() override; + void swap() override; + std::unique_ptr readStillImage() override; + + void resize(uint16_t width, uint16_t height); + +private: + void createContext(); + void loadExtensions(); + void clearBuffers(); + bool isActive(); + +private: + std::shared_ptr display; + const float pixelRatio; + std::array dimensions; + +#if MBGL_USE_CGL + CGLContextObj glContext = nullptr; +#endif + +#if MBGL_USE_GLX + Display *xDisplay = nullptr; + GLXFBConfig *fbConfigs = nullptr; + GLXContext glContext = 0; + GLXPbuffer glxPbuffer = 0; +#endif + + bool extensionsLoaded = false; + + GLuint fbo = 0; + GLuint fboDepthStencil = 0; + GLuint fboColor = 0; + + std::thread::id thread; +}; + +} + +#endif diff --git a/include/mbgl/platform/default/image_reader.hpp b/include/mbgl/platform/default/image_reader.hpp new file mode 100644 index 000000000..52a67a283 --- /dev/null +++ b/include/mbgl/platform/default/image_reader.hpp @@ -0,0 +1,42 @@ +#ifndef MBGL_UTIL_IMAGE_READER_HPP +#define MBGL_UTIL_IMAGE_READER_HPP + +#include +// stl +#include +#include +#include + +namespace mbgl { namespace util { + +class ImageReaderException : public std::exception +{ +private: + std::string message_; +public: + ImageReaderException(std::string const& message) + : message_(message) {} + + ~ImageReaderException() throw() {} + + virtual const char* what() const throw() + { + return message_.c_str(); + } +}; + +struct ImageReader : private noncopyable +{ + virtual unsigned width() const=0; + virtual unsigned height() const=0; + virtual bool hasAlpha() const=0; + virtual bool premultipliedAlpha() const=0; + virtual void read(unsigned x,unsigned y, unsigned width, unsigned height, char* image)=0; + virtual ~ImageReader() {} +}; + +std::unique_ptr getImageReader(char const* data, size_t size); + +}} + +#endif diff --git a/include/mbgl/platform/default/jpeg_reader.hpp b/include/mbgl/platform/default/jpeg_reader.hpp new file mode 100644 index 000000000..3e64ce291 --- /dev/null +++ b/include/mbgl/platform/default/jpeg_reader.hpp @@ -0,0 +1,74 @@ +#ifndef MBGL_UTIL_JPEG_READER_HPP +#define MBGL_UTIL_JPEG_READER_HPP + +#include + +// jpeg +extern "C" +{ +#include +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#pragma GCC diagnostic ignored "-Wshadow" +#include +#pragma GCC diagnostic pop + +namespace mbgl { namespace util { + +template +class JpegReader : public ImageReader +{ +public: + using source_type = T; + using input_stream = boost::iostreams::stream; + const static unsigned BUF_SIZE = 4096; +private: + struct jpeg_stream_wrapper + { + jpeg_source_mgr manager; + input_stream * stream; + JOCTET buffer[BUF_SIZE]; + }; + + struct jpeg_info_guard + { + jpeg_info_guard(jpeg_decompress_struct * cinfo) + : i_(cinfo) {} + + ~jpeg_info_guard() + { + jpeg_destroy_decompress(i_); + } + jpeg_decompress_struct * i_; + }; + +private: + source_type source_; + input_stream stream_; + unsigned width_; + unsigned height_; +public: + JpegReader(char const* data, size_t size); + ~JpegReader(); + unsigned width() const; + unsigned height() const; + inline bool hasAlpha() const { return false; } + inline bool premultipliedAlpha() const { return true; } + void read(unsigned x,unsigned y, unsigned w, unsigned h, char *image); +private: + void init(); + static void on_error(j_common_ptr cinfo); + static void on_error_message(j_common_ptr cinfo); + static void init_source(j_decompress_ptr cinfo); + static boolean fill_input_buffer(j_decompress_ptr cinfo); + static void skip(j_decompress_ptr cinfo, long count); + static void term(j_decompress_ptr cinfo); + static void attach_stream(j_decompress_ptr cinfo, input_stream* in); +}; + +}} + +#endif // MBGL_UTIL_JPEG_READER_HPP diff --git a/include/mbgl/platform/default/png_reader.hpp b/include/mbgl/platform/default/png_reader.hpp new file mode 100644 index 000000000..5cbbc51e7 --- /dev/null +++ b/include/mbgl/platform/default/png_reader.hpp @@ -0,0 +1,67 @@ +#ifndef MBGL_UTIL_PNG_READER_HPP +#define MBGL_UTIL_PNG_READER_HPP + +#include + +extern "C" +{ +#include +} + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#pragma GCC diagnostic ignored "-Wshadow" +#include +#pragma GCC diagnostic pop + +namespace mbgl { namespace util { + +template +class PngReader : public ImageReader +{ + using source_type = T; + using input_stream = boost::iostreams::stream; + + struct png_struct_guard + { + png_struct_guard(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) + : p_(png_ptr_ptr), + i_(info_ptr_ptr) {} + + ~png_struct_guard() + { + png_destroy_read_struct(p_,i_,0); + } + png_structpp p_; + png_infopp i_; + }; + +private: + source_type source_; + input_stream stream_; + unsigned width_; + unsigned height_; + int bit_depth_; + int color_type_; + bool has_alpha_; +public: + PngReader(char const* data, std::size_t size); + ~PngReader(); + unsigned width() const; + unsigned height() const; + inline bool hasAlpha() const { return has_alpha_; } + bool premultipliedAlpha() const { return true; } // png_set_alpha_mode(png, PNG_ALPHA_PREMULTIPLIED, 2.2) + void read(unsigned x,unsigned y, unsigned width, unsigned height, char * image); +private: + void init(); + static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length); +}; + + +}} + +#endif // MBGL_UTIL_PNG_READER_HPP diff --git a/include/mbgl/platform/default/settings_json.hpp b/include/mbgl/platform/default/settings_json.hpp new file mode 100644 index 000000000..25c2179ba --- /dev/null +++ b/include/mbgl/platform/default/settings_json.hpp @@ -0,0 +1,24 @@ +#ifndef MBGL_JSON_SETTINGS +#define MBGL_JSON_SETTINGS + +namespace mbgl { + +class Settings_JSON { +public: + Settings_JSON(); + void load(); + void save(); + void clear(); + +public: + double longitude = 0; + double latitude = 0; + double zoom = 0; + double bearing = 0; + + bool debug = false; +}; + +} + +#endif diff --git a/include/mbgl/platform/event.hpp b/include/mbgl/platform/event.hpp new file mode 100644 index 000000000..c80186da2 --- /dev/null +++ b/include/mbgl/platform/event.hpp @@ -0,0 +1,90 @@ +#ifndef MBGL_PLATFORM_EVENT +#define MBGL_PLATFORM_EVENT + +#include + +#include + +namespace mbgl { + +enum class EventSeverity : uint8_t { + Debug, + Info, + Warning, + Error, +}; + +MBGL_DEFINE_ENUM_CLASS(EventSeverityClass, EventSeverity, { + { EventSeverity::Debug, "DEBUG" }, + { EventSeverity::Info, "INFO" }, + { EventSeverity::Warning, "WARNING" }, + { EventSeverity::Error, "ERROR" }, + { EventSeverity(-1), "UNKNOWN" }, +}); + +enum class Event : uint8_t { + General, + Setup, + Shader, + ParseStyle, + ParseTile, + Render, + Style, + Database, + HttpRequest, + Sprite, + Image, + OpenGL, + JNI, + Android, + Crash +}; + +MBGL_DEFINE_ENUM_CLASS(EventClass, Event, { + { Event::General, "General" }, + { Event::Setup, "Setup" }, + { Event::Shader, "Shader" }, + { Event::ParseStyle, "ParseStyle" }, + { Event::ParseTile, "ParseTile" }, + { Event::Render, "Render" }, + { Event::Style, "Style" }, + { Event::Database, "Database" }, + { Event::HttpRequest, "HttpRequest" }, + { Event::Sprite, "Sprite" }, + { Event::Image, "Image" }, + { Event::OpenGL, "OpenGL" }, + { Event::JNI, "JNI" }, + { Event::Android, "Android" }, + { Event::Crash, "Crash" }, + { Event(-1), "Unknown" }, +}); + + +struct EventPermutation { + const EventSeverity severity; + const Event event; + + constexpr bool operator==(const EventPermutation &rhs) const { + return severity == rhs.severity && event == rhs.event; + } +}; + +constexpr EventSeverity disabledEventSeverities[] = { +#if DEBUG + EventSeverity(-1) // Avoid zero size array +#else + EventSeverity::Debug +#endif +}; + +constexpr Event disabledEvents[] = { + Event(-1) // Avoid zero size array +}; + +constexpr EventPermutation disabledEventPermutations[] = { + { EventSeverity::Debug, Event::Shader } +}; + +} + +#endif diff --git a/include/mbgl/platform/gl.hpp b/include/mbgl/platform/gl.hpp new file mode 100644 index 000000000..6bcb85fee --- /dev/null +++ b/include/mbgl/platform/gl.hpp @@ -0,0 +1,87 @@ +#ifndef MBGL_RENDERER_GL +#define MBGL_RENDERER_GL + +#include +#include +#include + +#if __APPLE__ + #include "TargetConditionals.h" + #if TARGET_OS_IPHONE + #include + #include + #elif TARGET_IPHONE_SIMULATOR + #include + #include + #elif TARGET_OS_MAC + #include + #include + #else + #error Unsupported Apple platform + #endif +#elif __ANDROID__ || MBGL_USE_GLES2 + #define GL_GLEXT_PROTOTYPES + #include + #include +#else + #define GL_GLEXT_PROTOTYPES + #include + #include +#endif + +namespace mbgl { +namespace gl { + +struct Error : ::std::runtime_error { + inline Error(GLenum err, const std::string &msg) : ::std::runtime_error(msg), code(err) {}; + const GLenum code; +}; + +void checkError(const char *cmd, const char *file, int line); + +#if defined(DEBUG) +#define MBGL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { inline ~__MBGL_C_E() { ::mbgl::gl::checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }()) +#else +#define MBGL_CHECK_ERROR(cmd) (cmd) +#endif + +class ExtensionFunctionBase { +public: + static std::vector& functions(); + typedef std::pair Probe; + std::vector probes; + void (*ptr)(); +}; + +template +class ExtensionFunction; + +template +class ExtensionFunction : protected ExtensionFunctionBase { +public: + ExtensionFunction(std::initializer_list probes_) { + probes = probes_; + ExtensionFunctionBase::functions().push_back(this); + } + + explicit operator bool() const { + return ptr; + } + + R operator()(Args... args) const { + return (*reinterpret_cast(ptr))(std::forward(args)...); + } +}; + +using glProc = void (*)(); +void InitializeExtensions(glProc (*getProcAddress)(const char *)); + +} +} + +#ifdef GL_ES_VERSION_2_0 + #define glClearDepth glClearDepthf + #define glDepthRange glDepthRangef +#endif + +#endif diff --git a/include/mbgl/platform/log.hpp b/include/mbgl/platform/log.hpp new file mode 100644 index 000000000..86a8cdbef --- /dev/null +++ b/include/mbgl/platform/log.hpp @@ -0,0 +1,77 @@ +#ifndef MBGL_PLATFORM_LOG +#define MBGL_PLATFORM_LOG + +#include + +#include + +#include +#include + +namespace mbgl { + +class Log { +public: + class Observer : private util::noncopyable { + public: + virtual ~Observer() = default; + + // When an observer is set, this function will be called for every log + // message. Returning true will consume the message. + virtual bool onRecord(EventSeverity severity, Event event, int64_t code, const std::string &msg) = 0; + }; + + static void setObserver(std::unique_ptr Observer); + static std::unique_ptr removeObserver(); + +private: + template + constexpr static bool includes(const T e, const T (&l)[N], const size_t i = 0) { + return i < N && (l[i] == e || includes(e, l, i + 1)); + } + +public: + template + static inline void Debug(Event event, Args&& ...args) { + Record(EventSeverity::Debug, event, ::std::forward(args)...); + } + + template + static inline void Info(Event event, Args&& ...args) { + Record(EventSeverity::Info, event, ::std::forward(args)...); + } + + template + static inline void Warning(Event event, Args&& ...args) { + Record(EventSeverity::Warning, event, ::std::forward(args)...); + } + + template + static inline void Error(Event event, Args&& ...args) { + Record(EventSeverity::Error, event, ::std::forward(args)...); + } + + template + static inline void Record(EventSeverity severity, Event event, Args&& ...args) { + if (!includes(severity, disabledEventSeverities) && + !includes(event, disabledEvents) && + !includes({ severity, event }, disabledEventPermutations)) { + record(severity, event, ::std::forward(args)...); + } + } + +private: + static void record(EventSeverity severity, Event event, const std::string &msg); + static void record(EventSeverity severity, Event event, const char* format, ...); + static void record(EventSeverity severity, Event event, int64_t code); + static void record(EventSeverity severity, Event event, int64_t code, const std::string &msg); + + // This method is the data sink that must be implemented by each platform we + // support. It should ideally output the error message in a human readable + // format to the developer. + static void platformRecord(EventSeverity severity, const std::string &msg); +}; + +} + +#endif diff --git a/include/mbgl/platform/platform.hpp b/include/mbgl/platform/platform.hpp new file mode 100644 index 000000000..f828af37f --- /dev/null +++ b/include/mbgl/platform/platform.hpp @@ -0,0 +1,35 @@ +#ifndef MBGL_PLATFORM_PLATFORM +#define MBGL_PLATFORM_PLATFORM + +#include +#include + +namespace mbgl { +namespace platform { + +class Request; + +// Uppercase a string, potentially using platform-specific routines. +std::string uppercase(const std::string &string); + +// Lowercase a string, potentially using platform-specific routines. +std::string lowercase(const std::string &string); + +// Returns the path to the root folder of the application. +const std::string &applicationRoot(); + +// Returns the path to the asset location. +const std::string &assetRoot(); + +// Makes the current thread low priority. +void makeThreadLowPriority(); + +// Shows an alpha image with the specified dimensions in a named window. +void showDebugImage(std::string name, const char *data, size_t width, size_t height); + +// Shows an alpha image with the specified dimensions in a named window. +void showColorDebugImage(std::string name, const char *data, size_t logical_width, size_t logical_height, size_t width, size_t height); +} +} + +#endif diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp new file mode 100644 index 000000000..8cfae03a9 --- /dev/null +++ b/include/mbgl/storage/default_file_source.hpp @@ -0,0 +1,34 @@ +#ifndef MBGL_STORAGE_DEFAULT_DEFAULT_FILE_SOURCE +#define MBGL_STORAGE_DEFAULT_DEFAULT_FILE_SOURCE + +#include +#include + +namespace mbgl { + +namespace util { +template class Thread; +} + +class DefaultFileSource : public FileSource { +public: + DefaultFileSource(FileCache *cache, const std::string &root = ""); + ~DefaultFileSource() override; + + void setAccessToken(const std::string& t) { accessToken = t; } + std::string getAccessToken() const { return accessToken; } + + // FileSource API + Request* request(const Resource&, uv_loop_t*, Callback) override; + void cancel(Request*) override; + +public: + class Impl; +private: + const std::unique_ptr> thread; + std::string accessToken; +}; + +} + +#endif diff --git a/include/mbgl/storage/file_cache.hpp b/include/mbgl/storage/file_cache.hpp new file mode 100644 index 000000000..a9071b1b6 --- /dev/null +++ b/include/mbgl/storage/file_cache.hpp @@ -0,0 +1,28 @@ +#ifndef MBGL_STORAGE_FILE_CACHE +#define MBGL_STORAGE_FILE_CACHE + +#include + +#include +#include + +namespace mbgl { + +struct Resource; +class Response; +class WorkRequest; + +class FileCache : private util::noncopyable { +public: + virtual ~FileCache() = default; + + enum class Hint : uint8_t { Full, Refresh, No }; + using Callback = std::function)>; + + virtual std::unique_ptr get(const Resource &resource, Callback callback) = 0; + virtual void put(const Resource &resource, std::shared_ptr response, Hint hint) = 0; +}; + +} + +#endif diff --git a/include/mbgl/storage/file_source.hpp b/include/mbgl/storage/file_source.hpp new file mode 100644 index 000000000..3b19e0078 --- /dev/null +++ b/include/mbgl/storage/file_source.hpp @@ -0,0 +1,35 @@ +#ifndef MBGL_STORAGE_FILE_SOURCE +#define MBGL_STORAGE_FILE_SOURCE + +#include "response.hpp" +#include "resource.hpp" + +#include +#include + +#include + +typedef struct uv_loop_s uv_loop_t; + +namespace mbgl { + +class Request; + +class FileSource : private util::noncopyable { +protected: + MBGL_STORE_THREAD(tid) + +public: + virtual ~FileSource() = default; + + using Callback = std::function; + + // These can be called from any thread. The callback will be invoked in the loop. + // You can only cancel a request from the same thread it was created in. + virtual Request* request(const Resource&, uv_loop_t*, Callback) = 0; + virtual void cancel(Request*) = 0; +}; + +} + +#endif diff --git a/include/mbgl/storage/network_status.hpp b/include/mbgl/storage/network_status.hpp new file mode 100644 index 000000000..cac2ae193 --- /dev/null +++ b/include/mbgl/storage/network_status.hpp @@ -0,0 +1,25 @@ +#ifndef MBGL_STORAGE_NETWORK_STATUS +#define MBGL_STORAGE_NETWORK_STATUS + +#include +#include + +typedef struct uv_async_s uv_async_t; + +namespace mbgl { + +class NetworkStatus { +public: + static void Reachable(); + + static void Subscribe(uv_async_t *async); + static void Unsubscribe(uv_async_t *async); + +private: + static std::mutex mtx; + static std::set observers; +}; + +} + +#endif \ No newline at end of file diff --git a/include/mbgl/storage/request.hpp b/include/mbgl/storage/request.hpp new file mode 100644 index 000000000..4b75f23f6 --- /dev/null +++ b/include/mbgl/storage/request.hpp @@ -0,0 +1,52 @@ +#ifndef MBGL_STORAGE_DEFAULT_REQUEST +#define MBGL_STORAGE_DEFAULT_REQUEST + +#include + +#include +#include + +#include +#include +#include +#include + +typedef struct uv_loop_s uv_loop_t; +namespace uv { class async; } + +namespace mbgl { + +class Response; + +class Request : private util::noncopyable { +public: + using Callback = std::function; + Request(const Resource &resource, uv_loop_t *loop, Callback callback); + +public: + // May be called from any thread. + void notify(const std::shared_ptr &response); + void destruct(); + + // May be called only from the thread the Request was created in. + void cancel(); + +private: + ~Request(); + void invoke(); + void notifyCallback(); + +private: + std::unique_ptr async; + struct Canceled; + std::unique_ptr canceled; + Callback callback; + std::shared_ptr response; + +public: + const Resource resource; +}; + +} + +#endif diff --git a/include/mbgl/storage/resource.hpp b/include/mbgl/storage/resource.hpp new file mode 100644 index 000000000..2fcb3b1b7 --- /dev/null +++ b/include/mbgl/storage/resource.hpp @@ -0,0 +1,37 @@ +#ifndef MBGL_STORAGE_RESOURCE +#define MBGL_STORAGE_RESOURCE + +#include +#include + +namespace mbgl { + +struct Resource { + enum Kind : uint8_t { + Unknown = 0, + Style, + Source, + Tile, + Glyphs, + JSON, + Image + }; + + const Kind kind; + const std::string url; + + inline bool operator==(const Resource &res) const { + return kind == res.kind && url == res.url; + } + + struct Hash { + std::size_t operator()(Resource const& r) const { + return std::hash()(r.url) ^ (std::hash()(r.kind) << 1); + } + }; + +}; + +} + +#endif diff --git a/include/mbgl/storage/response.hpp b/include/mbgl/storage/response.hpp new file mode 100644 index 000000000..cf22d9002 --- /dev/null +++ b/include/mbgl/storage/response.hpp @@ -0,0 +1,22 @@ +#ifndef MBGL_STORAGE_RESPONSE +#define MBGL_STORAGE_RESPONSE + +#include + +namespace mbgl { + +class Response { +public: + enum Status : bool { Error, Successful }; + + Status status = Error; + std::string message; + int64_t modified = 0; + int64_t expires = 0; + std::string etag; + std::string data; +}; + +} + +#endif diff --git a/include/mbgl/storage/sqlite_cache.hpp b/include/mbgl/storage/sqlite_cache.hpp new file mode 100644 index 000000000..65328652f --- /dev/null +++ b/include/mbgl/storage/sqlite_cache.hpp @@ -0,0 +1,31 @@ +#ifndef MBGL_STORAGE_DEFAULT_SQLITE_CACHE +#define MBGL_STORAGE_DEFAULT_SQLITE_CACHE + +#include + +#include + +namespace mbgl { + +namespace util { +template class Thread; +} + +class SQLiteCache : public FileCache { +public: + SQLiteCache(const std::string &path = ":memory:"); + ~SQLiteCache() override; + + // FileCache API + std::unique_ptr get(const Resource &resource, Callback callback) override; + void put(const Resource &resource, std::shared_ptr response, Hint hint) override; + + class Impl; + +private: + const std::unique_ptr> thread; +}; + +} + +#endif diff --git a/include/mbgl/style/style_properties.hpp b/include/mbgl/style/style_properties.hpp new file mode 100644 index 000000000..9ab528586 --- /dev/null +++ b/include/mbgl/style/style_properties.hpp @@ -0,0 +1,114 @@ +#ifndef MBGL_STYLE_STYLE_PROPERTIES +#define MBGL_STYLE_STYLE_PROPERTIES + +#include +#include + +#include +#include +#include +#include +#include + +namespace mbgl { + +struct FillProperties { + FillProperties() {} + bool antialias = true; + float opacity = 1.0f; + Color fill_color = {{ 0, 0, 0, 1 }}; + Color stroke_color = {{ 0, 0, 0, -1 }}; + std::array translate = {{ 0, 0 }}; + TranslateAnchorType translateAnchor = TranslateAnchorType::Map; + Faded image; + + inline bool isVisible() const { + return opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0); + } +}; + +struct LineProperties { + inline LineProperties() {} + float opacity = 1.0f; + Color color = {{ 0, 0, 0, 1 }}; + std::array translate = {{ 0, 0 }}; + TranslateAnchorType translateAnchor = TranslateAnchorType::Map; + float width = 1; + float gap_width = 0; + float blur = 0; + Faded> dash_array; + float dash_line_width = 1; + Faded image; + + inline bool isVisible() const { + return opacity > 0 && color[3] > 0 && width > 0; + } +}; + +struct SymbolProperties { + inline SymbolProperties() {} + + struct { + float opacity = 1.0f; + float size = 1.0f; + Color color = {{ 0, 0, 0, 1 }}; + Color halo_color = {{ 0, 0, 0, 0 }}; + float halo_width = 0.0f; + float halo_blur = 0.0f; + std::array translate = {{ 0, 0 }}; + TranslateAnchorType translate_anchor = TranslateAnchorType::Map; + } icon; + + struct { + float opacity = 1.0f; + float size = 16.0f; + Color color = {{ 0, 0, 0, 1 }}; + Color halo_color = {{ 0, 0, 0, 0 }}; + float halo_width = 0.0f; + float halo_blur = 0.0f; + std::array translate = {{ 0, 0 }}; + TranslateAnchorType translate_anchor = TranslateAnchorType::Map; + } text; + + inline bool isVisible() const { + return (icon.opacity > 0 && (icon.color[3] > 0 || icon.halo_color[3] > 0) && icon.size > 0) || + (text.opacity > 0 && (text.color[3] > 0 || text.halo_color[3] > 0) && text.size > 0); + } +}; + +struct RasterProperties { + inline RasterProperties() {} + float opacity = 1.0f; + float hue_rotate = 0.0f; + std::array brightness = {{ 0, 1 }}; + float saturation = 0.0f; + float contrast = 0.0f; + float fade = 0.0f; + + inline bool isVisible() const { + return opacity > 0; + } +}; + +struct BackgroundProperties { + inline BackgroundProperties() {} + float opacity = 1.0f; + Color color = {{ 0, 0, 0, 1 }}; + Faded image; +}; + +typedef mapbox::util::variant< + FillProperties, + LineProperties, + SymbolProperties, + RasterProperties, + BackgroundProperties, + std::false_type +> StyleProperties; + +template +const T &defaultStyleProperties(); + +} + +#endif diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp new file mode 100644 index 000000000..e46ece6f4 --- /dev/null +++ b/include/mbgl/style/types.hpp @@ -0,0 +1,213 @@ +#ifndef MBGL_STYLE_TYPES +#define MBGL_STYLE_TYPES + +#include + +#include +#include + +namespace mbgl { + +// Stores a premultiplied color, with all four channels ranging from 0..1 +typedef std::array Color; + + +template +struct Faded { + T from; + float fromScale; + T to; + float toScale; + float t; +}; + +// ------------------------------------------------------------------------------------------------- + +enum class StyleLayerType : uint8_t { + Unknown, + Fill, + Line, + Symbol, + Raster, + Background +}; + +MBGL_DEFINE_ENUM_CLASS(StyleLayerTypeClass, StyleLayerType, { + { StyleLayerType::Unknown, "unknown" }, + { StyleLayerType::Fill, "fill" }, + { StyleLayerType::Line, "line" }, + { StyleLayerType::Symbol, "symbol" }, + { StyleLayerType::Raster, "raster" }, + { StyleLayerType::Background, "background" }, + { StyleLayerType(-1), "unknown" }, +}); + +// ------------------------------------------------------------------------------------------------- + +enum class SourceType : uint8_t { + Vector, + Raster, + GeoJSON, + Video, + Annotations +}; + +MBGL_DEFINE_ENUM_CLASS(SourceTypeClass, SourceType, { + { SourceType::Vector, "vector" }, + { SourceType::Raster, "raster" }, + { SourceType::GeoJSON, "geojson" }, + { SourceType::Video, "video" }, + { SourceType::Annotations, "annotations" }, +}); + +// ------------------------------------------------------------------------------------------------- + +enum class VisibilityType : bool { + Visible, + None, +}; + +MBGL_DEFINE_ENUM_CLASS(VisibilityTypeClass, VisibilityType, { + { VisibilityType::Visible, "visible" }, + { VisibilityType::None, "none" }, +}); + +// ------------------------------------------------------------------------------------------------- + +enum class CapType : uint8_t { + Round, + Butt, + Square, +}; + +MBGL_DEFINE_ENUM_CLASS(CapTypeClass, CapType, { + { CapType::Round, "round" }, + { CapType::Butt, "butt" }, + { CapType::Square, "square" }, +}); + +// ------------------------------------------------------------------------------------------------- + +enum class JoinType : uint8_t { + Miter, + Bevel, + Round, + // the following two types are for internal use only + FakeRound, + FlipBevel +}; + +MBGL_DEFINE_ENUM_CLASS(JoinTypeClass, JoinType, { + { JoinType::Miter, "miter" }, + { JoinType::Bevel, "bevel" }, + { JoinType::Round, "round" }, + { JoinType::FakeRound, "fakeround" }, + { JoinType::FlipBevel, "flipbevel" }, +}); + +// ------------------------------------------------------------------------------------------------- + +enum class TranslateAnchorType : bool { + Map, + Viewport +}; + +MBGL_DEFINE_ENUM_CLASS(TranslateAnchorTypeClass, TranslateAnchorType, { + { TranslateAnchorType::Map, "map" }, + { TranslateAnchorType::Viewport, "viewport" }, +}); + +// ------------------------------------------------------------------------------------------------- + +enum class RotateAnchorType : bool { + Map, + Viewport, +}; + +MBGL_DEFINE_ENUM_CLASS(RotateAnchorTypeClass, RotateAnchorType, { + { RotateAnchorType::Map, "map" }, + { RotateAnchorType::Viewport, "viewport" }, +}); + +// ------------------------------------------------------------------------------------------------- + +enum class PlacementType : bool { + Point, + Line, +}; + +MBGL_DEFINE_ENUM_CLASS(PlacementTypeClass, PlacementType, { + { PlacementType::Point, "point" }, + { PlacementType::Line, "line" }, +}); + +// ------------------------------------------------------------------------------------------------- + +enum class RotationAlignmentType : bool { + Map, + Viewport, +}; + +MBGL_DEFINE_ENUM_CLASS(RotationAlignmentTypeClass, RotationAlignmentType, { + { RotationAlignmentType::Map, "map" }, + { RotationAlignmentType::Viewport, "viewport" }, +}); + +// ------------------------------------------------------------------------------------------------- + +enum class TextJustifyType : uint8_t { + Center, + Left, + Right +}; + +MBGL_DEFINE_ENUM_CLASS(TextJustifyTypeClass, TextJustifyType, { + { TextJustifyType::Center, "center" }, + { TextJustifyType::Left, "left" }, + { TextJustifyType::Right, "right" }, +}); + +// ------------------------------------------------------------------------------------------------- + +enum class TextAnchorType : uint8_t { + Center, + Left, + Right, + Top, + Bottom, + TopLeft, + TopRight, + BottomLeft, + BottomRight +}; + +MBGL_DEFINE_ENUM_CLASS(TextAnchorTypeClass, TextAnchorType, { + { TextAnchorType::Center, "center" }, + { TextAnchorType::Left, "left" }, + { TextAnchorType::Right, "right" }, + { TextAnchorType::Top, "top" }, + { TextAnchorType::Bottom, "bottom" }, + { TextAnchorType::TopLeft, "top-left" }, + { TextAnchorType::TopRight, "top-right" }, + { TextAnchorType::BottomLeft, "bottom-left" }, + { TextAnchorType::BottomRight, "bottom-right" } +}); + +// ------------------------------------------------------------------------------------------------- + +enum class TextTransformType : uint8_t { + None, + Uppercase, + Lowercase, +}; + +MBGL_DEFINE_ENUM_CLASS(TextTransformTypeClass, TextTransformType, { + { TextTransformType::None, "none" }, + { TextTransformType::Uppercase, "uppercase" }, + { TextTransformType::Lowercase, "lowercase" }, +}); + +} + +#endif + diff --git a/include/mbgl/util/chrono.hpp b/include/mbgl/util/chrono.hpp new file mode 100644 index 000000000..df8c5e623 --- /dev/null +++ b/include/mbgl/util/chrono.hpp @@ -0,0 +1,16 @@ +#ifndef MBGL_UTIL_CHRONO +#define MBGL_UTIL_CHRONO + +#include + +namespace mbgl { + +using Clock = std::chrono::steady_clock; +using SystemClock = std::chrono::system_clock; + +using TimePoint = Clock::time_point; +using Duration = Clock::duration; + +} + +#endif diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp new file mode 100644 index 000000000..bb5aad2af --- /dev/null +++ b/include/mbgl/util/constants.hpp @@ -0,0 +1,39 @@ +#ifndef MBGL_UTIL_CONSTANTS +#define MBGL_UTIL_CONSTANTS + +#include +#include +#include + +namespace mbgl { + +namespace util { + +extern const float tileSize; + +extern const double DEG2RAD; +extern const double RAD2DEG; +extern const double M2PI; +extern const double EARTH_RADIUS_M; +extern const double LATITUDE_MAX; + +} + +namespace debug { + +extern const bool tileParseWarnings; +extern const bool styleParseWarnings; +extern const bool spriteWarnings; +extern const bool renderWarnings; +extern const bool renderTree; +extern const bool labelTextMissingWarning; +extern const bool missingFontStackWarning; +extern const bool missingFontFaceWarning; +extern const bool glyphWarning; +extern const bool shapingWarning; + +} + +} + +#endif diff --git a/include/mbgl/util/enum.hpp b/include/mbgl/util/enum.hpp new file mode 100644 index 000000000..3c3e4a5c4 --- /dev/null +++ b/include/mbgl/util/enum.hpp @@ -0,0 +1,55 @@ +#ifndef MBGL_UTIL_ENUM +#define MBGL_UTIL_ENUM + +#include +#include + +namespace mbgl { + +template +struct EnumValue { + const Type value; + const char *name; +}; + +template *names, const size_t length> +struct Enum { + using Type = EnumName; + Type value; + static const constexpr size_t l = length; +private: + static constexpr inline bool compare(const char *a, const char *b) { + return *a == *b && (*a == '\0' || compare(a + 1, b + 1)); + } + static constexpr inline const char *lookup_type(Type e, EnumValue const * const list, size_t r) { + return r == 0 ? "" : list->value == e ? list->name : lookup_type(e, list + 1, r - 1); + } + static constexpr inline Type lookup_name(const char *n, EnumValue const * const list, size_t r) { + return r == 0 ? Type(-1) : compare(list->name, n) ? list->value : lookup_name(n, list + 1, r - 1); + } +public: + inline constexpr Enum(const char *n) : value(lookup_name(n, names, length)) {} + inline constexpr Enum(const std::string &n) : value(lookup_name(n.c_str(), names, length)) {} + inline constexpr Enum(Type t) : value(t) {} + + inline void operator=(const char *n) { value = lookup_name(n, names, length); } + inline void operator=(const std::string &n) { *this = n.c_str(); } + inline void operator=(Type t) { value = t; } + + inline constexpr bool valid() const { return value != Type(-1); } + + inline constexpr const char *c_str() const { return lookup_type(value, names, length); } + inline std::string str() const { return c_str(); } + + inline constexpr operator Type() const { return value; } +}; + +#define MBGL_DEFINE_ENUM_CLASS(name, type, strings...) \ + const constexpr ::mbgl::EnumValue type##_names[] = strings; \ + using name = ::mbgl::Enum)>; \ + inline std::ostream& operator<<(std::ostream& os, type t) { return os << name(t).str(); } + +} + +#endif + diff --git a/include/mbgl/util/exception.hpp b/include/mbgl/util/exception.hpp new file mode 100644 index 000000000..31fa693f8 --- /dev/null +++ b/include/mbgl/util/exception.hpp @@ -0,0 +1,52 @@ +#ifndef MBGL_UTIL_EXCEPTION +#define MBGL_UTIL_EXCEPTION + +#include + +namespace mbgl { +namespace util { + +struct Exception : std::runtime_error { + inline Exception(const char *msg) : std::runtime_error(msg) {} + inline Exception(const std::string &msg) : std::runtime_error(msg) {} +}; + +struct SpriteImageException : Exception { + inline SpriteImageException(const char *msg) : Exception(msg) {} + inline SpriteImageException(const std::string &msg) : Exception(msg) {} +}; + +struct GlyphRangeLoadingException : Exception { + inline GlyphRangeLoadingException(const char *msg) : Exception(msg) {} + inline GlyphRangeLoadingException(const std::string &msg) : Exception(msg) {} +}; + +struct MisuseException : Exception { + inline MisuseException(const char *msg) : Exception(msg) {} + inline MisuseException(const std::string &msg) : Exception(msg) {} +}; + +struct ShaderException : Exception { + inline ShaderException(const char *msg) : Exception(msg) {} + inline ShaderException(const std::string &msg) : Exception(msg) {} +}; + +struct SourceLoadingException : Exception { + inline SourceLoadingException(const char *msg) : Exception(msg) {} + inline SourceLoadingException(const std::string &msg) : Exception(msg) {} +}; + +struct SpriteLoadingException : Exception { + inline SpriteLoadingException(const char *msg) : Exception(msg) {} + inline SpriteLoadingException(const std::string &msg) : Exception(msg) {} +}; + +struct TileLoadingException : Exception { + inline TileLoadingException(const char *msg) : Exception(msg) {} + inline TileLoadingException(const std::string &msg) : Exception(msg) {} +}; + +} +} + +#endif diff --git a/include/mbgl/util/exclusive.hpp b/include/mbgl/util/exclusive.hpp new file mode 100644 index 000000000..bb3395996 --- /dev/null +++ b/include/mbgl/util/exclusive.hpp @@ -0,0 +1,30 @@ +#ifndef MBGL_UTIL_EXCLUSIVE +#define MBGL_UTIL_EXCLUSIVE + +#include +#include + + +namespace mbgl { +namespace util { + +template +class exclusive { +public: + inline exclusive(T* val, std::unique_ptr> mtx) : ptr(val), lock(std::move(mtx)) {} + + inline T* operator->() { return ptr; } + inline const T* operator->() const { return ptr; } + inline T* operator*() { return ptr; } + inline const T* operator*() const { return ptr; } + +private: + T *ptr; + std::unique_ptr> lock; +}; + + +} // end namespace util +} // end namespace mbgl + +#endif diff --git a/include/mbgl/util/geo.hpp b/include/mbgl/util/geo.hpp new file mode 100644 index 000000000..1f073ded8 --- /dev/null +++ b/include/mbgl/util/geo.hpp @@ -0,0 +1,66 @@ +#ifndef MBGL_UTIL_GEO +#define MBGL_UTIL_GEO + +namespace mbgl { + +class TileID; + +struct LatLng { + double latitude = 0; + double longitude = 0; + + inline LatLng(double lat = 0, double lon = 0) + : latitude(lat), longitude(lon) {} + + // Constructs a LatLng object with the top left position of the specified tile. + LatLng(const TileID& id); +}; + +struct ProjectedMeters { + double northing = 0; + double easting = 0; + + inline ProjectedMeters(double n = 0, double e = 0) + : northing(n), easting(e) {} +}; + +struct LatLngBounds { + LatLng sw = {90, 180}; + LatLng ne = {-90, -180}; + + inline LatLngBounds(LatLng sw_ = {90, 180}, LatLng ne_ = {-90, -180}) + : sw(sw_), ne(ne_) {} + + // Constructs a LatLngBounds object with the tile's exact boundaries. + LatLngBounds(const TileID& id); + + inline void extend(const LatLng& point) { + if (point.latitude < sw.latitude) sw.latitude = point.latitude; + if (point.latitude > ne.latitude) ne.latitude = point.latitude; + if (point.longitude < sw.longitude) sw.longitude = point.longitude; + if (point.longitude > ne.longitude) ne.longitude = point.longitude; + } + + inline void extend(const LatLngBounds& bounds) { + extend(bounds.sw); + extend(bounds.ne); + } + + inline bool contains(const LatLng& point) const { + return (point.latitude >= sw.latitude && + point.latitude <= ne.latitude && + point.longitude >= sw.longitude && + point.longitude <= ne.longitude); + } + + inline bool intersects(const LatLngBounds area) const { + return (area.ne.latitude > sw.latitude && + area.sw.latitude < ne.latitude && + area.ne.longitude > sw.longitude && + area.sw.longitude < ne.longitude); + } +}; + +} + +#endif diff --git a/include/mbgl/util/gl_helper.hpp b/include/mbgl/util/gl_helper.hpp new file mode 100644 index 000000000..288fc2c68 --- /dev/null +++ b/include/mbgl/util/gl_helper.hpp @@ -0,0 +1,90 @@ +#ifndef MBGL_UTIL_GL_HELPER +#define MBGL_UTIL_GL_HELPER + +#include + +#include + +namespace { + +template +class Preserve { +public: + Preserve() : data(Create()) {} + ~Preserve() { Destroy(data); } + +private: + const T data; +}; + +inline bool getBlend() { + return glIsEnabled(GL_BLEND); +} + +inline void setBlend(const bool& enabled) { + enabled ? MBGL_CHECK_ERROR(glEnable(GL_BLEND)) : MBGL_CHECK_ERROR(glDisable(GL_BLEND)); +} + +inline std::array getClearColor() { + std::array color; + MBGL_CHECK_ERROR(glGetFloatv(GL_COLOR_CLEAR_VALUE, color.data())); + return color; +} + +inline void setClearColor(const std::array& color) { + MBGL_CHECK_ERROR(glClearColor(color[0], color[1], color[2], color[3])); +} + + +inline std::array getBlendFunc() { + GLint func[2]; + glGetIntegerv(GL_BLEND_SRC_ALPHA, &func[0]); + glGetIntegerv(GL_BLEND_DST_ALPHA, &func[1]); + return {{ static_cast(func[0]), static_cast(func[1]) }}; +} + +inline void setBlendFunc(const std::array& func) { + MBGL_CHECK_ERROR(glBlendFunc(func[0], func[1])); +} + +#ifndef GL_ES_VERSION_2_0 +inline std::array getPixelZoom() { + std::array zoom; + glGetDoublev(GL_ZOOM_X, &zoom[0]); + glGetDoublev(GL_ZOOM_Y, &zoom[1]); + return zoom; +} + +inline void setPixelZoom(const std::array& func) { + MBGL_CHECK_ERROR(glPixelZoom(func[0], func[1])); +} + + +inline std::array getRasterPos() { + std::array pos; + MBGL_CHECK_ERROR(glGetDoublev(GL_CURRENT_RASTER_POSITION, pos.data())); + return pos; +} + +inline void setRasterPos(const std::array& pos) { + MBGL_CHECK_ERROR(glRasterPos4d(pos[0], pos[1], pos[2], pos[3])); +} +#endif +} // end anonymous namespace + +namespace mbgl { +namespace gl { + +using PreserveBlend = Preserve; +using PreserveClearColor = Preserve, getClearColor, setClearColor>; +using PreserveBlendFunc = Preserve, getBlendFunc, setBlendFunc>; + +#ifndef GL_ES_VERSION_2_0 +using PreservePixelZoom = Preserve, getPixelZoom, setPixelZoom>; +using PreserveRasterPos = Preserve, getRasterPos, setRasterPos>; +#endif + +} +} + +#endif diff --git a/include/mbgl/util/image.hpp b/include/mbgl/util/image.hpp new file mode 100644 index 000000000..f58c2c098 --- /dev/null +++ b/include/mbgl/util/image.hpp @@ -0,0 +1,34 @@ +#ifndef MBGL_UTIL_IMAGE +#define MBGL_UTIL_IMAGE + +#include +#include + +namespace mbgl { +namespace util { + +std::string compress_png(int width, int height, const void *rgba); + + +class Image { +public: + explicit Image(const std::string &img); + + inline const char *getData() const { return img.get(); } + inline uint32_t getWidth() const { return width; } + inline uint32_t getHeight() const { return height; } + inline operator bool() const { return img && width && height; } + +private: + // loaded image dimensions + uint32_t width = 0, height = 0; + + // the raw image data + std::unique_ptr img; +}; + + +} +} + +#endif diff --git a/include/mbgl/util/mat4.hpp b/include/mbgl/util/mat4.hpp new file mode 100644 index 000000000..4279113d2 --- /dev/null +++ b/include/mbgl/util/mat4.hpp @@ -0,0 +1,45 @@ +// This is an incomplete port of http://glmatrix.net/ +// +// Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim +// that you wrote the original software. If you use this software in a +// product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef MBGL_UTIL_MAT4 +#define MBGL_UTIL_MAT4 + +#include + +namespace mbgl { + +typedef std::array mat4; + +namespace matrix { + +void identity(mat4& out); +void ortho(mat4& out, float left, float right, float bottom, float top, float near, float far); +void copy(mat4& out, const mat4& a); +void translate(mat4& out, const mat4& a, float x, float y, float z); +void rotate_z(mat4& out, const mat4& a, float rad); +void scale(mat4& out, const mat4& a, float x, float y, float z); +void multiply(mat4& out, const mat4& a, const mat4& b); + +} +} + +#endif diff --git a/include/mbgl/util/math.hpp b/include/mbgl/util/math.hpp new file mode 100644 index 000000000..37b1dd343 --- /dev/null +++ b/include/mbgl/util/math.hpp @@ -0,0 +1,136 @@ +#ifndef MBGL_UTIL_MATH +#define MBGL_UTIL_MATH + +#include +#include + +#include + +namespace mbgl { +namespace util { + + +template +inline T max(T a, T b) { + return b > a ? b : a; +} + +template +inline T max(T a, T b, T c) { + return max(max(a, b), c); +} + +template +inline T max(T a, T b, T c, T d) { + return max(max(a, b), max(c, d)); +} + +template +inline T min(T a, T b) { + return b < a ? b : a; +} + +template +inline T min(T a, T b, T c) { + return min(min(a, b), c); +} + +template +inline T min(T a, T b, T c, T d) { + return min(min(a, b), min(c, d)); +} + +// Find the angle of the two vectors, solving the formula for the cross product +// a x b = |a||b|sin(θ) for θ. +template +inline T angle_between(S ax, S ay, S bx, S by) { + return std::atan2((ax * by - ay * bx), ax * bx + ay * by); +} + +template +inline T angle_between(const vec2& a, const vec2& b) { + return angle_between(a.x, a.y, b.x, b.y); +} + +template +inline T angle_to(const vec2& a, const vec2& b) { + return std::atan2(a.y - b.y, a.x - b.x); +} + +// Reflect an angle around 0 degrees +template +inline std::array flip(const std::array& c) { + return {{ + static_cast(2 * M_PI - c[0]), + static_cast(2 * M_PI - c[1]) + }}; +} + +template +inline vec2 normal(const S1& a, const S2& b) { + T dx = b.x - a.x; + T dy = b.y - a.y; + T c = std::sqrt(dx * dx + dy * dy); + return { dx / c, dy / c }; +} + +template +inline T perp(const T& a) { + return T(-a.y, a.x); +} + +template +inline T dist(const S1& a, const S2& b) { + T dx = b.x - a.x; + T dy = b.y - a.y; + T c = std::sqrt(dx * dx + dy * dy); + return c; +} + +template +inline T length(T a, T b) { + return std::sqrt(a * a + b * b); +} + +// Take the magnitude of vector a. +template +inline T mag(const S& a) { + return std::sqrt(a.x * a.x + a.y * a.y); +} + +template +inline S unit(const S& a) { + auto magnitude = mag(a); + if (magnitude == 0) { + return a; + } + return a * (1 / magnitude); +} + +template +T clamp(T value, T min, T max) { + return value < min ? min : (value > max ? max : value); +} + +// Constrains n to the given range (including min, excluding max) via modular +// arithmetic. +template +T wrap(T value, T min, T max) { + T d = max - min; + return std::fmod((std::fmod((value - min), d) + d), d) + min; +} + +template +T smoothstep(T edge0, T edge1, T x) { + T t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1)); + return t * t * (T(3) - T(2) * t); +} + +// Computes the log2(x) rounded up to the next integer. +// (== number of bits required to store x) +uint32_t ceil_log2(uint64_t x); + +} +} + +#endif diff --git a/include/mbgl/util/noncopyable.hpp b/include/mbgl/util/noncopyable.hpp new file mode 100644 index 000000000..ada701efc --- /dev/null +++ b/include/mbgl/util/noncopyable.hpp @@ -0,0 +1,23 @@ +#ifndef MBGL_UTIL_NONCOPYABLE +#define MBGL_UTIL_NONCOPYABLE + +namespace mbgl { namespace util { + +namespace non_copyable_ +{ + +class noncopyable +{ +protected: + constexpr noncopyable() = default; + ~noncopyable() = default; + noncopyable( noncopyable const& ) = delete; + noncopyable& operator=(noncopyable const& ) = delete; +}; +} + +typedef non_copyable_::noncopyable noncopyable; + +}} + +#endif diff --git a/include/mbgl/util/parsedate.h b/include/mbgl/util/parsedate.h new file mode 100644 index 000000000..6905e361d --- /dev/null +++ b/include/mbgl/util/parsedate.h @@ -0,0 +1,38 @@ +#ifndef HEADER_PARSEDATE_H +#define HEADER_PARSEDATE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +time_t parse_date(const char *p); + +#ifdef __cplusplus +} +#endif + +#endif /* HEADER_PARSEDATE_H */ diff --git a/include/mbgl/util/projection.hpp b/include/mbgl/util/projection.hpp new file mode 100644 index 000000000..956390085 --- /dev/null +++ b/include/mbgl/util/projection.hpp @@ -0,0 +1,65 @@ +#ifndef MBGL_UTIL_PROJECTION +#define MBGL_UTIL_PROJECTION + +#include +#include + +#include + +namespace mbgl { + +class Projection { + +public: + static inline void getWorldBoundsMeters(ProjectedMeters &sw, ProjectedMeters &ne) { + const double d = util::EARTH_RADIUS_M * M_PI; + + sw.easting = -d; + sw.northing = -d; + + ne.easting = d; + ne.northing = d; + } + + static inline void getWorldBoundsLatLng(LatLng &sw, LatLng &ne) { + ProjectedMeters projectedMetersSW = ProjectedMeters(); + ProjectedMeters projectedMetersNE = ProjectedMeters(); + + getWorldBoundsMeters(projectedMetersSW, projectedMetersNE); + + sw = latLngForProjectedMeters(projectedMetersSW); + ne = latLngForProjectedMeters(projectedMetersNE); + } + + static inline double getMetersPerPixelAtLatitude(const double lat, const double zoom) { + const double mapPixelWidthAtZoom = std::pow(2.0, zoom) * util::tileSize; + const double constrainedLatitude = ::fmin(::fmax(lat, -util::LATITUDE_MAX), util::LATITUDE_MAX); + + return std::cos(constrainedLatitude * util::DEG2RAD) * util::M2PI * util::EARTH_RADIUS_M / mapPixelWidthAtZoom; + } + + static inline const ProjectedMeters projectedMetersForLatLng(const LatLng latLng) { + const double constrainedLatitude = ::fmin(::fmax(latLng.latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX); + + const double m = 1 - 1e-15; + const double f = ::fmin(::fmax(std::sin(util::DEG2RAD * constrainedLatitude), -m), m); + + const double easting = util::EARTH_RADIUS_M * latLng.longitude * util::DEG2RAD; + const double northing = 0.5 * util::EARTH_RADIUS_M * std::log((1 + f) / (1 - f)); + + return ProjectedMeters(northing, easting); + } + + static inline const LatLng latLngForProjectedMeters(const ProjectedMeters projectedMeters) { + double latitude = (2 * std::atan(std::exp(projectedMeters.northing / util::EARTH_RADIUS_M)) - (M_PI / 2)) * util::RAD2DEG; + double longitude = projectedMeters.easting * util::RAD2DEG / util::EARTH_RADIUS_M; + + latitude = ::fmin(::fmax(latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX); + + return LatLng(latitude, longitude); + } +}; + +} + +#endif diff --git a/include/mbgl/util/ptr.hpp b/include/mbgl/util/ptr.hpp new file mode 100644 index 000000000..6e02f956f --- /dev/null +++ b/include/mbgl/util/ptr.hpp @@ -0,0 +1,29 @@ +#ifndef MBGL_UTIL_PTR +#define MBGL_UTIL_PTR + +#include +#include + +namespace mbgl { +namespace util { + +template +class ptr : public ::std::shared_ptr { +public: + template + inline ptr(Args &&... args) + : ::std::shared_ptr(::std::forward(args)...) {} + + inline auto operator->() const -> decltype(this->::std::shared_ptr::operator->()) { + assert(*this); + return ::std::shared_ptr::operator->(); + } + inline auto operator*() const -> decltype(this->::std::shared_ptr::operator*()) { + assert(*this); + return ::std::shared_ptr::operator*(); + } +}; +} +} + +#endif \ No newline at end of file diff --git a/include/mbgl/util/recursive_wrapper.hpp b/include/mbgl/util/recursive_wrapper.hpp new file mode 100644 index 000000000..54b27634a --- /dev/null +++ b/include/mbgl/util/recursive_wrapper.hpp @@ -0,0 +1,127 @@ +#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP + +#include + +namespace mapbox { namespace util { + +template +class recursive_wrapper +{ +public: + using type = T; +private: + + T* p_; + +public: + + ~recursive_wrapper(); + recursive_wrapper(); + + recursive_wrapper(recursive_wrapper const& operand); + recursive_wrapper(T const& operand); + recursive_wrapper(recursive_wrapper&& operand); + recursive_wrapper(T&& operand); + +private: + + void assign(const T& rhs); + +public: + + inline recursive_wrapper& operator=(recursive_wrapper const& rhs) + { + assign( rhs.get() ); + return *this; + } + + inline recursive_wrapper& operator=(T const& rhs) + { + assign( rhs ); + return *this; + } + + inline void swap(recursive_wrapper& operand) noexcept + { + T* temp = operand.p_; + operand.p_ = p_; + p_ = temp; + } + + + recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept + { + swap(rhs); + return *this; + } + + recursive_wrapper& operator=(T&& rhs) + { + get() = std::move(rhs); + return *this; + } + + +public: + + T& get() { return *get_pointer(); } + const T& get() const { return *get_pointer(); } + T* get_pointer() { return p_; } + const T* get_pointer() const { return p_; } + operator T const&() const { return this->get(); } + operator T&() { return this->get(); } +}; + +template +recursive_wrapper::~recursive_wrapper() +{ + delete p_; +} + +template +recursive_wrapper::recursive_wrapper() + : p_(new T) +{ +} + +template +recursive_wrapper::recursive_wrapper(recursive_wrapper const& operand) + : p_(new T( operand.get() )) +{ +} + +template +recursive_wrapper::recursive_wrapper(T const& operand) + : p_(new T(operand)) +{ +} + +template +recursive_wrapper::recursive_wrapper(recursive_wrapper&& operand) + : p_(operand.p_) +{ + operand.p_ = nullptr; +} + +template +recursive_wrapper::recursive_wrapper(T&& operand) + : p_(new T( std::move(operand) )) +{ +} + +template +void recursive_wrapper::assign(const T& rhs) +{ + this->get() = rhs; +} + +template +inline void swap(recursive_wrapper& lhs, recursive_wrapper& rhs) noexcept +{ + lhs.swap(rhs); +} + +}} + +#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP diff --git a/include/mbgl/util/std.hpp b/include/mbgl/util/std.hpp new file mode 100644 index 000000000..0e2d3346b --- /dev/null +++ b/include/mbgl/util/std.hpp @@ -0,0 +1,30 @@ +#ifndef MBGL_UTIL_STD +#define MBGL_UTIL_STD + +#include +#include +#include + +namespace mbgl { +namespace util { + +template +void erase_if(Container &container, ForwardIterator it, const ForwardIterator end, Predicate pred) { + while (it != end) { + if (pred(*it)) { + container.erase(it++); + } else { + ++it; + } + } +} + +template +void erase_if(Container &container, Predicate pred) { + erase_if(container, container.begin(), container.end(), pred); +} + +} +} + +#endif diff --git a/include/mbgl/util/string.hpp b/include/mbgl/util/string.hpp new file mode 100644 index 000000000..672ead244 --- /dev/null +++ b/include/mbgl/util/string.hpp @@ -0,0 +1,41 @@ +#ifndef MBGL_UTIL_STRING +#define MBGL_UTIL_STRING + +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#include +#pragma GCC diagnostic pop + +namespace mbgl { +namespace util { + +template +inline std::string toString(Args&&... args) { + return boost::lexical_cast(::std::forward(args)...); +} + +// boost::lexical_cast() treats this as a character, but we are using it as number types. +inline std::string toString(int8_t num) { + return boost::lexical_cast(int(num)); +} + + +template +inline std::string sprintf(const char *msg, Args... args) { + char res[max]; + int len = snprintf(res, sizeof(res), msg, args...); + return std::string(res, len); +} + +template +inline std::string sprintf(const std::string &msg, Args... args) { + return sprintf(msg.c_str(), args...); +} + +} +} + +#endif diff --git a/include/mbgl/util/time.hpp b/include/mbgl/util/time.hpp new file mode 100644 index 000000000..c2e931b10 --- /dev/null +++ b/include/mbgl/util/time.hpp @@ -0,0 +1,19 @@ +#ifndef MBGL_UTIL_TIME +#define MBGL_UTIL_TIME + +#include +#include +#include + +namespace mbgl { + +namespace util { + +// Returns the RFC1123 formatted date. E.g. "Tue, 04 Nov 2014 02:13:24 GMT" +std::string rfc1123(std::time_t time); + +} + +} + +#endif diff --git a/include/mbgl/util/utf.hpp b/include/mbgl/util/utf.hpp new file mode 100644 index 000000000..d6ba2a1f2 --- /dev/null +++ b/include/mbgl/util/utf.hpp @@ -0,0 +1,24 @@ +#ifndef MBGL_UTIL_UTF +#define MBGL_UTIL_UTF + +#include + +#include + +namespace mbgl { + +namespace util { + +class utf8_to_utf32 { + public: + static std::u32string convert(std::string const& utf8) + { + boost::u8_to_u32_iterator begin(utf8.begin()); + boost::u8_to_u32_iterator end(utf8.end()); + return std::u32string(begin,end); + } +}; + +}} + +#endif diff --git a/include/mbgl/util/util.hpp b/include/mbgl/util/util.hpp new file mode 100644 index 000000000..2b0fd9cdd --- /dev/null +++ b/include/mbgl/util/util.hpp @@ -0,0 +1,17 @@ +#ifndef MBGL_UTIL_UTIL +#define MBGL_UTIL_UTIL + +#ifdef DEBUG + +#include +#define MBGL_STORE_THREAD(tid) const std::thread::id tid = std::this_thread::get_id(); +#define MBGL_VERIFY_THREAD(tid) assert(tid == std::this_thread::get_id()); + +#else + +#define MBGL_STORE_THREAD(tid) +#define MBGL_VERIFY_THREAD(tid) + +#endif + +#endif diff --git a/include/mbgl/util/uv.hpp b/include/mbgl/util/uv.hpp new file mode 100644 index 000000000..9198b0fd1 --- /dev/null +++ b/include/mbgl/util/uv.hpp @@ -0,0 +1,105 @@ +#ifndef MBGL_UTIL_UV +#define MBGL_UTIL_UV + +#include +#include + +typedef struct uv_handle_s uv_handle_t; +typedef struct uv_async_s uv_async_t; +typedef struct uv_timer_s uv_timer_t; +typedef struct uv_loop_s uv_loop_t; +typedef struct uv_fs_s uv_fs_t; + +namespace uv { + +class rwlock; +class loop; +class async; +class mutex; +class cond; + +class lock { +public: + lock(mutex &); + lock(const std::unique_ptr &); + lock(const lock &) = delete; + lock(lock &&lock); + lock &operator=(const lock &lock) = delete; + lock &operator=(lock &&lock); + ~lock(); +private: + mutex *mtx = nullptr; +}; + +class readlock { +public: + readlock(rwlock &); + readlock(const std::unique_ptr &); + readlock(const readlock &) = delete; + readlock(readlock &&lock); + readlock &operator=(const readlock &lock) = delete; + readlock &operator=(readlock &&lock); + ~readlock(); +private: + rwlock *mtx = nullptr; +}; + +class writelock { +public: + writelock(rwlock &); + writelock(const std::unique_ptr &); + writelock(const writelock &) = delete; + writelock(writelock &&lock); + writelock &operator=(const writelock &lock) = delete; + writelock &operator=(writelock &&lock); + ~writelock(); +private: + rwlock *mtx = nullptr; +}; + +template +class exclusive { +public: + exclusive(T& val, mutex &mtx) : ptr(&val), lock(mtx) {} + exclusive(T *val, mutex &mtx) : ptr(val), lock(mtx) {} + exclusive(mutex &mtx) : lock(mtx) {} + exclusive(const std::unique_ptr &mtx) : lock(mtx) {} + exclusive(const exclusive &) = delete; + exclusive(exclusive &&) = default; + exclusive &operator=(const exclusive &) = delete; + exclusive &operator=(exclusive &&) = default; + + T *operator->() { return ptr; } + const T *operator->() const { return ptr; } + T *operator*() { return ptr; } + const T *operator*() const { return ptr; } + operator T&() { return *ptr; } + operator const T&() const { return *ptr; } + + void operator<<(T& val) { operator<<(&val); } + void operator<<(T *val) { + if (ptr) { + throw std::runtime_error("exclusive<> was assigned before"); + } + ptr = val; + } + +private: + T *ptr = nullptr; + class lock lock; +}; + + + +const char *getFileRequestError(uv_fs_t *req); + +template +void close(T *specific) { + uv_close(reinterpret_cast(specific), [](uv_handle_t *generic) { + delete reinterpret_cast(generic); + }); +} + +} + +#endif diff --git a/include/mbgl/util/variant.hpp b/include/mbgl/util/variant.hpp new file mode 100644 index 000000000..a3cdea63a --- /dev/null +++ b/include/mbgl/util/variant.hpp @@ -0,0 +1,793 @@ +#ifndef MAPBOX_UTIL_VARIANT_HPP +#define MAPBOX_UTIL_VARIANT_HPP + +#include +#include +#include +#include // runtime_error +#include // operator new +#include // size_t +#include +#include + +#include "recursive_wrapper.hpp" + +#ifdef _MSC_VER + // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx + #ifdef NDEBUG + #define VARIANT_INLINE __forceinline + #else + #define VARIANT_INLINE __declspec(noinline) + #endif +#else + #ifdef NDEBUG + #define VARIANT_INLINE inline __attribute__((always_inline)) + #else + #define VARIANT_INLINE __attribute__((noinline)) + #endif +#endif + +#define VARIANT_MAJOR_VERSION 0 +#define VARIANT_MINOR_VERSION 1 +#define VARIANT_PATCH_VERSION 0 + +// translates to 100 +#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION) + +namespace mapbox { namespace util { + +// static visitor +template +struct static_visitor +{ + using result_type = R; +protected: + static_visitor() {} + ~static_visitor() {} +}; + +namespace detail { + +static constexpr std::size_t invalid_value = std::size_t(-1); + +template +struct direct_type; + +template +struct direct_type +{ + static constexpr std::size_t index = std::is_same::value + ? sizeof...(Types) : direct_type::index; +}; + +template +struct direct_type +{ + static constexpr std::size_t index = invalid_value; +}; + +template +struct convertible_type; + +template +struct convertible_type +{ + static constexpr std::size_t index = std::is_convertible::value + ? sizeof...(Types) : convertible_type::index; +}; + +template +struct convertible_type +{ + static constexpr std::size_t index = invalid_value; +}; + +template +struct value_traits +{ + static constexpr std::size_t direct_index = direct_type::index; + static constexpr std::size_t index = + (direct_index == invalid_value) ? convertible_type::index : direct_index; +}; + +template +struct is_valid_type; + +template +struct is_valid_type +{ + static constexpr bool value = std::is_convertible::value + || is_valid_type::value; +}; + +template +struct is_valid_type : std::false_type {}; + +template +struct select_type +{ + static_assert(N < sizeof...(Types), "index out of bounds"); +}; + +template +struct select_type +{ + using type = typename select_type::type; +}; + +template +struct select_type<0, T, Types...> +{ + using type = T; +}; + + +template +struct enable_if_type { using type = R; }; + +template +struct result_of_unary_visit +{ + using type = typename std::result_of::type; +}; + +template +struct result_of_unary_visit::type > +{ + using type = typename F::result_type; +}; + +template +struct result_of_binary_visit +{ + using type = typename std::result_of::type; +}; + + +template +struct result_of_binary_visit::type > +{ + using type = typename F::result_type; +}; + + +} // namespace detail + + +template +struct static_max; + +template +struct static_max +{ + static const std::size_t value = arg; +}; + +template +struct static_max +{ + static const std::size_t value = arg1 >= arg2 ? static_max::value : + static_max::value; +}; + +template +struct variant_helper; + +template +struct variant_helper +{ + VARIANT_INLINE static void destroy(const std::size_t id, void * data) + { + if (id == sizeof...(Types)) + { + reinterpret_cast(data)->~T(); + } + else + { + variant_helper::destroy(id, data); + } + } + + VARIANT_INLINE static void move(const std::size_t old_id, void * old_value, void * new_value) + { + if (old_id == sizeof...(Types)) + { + new (new_value) T(std::move(*reinterpret_cast(old_value))); + //std::memcpy(new_value, old_value, sizeof(T)); + // ^^ DANGER: this should only be considered for relocatable types e.g built-in types + // Also, I don't see any measurable performance benefit just yet + } + else + { + variant_helper::move(old_id, old_value, new_value); + } + } + + VARIANT_INLINE static void copy(const std::size_t old_id, const void * old_value, void * new_value) + { + if (old_id == sizeof...(Types)) + { + new (new_value) T(*reinterpret_cast(old_value)); + } + else + { + variant_helper::copy(old_id, old_value, new_value); + } + } +}; + +template<> struct variant_helper<> +{ + VARIANT_INLINE static void destroy(const std::size_t, void *) {} + VARIANT_INLINE static void move(const std::size_t, void *, void *) {} + VARIANT_INLINE static void copy(const std::size_t, const void *, void *) {} +}; + +namespace detail { + +template +struct unwrapper +{ + T const& operator() (T const& obj) const + { + return obj; + } + + T& operator() (T & obj) const + { + return obj; + } +}; + + +template +struct unwrapper> +{ + auto operator() (recursive_wrapper const& obj) const + -> typename recursive_wrapper::type const& + { + return obj.get(); + } +}; + + +template +struct dispatcher; + +template +struct dispatcher +{ + using result_type = R; + VARIANT_INLINE static result_type apply_const(V const& v, F f) + { + if (v.get_type_index() == sizeof...(Types)) + { + return f(unwrapper()(v. template get())); + } + else + { + return dispatcher::apply_const(v, f); + } + } + + VARIANT_INLINE static result_type apply(V & v, F f) + { + if (v.get_type_index() == sizeof...(Types)) + { + return f(unwrapper()(v. template get())); + } + else + { + return dispatcher::apply(v, f); + } + } +}; + +template +struct dispatcher +{ + using result_type = R; + VARIANT_INLINE static result_type apply_const(V const&, F) + { + throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); + } + + VARIANT_INLINE static result_type apply(V &, F) + { + throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); + } +}; + + +template +struct binary_dispatcher_rhs; + +template +struct binary_dispatcher_rhs +{ + using result_type = R; + VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) + { + if (rhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(unwrapper()(lhs. template get()), + unwrapper()(rhs. template get())); + } + else + { + return binary_dispatcher_rhs::apply_const(lhs, rhs, f); + } + } + + VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) + { + if (rhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(unwrapper()(lhs. template get()), + unwrapper()(rhs. template get())); + } + else + { + return binary_dispatcher_rhs::apply(lhs, rhs, f); + } + } + +}; + +template +struct binary_dispatcher_rhs +{ + using result_type = R; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } + VARIANT_INLINE static result_type apply(V &, V &, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } +}; + + +template +struct binary_dispatcher_lhs; + +template +struct binary_dispatcher_lhs +{ + using result_type = R; + VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) + { + if (lhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(lhs. template get(), rhs. template get()); + } + else + { + return binary_dispatcher_lhs::apply_const(lhs, rhs, f); + } + } + + VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) + { + if (lhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(lhs. template get(), rhs. template get()); + } + else + { + return binary_dispatcher_lhs::apply(lhs, rhs, f); + } + } + +}; + +template +struct binary_dispatcher_lhs +{ + using result_type = R; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } + + VARIANT_INLINE static result_type apply(V &, V &, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } +}; + +template +struct binary_dispatcher; + +template +struct binary_dispatcher +{ + using result_type = R; + VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f) + { + if (v0.get_type_index() == sizeof...(Types)) + { + if (v0.get_type_index() == v1.get_type_index()) + { + return f(v0. template get(), v1. template get()); // call binary functor + } + else + { + return binary_dispatcher_rhs::apply_const(v0, v1, f); + } + } + else if (v1.get_type_index() == sizeof...(Types)) + { + return binary_dispatcher_lhs::apply_const(v0, v1, f); + } + return binary_dispatcher::apply_const(v0, v1, f); + } + + VARIANT_INLINE static result_type apply(V & v0, V & v1, F f) + { + if (v0.get_type_index() == sizeof...(Types)) + { + if (v0.get_type_index() == v1.get_type_index()) + { + return f(v0. template get(), v1. template get()); // call binary functor + } + else + { + return binary_dispatcher_rhs::apply(v0, v1, f); + } + } + else if (v1.get_type_index() == sizeof...(Types)) + { + return binary_dispatcher_lhs::apply(v0, v1, f); + } + return binary_dispatcher::apply(v0, v1, f); + } +}; + +template +struct binary_dispatcher +{ + using result_type = R; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } + + VARIANT_INLINE static result_type apply(V &, V &, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } +}; + +// comparator functors +struct equal_comp +{ + template + bool operator()(T const& lhs, T const& rhs) const + { + return lhs == rhs; + } +}; + +struct less_comp +{ + template + bool operator()(T const& lhs, T const& rhs) const + { + return lhs < rhs; + } +}; + +template +class comparer +{ +public: + explicit comparer(Variant const& lhs) noexcept + : lhs_(lhs) {} + comparer& operator=(comparer const&) = delete; + // visitor + template + bool operator()(T const& rhs_content) const + { + T const& lhs_content = lhs_.template get(); + return Comp()(lhs_content, rhs_content); + } +private: + Variant const& lhs_; +}; + + +} // namespace detail + +struct no_init {}; + +template +class variant +{ +private: + + static const std::size_t data_size = static_max::value; + static const std::size_t data_align = static_max::value; + + using data_type = typename std::aligned_storage::type; + using helper_type = variant_helper; + + std::size_t type_index; + data_type data; + +public: + + VARIANT_INLINE variant() + : type_index(sizeof...(Types) - 1) + { + new (&data) typename detail::select_type<0, Types...>::type(); + } + + VARIANT_INLINE variant(no_init) + : type_index(detail::invalid_value) {} + + // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers + template ::type, Types...>::value>::type> + VARIANT_INLINE variant(T && val) noexcept + : type_index(detail::value_traits::type, Types...>::index) + { + constexpr std::size_t index = sizeof...(Types) - detail::value_traits::type, Types...>::index - 1; + using target_type = typename detail::select_type::type; + new (&data) target_type(std::forward(val)); // nothrow + } + + VARIANT_INLINE variant(variant const& old) + : type_index(old.type_index) + { + helper_type::copy(old.type_index, &old.data, &data); + } + + VARIANT_INLINE variant(variant&& old) noexcept + : type_index(old.type_index) + { + helper_type::move(old.type_index, &old.data, &data); + } + + friend void swap(variant & first, variant & second) + { + using std::swap; //enable ADL + swap(first.type_index, second.type_index); + swap(first.data, second.data); + } + + VARIANT_INLINE variant& operator=(variant other) + { + swap(*this, other); + return *this; + } + + // conversions + // move-assign + template + VARIANT_INLINE variant& operator=(T && rhs) noexcept + { + variant temp(std::forward(rhs)); + swap(*this, temp); + return *this; + } + + // copy-assign + template + VARIANT_INLINE variant& operator=(T const& rhs) + { + variant temp(rhs); + swap(*this, temp); + return *this; + } + + template + VARIANT_INLINE bool is() const + { + return (type_index == detail::direct_type::index); + } + + VARIANT_INLINE bool valid() const + { + return (type_index != detail::invalid_value); + } + + template + VARIANT_INLINE void set(Args&&... args) + { + helper_type::destroy(type_index, &data); + new (&data) T(std::forward(args)...); + type_index = detail::direct_type::index; + } + + // get() + template::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T& get() + { + if (type_index == detail::direct_type::index) + { + return *reinterpret_cast(&data); + } + else + { + throw std::runtime_error("in get()"); + } + } + + template ::index != detail::invalid_value) + >::type* = nullptr> + VARIANT_INLINE T const& get() const + { + if (type_index == detail::direct_type::index) + { + return *reinterpret_cast(&data); + } + else + { + throw std::runtime_error("in get()"); + } + } + + // get() - T stored as recursive_wrapper + template , Types...>::index != detail::invalid_value) + >::type* = nullptr> + VARIANT_INLINE T& get() + { + if (type_index == detail::direct_type, Types...>::index) + { + return (*reinterpret_cast*>(&data)).get(); + } + else + { + throw std::runtime_error("in get()"); + } + } + + template , Types...>::index != detail::invalid_value) + >::type* = nullptr> + VARIANT_INLINE T const& get() const + { + if (type_index == detail::direct_type, Types...>::index) + { + return (*reinterpret_cast const*>(&data)).get(); + } + else + { + throw std::runtime_error("in get()"); + } + } + VARIANT_INLINE std::size_t get_type_index() const + { + return type_index; + } + + VARIANT_INLINE int which() const noexcept + { + return static_cast(sizeof...(Types) - type_index - 1); + } + + // visitor + // unary + template + auto VARIANT_INLINE + static visit(V const& v, F f) + -> decltype(detail::dispatcher::type>::type, Types...>::apply_const(v, f)) + { + using R = typename detail::result_of_unary_visit::type>::type; + return detail::dispatcher::apply_const(v, f); + } + // non-const + template + auto VARIANT_INLINE + static visit(V & v, F f) + -> decltype(detail::dispatcher::type>::type, Types...>::apply(v, f)) + { + using R = typename detail::result_of_unary_visit::type>::type; + return detail::dispatcher::apply(v, f); + } + + // binary + // const + template + auto VARIANT_INLINE + static binary_visit(V const& v0, V const& v1, F f) + -> decltype(detail::binary_dispatcher::type>::type, Types...>::apply_const(v0, v1, f)) + { + using R = typename detail::result_of_binary_visit::type>::type; + return detail::binary_dispatcher::apply_const(v0, v1, f); + } + // non-const + template + auto VARIANT_INLINE + static binary_visit(V& v0, V& v1, F f) + -> decltype(detail::binary_dispatcher::type>::type, Types...>::apply(v0, v1, f)) + { + using R = typename detail::result_of_binary_visit::type>::type; + return detail::binary_dispatcher::apply(v0, v1, f); + } + + ~variant() noexcept + { + helper_type::destroy(type_index, &data); + } + + // comparison operators + // equality + VARIANT_INLINE bool operator==(variant const& rhs) const + { + if (this->get_type_index() != rhs.get_type_index()) + return false; + detail::comparer visitor(*this); + return visit(rhs, visitor); + } + // less than + VARIANT_INLINE bool operator<(variant const& rhs) const + { + if (this->get_type_index() != rhs.get_type_index()) + { + return this->get_type_index() < rhs.get_type_index(); + // ^^ borrowed from boost::variant + } + detail::comparer visitor(*this); + return visit(rhs, visitor); + } +}; + +// unary visitor interface + +// const +template +auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f)) +{ + return V::visit(v, f); +} +// non-const +template +auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f)) +{ + return V::visit(v, f); +} + +// binary visitor interface +// const +template +auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f)) +{ + return V::binary_visit(v0, v1, f); +} +// non-const +template +auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f)) +{ + return V::binary_visit(v0, v1, f); +} + +// getter interface +template +ResultType & get(T & var) +{ + return var.template get(); +} + +template +ResultType const& get(T const& var) +{ + return var.template get(); +} + + +}} + +#endif // MAPBOX_UTIL_VARIANT_HPP diff --git a/include/mbgl/util/variant_io.hpp b/include/mbgl/util/variant_io.hpp new file mode 100644 index 000000000..224732d97 --- /dev/null +++ b/include/mbgl/util/variant_io.hpp @@ -0,0 +1,41 @@ +#ifndef MAPBOX_UTIL_VARIANT_IO_HPP +#define MAPBOX_UTIL_VARIANT_IO_HPP + +#include "variant.hpp" + +namespace mapbox { namespace util { + +namespace detail { +// operator<< helper +template +class printer +{ +public: + explicit printer(Out & out) + : out_(out) {} + printer& operator=(printer const&) = delete; + +// visitor + template + void operator()(T const& operand) const + { + out_ << operand; + } +private: + Out & out_; +}; +} + +// operator<< +template +VARIANT_INLINE std::basic_ostream& +operator<< (std::basic_ostream& out, variant const& rhs) +{ + detail::printer> visitor(out); + apply_visitor(visitor, rhs); + return out; +} + +}} + +#endif //MAPBOX_UTIL_VARIANT_IO_HPP diff --git a/include/mbgl/util/vec.hpp b/include/mbgl/util/vec.hpp new file mode 100644 index 000000000..052dffcfa --- /dev/null +++ b/include/mbgl/util/vec.hpp @@ -0,0 +1,118 @@ +#ifndef MBGL_UTIL_VEC +#define MBGL_UTIL_VEC + +#include +#include +#include +#include +#include + +namespace mbgl { + +template +struct vec2 { + struct null {}; + typedef T Type; + + T x, y; + + inline vec2() {} + + template::has_quiet_NaN, int>::type = 0> + inline vec2(null) : x(std::numeric_limits::quiet_NaN()), y(std::numeric_limits::quiet_NaN()) {} + + template::has_quiet_NaN, int>::type = 0> + inline vec2(null) : x(std::numeric_limits::min()), y(std::numeric_limits::min()) {} + + inline vec2(const vec2& o) : x(o.x), y(o.y) {} + + template + inline vec2(const U& u) : x(u.x), y(u.y) {} + + inline vec2(T x_, T y_) : x(x_), y(y_) {} + + inline bool operator==(const vec2& rhs) const { + return x == rhs.x && y == rhs.y; + } + + template + inline typename std::enable_if::value, vec2>::type + operator*(O o) const { + return {x * o, y * o}; + } + + template + inline typename std::enable_if::value, vec2>::type & + operator*=(O o) { + x *= o; + y *= o; + } + + inline vec2 operator *(const std::array& matrix) { + return { x * matrix[0] + y * matrix[4] + matrix[12], x * matrix[1] + y * matrix[5] + matrix[13] }; + } + + template + inline typename std::enable_if::value, vec2>::type + operator-(O o) const { + return {x - o, y - o}; + } + + template + inline typename std::enable_if::value, vec2>::type + operator-(const O &o) const { + return vec2(x - o.x, y - o.y); + } + + template + inline typename std::enable_if::value, vec2>::type + operator+(const O &o) const { + return vec2(x + o.x, y + o.y); + } + + template + inline vec2 matMul(const M &m) const { + return {m[0] * x + m[1] * y, m[2] * x + m[3] * y}; + } + + template::has_quiet_NaN, int>::type = 0> + inline operator bool() const { + return !std::isnan(x) && !std::isnan(y); + } + + template::has_quiet_NaN, int>::type = 0> + inline operator bool() const { + return x != std::numeric_limits::min() && y != std::numeric_limits::min(); + } +}; + +template +struct vec3 { + T x, y, z; + + inline vec3() {} + inline vec3(const vec3& o) : x(o.x), y(o.y), z(o.z) {} + inline vec3(T x_, T y_, T z_) : x(x_), y(y_), z(z_) {} + inline bool operator==(const vec3& rhs) const { + return x == rhs.x && y == rhs.y && z == rhs.z; + } +}; + +template +struct vec4 { + T x, y, z, w; + + inline vec4() {} + inline vec4(const vec4& o) : x(o.x), y(o.y), z(o.z), w(o.w) {} + inline vec4(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) {} + inline bool operator==(const vec4& rhs) const { + return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w; + } +}; + + +typedef vec2 Coordinate; + +} + +#endif diff --git a/ios/Mapbox-iOS-SDK.podspec b/ios/Mapbox-iOS-SDK.podspec new file mode 100644 index 000000000..a7a0ed1ee --- /dev/null +++ b/ios/Mapbox-iOS-SDK.podspec @@ -0,0 +1,38 @@ +Pod::Spec.new do |m| + + m.name = 'Mapbox-iOS-SDK' + m.version = '2.0.0-pre.1.symbols' + + m.summary = 'Open source vector map solution for iOS with full styling capabilities.' + m.description = 'Open source OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa bindings.' + m.homepage = 'https://www.mapbox.com/mapbox-gl-ios/' + m.license = 'BSD' + m.author = { 'Mapbox' => 'mobile@mapbox.com' } + m.screenshot = 'https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/ios/screenshot.png' + m.social_media_url = 'https://twitter.com/mapbox' + m.documentation_url = 'https://www.mapbox.com/mapbox-gl-ios' + + m.source = { + :http => "http://mapbox.s3.amazonaws.com/mapbox-gl-native/ios/builds/mapbox-gl-ios-#{m.version.to_s}.zip", + :flatten => true + } + + m.platform = :ios + m.ios.deployment_target = '7.0' + + m.requires_arc = true + + m.preserve_paths = '**' + m.source_files = 'Headers/*.h', 'MGLDummy.m' + m.resource_bundle = { 'Mapbox' => 'Mapbox.bundle/*' } + m.vendored_library = 'libMapbox.a' + m.module_name = 'Mapbox' + + m.frameworks = 'CoreLocation', 'CoreTelephony', 'GLKit', 'ImageIO', 'MobileCoreServices', 'QuartzCore', 'SystemConfiguration' + m.libraries = 'c++', 'sqlite3', 'z' + m.xcconfig = { + 'OTHER_CPLUSPLUSFLAGS' => '-std=gnu++11 -stdlib=libc++', + 'OTHER_LDFLAGS' => '-ObjC', + } + +end diff --git a/ios/app/MBXAppDelegate.h b/ios/app/MBXAppDelegate.h new file mode 100644 index 000000000..da081fdcd --- /dev/null +++ b/ios/app/MBXAppDelegate.h @@ -0,0 +1,7 @@ +#import + +@interface MBXAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end \ No newline at end of file diff --git a/ios/app/MBXAppDelegate.m b/ios/app/MBXAppDelegate.m new file mode 100644 index 000000000..bca039739 --- /dev/null +++ b/ios/app/MBXAppDelegate.m @@ -0,0 +1,33 @@ +#import "MBXAppDelegate.h" +#import "MBXViewController.h" +#import + +@implementation MBXAppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + // Set access token, unless MGLAccountManager already read it in from Info.plist. + if ( ! [MGLAccountManager accessToken]) { + NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"]; + if (accessToken) { + // Store to preferences so that we can launch the app later on without having to specify + // token. + [[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:@"access_token"]; + } else { + // Try to retrieve from preferences, maybe we've stored them there previously and can reuse + // the token. + accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"access_token"]; + } + if ( ! accessToken) NSLog(@"No access token set. Mapbox vector tiles won't work."); + + [MGLAccountManager setAccessToken:accessToken]; + } + + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[MBXViewController new]]; + [self.window makeKeyAndVisible]; + + return YES; +} + +@end diff --git a/ios/app/MBXViewController.h b/ios/app/MBXViewController.h new file mode 100644 index 000000000..924d3af60 --- /dev/null +++ b/ios/app/MBXViewController.h @@ -0,0 +1,5 @@ +#import + +@interface MBXViewController : UIViewController + +@end diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm new file mode 100644 index 000000000..f5ec262bf --- /dev/null +++ b/ios/app/MBXViewController.mm @@ -0,0 +1,435 @@ +#import "MBXViewController.h" + +#import + +#import + +#import + +static UIColor *const kTintColor = [UIColor colorWithRed:0.120 green:0.550 blue:0.670 alpha:1.000]; + +static NSArray *const kStyleNames = @[ + @"Mapbox Streets", + @"Emerald", + @"Light", + @"Dark", + @"Bright", + @"Basic", + @"Outdoors", + @"Satellite", +]; + +static NSString *const kStyleVersion = @"7"; + +@interface MBXViewController () + +@property (nonatomic) MGLMapView *mapView; + +@end + +@implementation MBXViewController + +mbgl::Settings_NSUserDefaults *settings = nullptr; + +#pragma mark - Setup + +- (id)init +{ + self = [super init]; + + if (self) + { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveState:) name:UIApplicationDidEnterBackgroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(restoreState:) name:UIApplicationWillEnterForegroundNotification object:nil]; + } + + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds]; + self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.mapView.showsUserLocation = YES; + self.mapView.delegate = self; + [self.view addSubview:self.mapView]; + + self.view.tintColor = kTintColor; + self.navigationController.navigationBar.tintColor = kTintColor; + self.mapView.tintColor = kTintColor; + + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"settings.png"] + style:UIBarButtonItemStylePlain + target:self + action:@selector(showSettings)]; + + UIButton *titleButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [titleButton setFrame:CGRectMake(0, 0, 150, 40)]; + [titleButton setTitle:[kStyleNames firstObject] forState:UIControlStateNormal]; + [titleButton setTitleColor:kTintColor forState:UIControlStateNormal]; + [titleButton addTarget:self action:@selector(cycleStyles) forControlEvents:UIControlEventTouchUpInside]; + self.navigationItem.titleView = titleButton; + + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"TrackingLocationOffMask.png"] + style:UIBarButtonItemStylePlain + target:self + action:@selector(locateUser)]; + + settings = new mbgl::Settings_NSUserDefaults(); + [self restoreState:nil]; +} + +- (void)saveState:(__unused NSNotification *)notification +{ + if (self.mapView && settings) + { + settings->longitude = self.mapView.centerCoordinate.longitude; + settings->latitude = self.mapView.centerCoordinate.latitude; + settings->zoom = self.mapView.zoomLevel; + settings->bearing = self.mapView.direction; + settings->debug = self.mapView.isDebugActive; + settings->userTrackingMode = self.mapView.userTrackingMode; + settings->showsUserLocation = self.mapView.showsUserLocation; + settings->save(); + } +} + +- (void)restoreState:(__unused NSNotification *)notification +{ + if (self.mapView && settings) { + settings->load(); + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(settings->latitude, settings->longitude) zoomLevel:settings->zoom animated:NO]; + self.mapView.direction = settings->bearing; + self.mapView.userTrackingMode = settings->userTrackingMode; + self.mapView.showsUserLocation = settings->showsUserLocation; + [self.mapView setDebugActive:settings->debug]; + } +} + +- (NSUInteger)supportedInterfaceOrientations +{ + return UIInterfaceOrientationMaskAll; +} + +#pragma mark - Actions + +- (void)showSettings +{ + UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"Map Settings" + delegate:self + cancelButtonTitle:@"Cancel" + destructiveButtonTitle:nil + otherButtonTitles:@"Reset North", + @"Reset Position", + @"Toggle Debug", + @"Empty Memory", + @"Add 100 Points", + @"Add 1,000 Points", + @"Add 10,000 Points", + @"Add Test Shapes", + @"Remove Annotations", + nil]; + + [sheet showFromBarButtonItem:self.navigationItem.leftBarButtonItem animated:YES]; +} + +- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex +{ + if (buttonIndex == actionSheet.firstOtherButtonIndex) + { + [self.mapView resetNorth]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 1) + { + [self.mapView resetPosition]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 2) + { + [self.mapView toggleDebug]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 3) + { + [self.mapView emptyMemoryCache]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 4) + { + [self parseFeaturesAddingCount:100]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 5) + { + [self parseFeaturesAddingCount:1000]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 6) + { + [self parseFeaturesAddingCount:10000]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 7) + { + // PNW triangle + // + CLLocationCoordinate2D triangleCoordinates[3] = + { + CLLocationCoordinate2DMake(44, -122), + CLLocationCoordinate2DMake(46, -122), + CLLocationCoordinate2DMake(46, -121) + }; + + MGLPolygon *triangle = [MGLPolygon polygonWithCoordinates:triangleCoordinates count:3]; + + [self.mapView addAnnotation:triangle]; + + // Orcas Island hike + // + NSDictionary *hike = [NSJSONSerialization JSONObjectWithData: + [NSData dataWithContentsOfFile: + [[NSBundle mainBundle] pathForResource:@"polyline" ofType:@"geojson"]] + options:0 + error:nil]; + + NSArray *hikeCoordinatePairs = hike[@"features"][0][@"geometry"][@"coordinates"]; + + CLLocationCoordinate2D *polylineCoordinates = (CLLocationCoordinate2D *)malloc([hikeCoordinatePairs count] * sizeof(CLLocationCoordinate2D)); + + for (NSUInteger i = 0; i < [hikeCoordinatePairs count]; i++) + { + polylineCoordinates[i] = CLLocationCoordinate2DMake([hikeCoordinatePairs[i][1] doubleValue], [hikeCoordinatePairs[i][0] doubleValue]); + } + + MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:polylineCoordinates + count:[hikeCoordinatePairs count]]; + + [self.mapView addAnnotation:polyline]; + + free(polylineCoordinates); + + // PA/NJ/DE polys + // + NSDictionary *threestates = [NSJSONSerialization JSONObjectWithData: + [NSData dataWithContentsOfFile: + [[NSBundle mainBundle] pathForResource:@"threestates" ofType:@"geojson"]] + options:0 + error:nil]; + + for (NSDictionary *feature in threestates[@"features"]) + { + NSArray *stateCoordinatePairs = feature[@"geometry"][@"coordinates"]; + + while ([stateCoordinatePairs count] == 1) stateCoordinatePairs = stateCoordinatePairs[0]; + + CLLocationCoordinate2D *polygonCoordinates = (CLLocationCoordinate2D *)malloc([stateCoordinatePairs count] * sizeof(CLLocationCoordinate2D)); + + for (NSUInteger i = 0; i < [stateCoordinatePairs count]; i++) + { + polygonCoordinates[i] = CLLocationCoordinate2DMake([stateCoordinatePairs[i][1] doubleValue], [stateCoordinatePairs[i][0] doubleValue]); + } + + MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:polygonCoordinates count:[stateCoordinatePairs count]]; + + [self.mapView addAnnotation:polygon]; + + free(polygonCoordinates); + } + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 8) + { + [self.mapView removeAnnotations:self.mapView.annotations]; + } +} + +- (void)parseFeaturesAddingCount:(NSUInteger)featuresCount +{ + [self.mapView removeAnnotations:self.mapView.annotations]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ + { + NSData *featuresData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"points" ofType:@"geojson"]]; + + id features = [NSJSONSerialization JSONObjectWithData:featuresData + options:0 + error:nil]; + + if ([features isKindOfClass:[NSDictionary class]]) + { + NSMutableArray *annotations = [NSMutableArray array]; + + for (NSDictionary *feature in features[@"features"]) + { + CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake([feature[@"geometry"][@"coordinates"][1] doubleValue], + [feature[@"geometry"][@"coordinates"][0] doubleValue]); + NSString *title = feature[@"properties"][@"NAME"]; + + MGLPointAnnotation *annotation = [MGLPointAnnotation new]; + annotation.coordinate = coordinate; + annotation.title = title; + + [annotations addObject:annotation]; + + if (annotations.count == featuresCount) break; + } + + dispatch_async(dispatch_get_main_queue(), ^ + { + [self.mapView addAnnotations:annotations]; + + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(38.904722, -77.016389) + zoomLevel:10 + animated:NO]; + + [self.mapView setDirection:0]; + }); + } + }); +} + +- (void)cycleStyles +{ + UIButton *titleButton = (UIButton *)self.navigationItem.titleView; + + NSString *styleName = [titleButton titleForState:UIControlStateNormal]; + + if ( ! styleName) + { + styleName = [kStyleNames firstObject]; + } + else + { + NSUInteger index = [kStyleNames indexOfObject:styleName] + 1; + if (index == [kStyleNames count]) index = 0; + styleName = [kStyleNames objectAtIndex:index]; + } + + self.mapView.styleURL = [NSURL URLWithString: + [NSString stringWithFormat:@"asset://styles/%@-v%@.json", + [[styleName lowercaseString] stringByReplacingOccurrencesOfString:@" " withString:@"-"], + kStyleVersion]]; + + [titleButton setTitle:styleName forState:UIControlStateNormal]; +} + +- (void)locateUser +{ + MGLUserTrackingMode nextMode; + switch (self.mapView.userTrackingMode) { + case MGLUserTrackingModeNone: + nextMode = MGLUserTrackingModeFollow; + break; + case MGLUserTrackingModeFollow: + nextMode = MGLUserTrackingModeFollowWithHeading; + break; + case MGLUserTrackingModeFollowWithHeading: + nextMode = MGLUserTrackingModeFollowWithCourse; + break; + case MGLUserTrackingModeFollowWithCourse: + nextMode = MGLUserTrackingModeNone; + break; + } + self.mapView.userTrackingMode = nextMode; +} + +#pragma mark - Destruction + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + if (settings) + { + [self saveState:nil]; + delete settings; + settings = nullptr; + } +} + +#pragma mark - MGLMapViewDelegate + +- (MGLAnnotationImage *)mapView:(MGLMapView * __nonnull)mapView imageForAnnotation:(id __nonnull)annotation +{ + NSString *title = [(MGLPointAnnotation *)annotation title]; + NSString *lastTwoCharacters = [title substringFromIndex:title.length - 2]; + + MGLAnnotationImage *image = [mapView dequeueReusableAnnotationImageWithIdentifier:lastTwoCharacters]; + + if ( ! image) + { + CGRect rect = CGRectMake(0, 0, 20, 15); + + UIGraphicsBeginImageContextWithOptions(rect.size, NO, [[UIScreen mainScreen] scale]); + + CGContextRef ctx = UIGraphicsGetCurrentContext(); + + CGContextSetFillColorWithColor(ctx, [[[UIColor redColor] colorWithAlphaComponent:0.75] CGColor]); + CGContextFillRect(ctx, rect); + + CGContextSetStrokeColorWithColor(ctx, [[UIColor blackColor] CGColor]); + CGContextStrokeRectWithWidth(ctx, rect, 2); + + NSAttributedString *drawString = [[NSAttributedString alloc] initWithString:lastTwoCharacters attributes:@{ + NSFontAttributeName: [UIFont fontWithName:@"Arial-BoldMT" size:12], + NSForegroundColorAttributeName: [UIColor whiteColor] }]; + CGSize stringSize = drawString.size; + CGRect stringRect = CGRectMake((rect.size.width - stringSize.width) / 2, + (rect.size.height - stringSize.height) / 2, + stringSize.width, + stringSize.height); + [drawString drawInRect:stringRect]; + + image = [MGLAnnotationImage annotationImageWithImage:UIGraphicsGetImageFromCurrentImageContext() reuseIdentifier:lastTwoCharacters]; + + UIGraphicsEndImageContext(); + } + + return image; +} + +- (BOOL)mapView:(__unused MGLMapView *)mapView annotationCanShowCallout:(__unused id )annotation +{ + return YES; +} + +- (CGFloat)mapView:(__unused MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation +{ + return ([annotation isKindOfClass:[MGLPolygon class]] ? 0.5 : 1.0); +} + +- (UIColor *)mapView:(__unused MGLMapView *)mapView strokeColorForShapeAnnotation:(MGLShape *)annotation +{ + return ([annotation isKindOfClass:[MGLPolyline class]] ? [UIColor purpleColor] : [UIColor blackColor]); +} + +- (UIColor *)mapView:(__unused MGLMapView *)mapView fillColorForPolygonAnnotation:(__unused MGLPolygon *)annotation +{ + return (annotation.pointCount > 3 ? [UIColor greenColor] : [UIColor redColor]); +} + +- (void)mapView:(__unused MGLMapView *)mapView didChangeUserTrackingMode:(MGLUserTrackingMode)mode animated:(__unused BOOL)animated +{ + UIImage *newButtonImage; + NSString *newButtonTitle; + + switch (mode) { + case MGLUserTrackingModeNone: + newButtonImage = [UIImage imageNamed:@"TrackingLocationOffMask.png"]; + break; + + case MGLUserTrackingModeFollow: + newButtonImage = [UIImage imageNamed:@"TrackingLocationMask.png"]; + break; + + case MGLUserTrackingModeFollowWithHeading: + newButtonImage = [UIImage imageNamed:@"TrackingHeadingMask.png"]; + break; + case MGLUserTrackingModeFollowWithCourse: + newButtonImage = nil; + newButtonTitle = @"Course"; + break; + } + + self.navigationItem.rightBarButtonItem.title = newButtonTitle; + [UIView animateWithDuration:0.25 animations:^{ + self.navigationItem.rightBarButtonItem.image = newButtonImage; + }]; +} + +@end diff --git a/ios/app/Settings.bundle/Root.plist b/ios/app/Settings.bundle/Root.plist new file mode 100644 index 000000000..076f402e1 --- /dev/null +++ b/ios/app/Settings.bundle/Root.plist @@ -0,0 +1,33 @@ + + + + + PreferenceSpecifiers + + + Title + Privacy Settings + Type + PSGroupSpecifier + FooterText + This setting allows the application to share anonymized location and usage data with Mapbox. + + + DefaultValue + + Key + MGLMapboxMetricsEnabled + Title + Mapbox Metrics + Type + PSToggleSwitchSpecifier + TrueValue + + FalseValue + + + + StringsTable + Root + + diff --git a/ios/app/Settings.bundle/en.lproj/Root.strings b/ios/app/Settings.bundle/en.lproj/Root.strings new file mode 100644 index 000000000..c4fe784dd --- /dev/null +++ b/ios/app/Settings.bundle/en.lproj/Root.strings @@ -0,0 +1,3 @@ +"Privacy Settings" = "Privacy Settings"; +"Mapbox Metrics" = "Mapbox Metrics"; +"This setting allows the application to share anonymized location and usage data with Mapbox." = "This setting allows the application to share anonymized location and usage data with Mapbox."; diff --git a/ios/app/app-info.plist b/ios/app/app-info.plist new file mode 100644 index 000000000..978cc271e --- /dev/null +++ b/ios/app/app-info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.mapbox.MapboxGL + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.0.2 + CFBundleSignature + MBGL + CFBundleVersion + 0.0.3 + LSRequiresIPhoneOS + + MGLMetricsTestServerURL + https://cloudfront-staging.tilestream.net + NSAppTransportSecurity + + NSExceptionDomains + + cloudfront-staging.tilestream.net + + NSExceptionRequiresForwardSecrecy + + + + + NSHumanReadableCopyright + (c) 2014 Mapbox + NSLocationWhenInUseUsageDescription + The map will be centered on the user's location. + UILaunchStoryboardName + Default + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ios/app/img/Default-568h@2x.png b/ios/app/img/Default-568h@2x.png new file mode 100644 index 000000000..ea3706427 Binary files /dev/null and b/ios/app/img/Default-568h@2x.png differ diff --git a/ios/app/img/Default-667h@2x.png b/ios/app/img/Default-667h@2x.png new file mode 100644 index 000000000..03f139de6 Binary files /dev/null and b/ios/app/img/Default-667h@2x.png differ diff --git a/ios/app/img/Icon-40.png b/ios/app/img/Icon-40.png new file mode 100644 index 000000000..eca13393e Binary files /dev/null and b/ios/app/img/Icon-40.png differ diff --git a/ios/app/img/Icon-40@2x.png b/ios/app/img/Icon-40@2x.png new file mode 100644 index 000000000..070d03753 Binary files /dev/null and b/ios/app/img/Icon-40@2x.png differ diff --git a/ios/app/img/Icon-60.png b/ios/app/img/Icon-60.png new file mode 100644 index 000000000..ff4c6ab4b Binary files /dev/null and b/ios/app/img/Icon-60.png differ diff --git a/ios/app/img/Icon-60@2x.png b/ios/app/img/Icon-60@2x.png new file mode 100644 index 000000000..b7f25955f Binary files /dev/null and b/ios/app/img/Icon-60@2x.png differ diff --git a/ios/app/img/Icon-60@3x.png b/ios/app/img/Icon-60@3x.png new file mode 100644 index 000000000..b00d47983 Binary files /dev/null and b/ios/app/img/Icon-60@3x.png differ diff --git a/ios/app/img/Icon-72.png b/ios/app/img/Icon-72.png new file mode 100644 index 000000000..0c876f664 Binary files /dev/null and b/ios/app/img/Icon-72.png differ diff --git a/ios/app/img/Icon-72@2x.png b/ios/app/img/Icon-72@2x.png new file mode 100644 index 000000000..6da408204 Binary files /dev/null and b/ios/app/img/Icon-72@2x.png differ diff --git a/ios/app/img/Icon-76.png b/ios/app/img/Icon-76.png new file mode 100644 index 000000000..895b4a176 Binary files /dev/null and b/ios/app/img/Icon-76.png differ diff --git a/ios/app/img/Icon-76@2x.png b/ios/app/img/Icon-76@2x.png new file mode 100644 index 000000000..7bc520897 Binary files /dev/null and b/ios/app/img/Icon-76@2x.png differ diff --git a/ios/app/img/Icon-76@3x.png b/ios/app/img/Icon-76@3x.png new file mode 100644 index 000000000..64edff183 Binary files /dev/null and b/ios/app/img/Icon-76@3x.png differ diff --git a/ios/app/img/Icon-Small-50.png b/ios/app/img/Icon-Small-50.png new file mode 100644 index 000000000..6d17da4b0 Binary files /dev/null and b/ios/app/img/Icon-Small-50.png differ diff --git a/ios/app/img/Icon-Small-50@2x.png b/ios/app/img/Icon-Small-50@2x.png new file mode 100644 index 000000000..ac4ec1928 Binary files /dev/null and b/ios/app/img/Icon-Small-50@2x.png differ diff --git a/ios/app/img/Icon-Small.png b/ios/app/img/Icon-Small.png new file mode 100644 index 000000000..aecbbc8a1 Binary files /dev/null and b/ios/app/img/Icon-Small.png differ diff --git a/ios/app/img/Icon-Small@2x.png b/ios/app/img/Icon-Small@2x.png new file mode 100644 index 000000000..7773852e7 Binary files /dev/null and b/ios/app/img/Icon-Small@2x.png differ diff --git a/ios/app/img/Icon-Small@3x.png b/ios/app/img/Icon-Small@3x.png new file mode 100644 index 000000000..e16f3fa6a Binary files /dev/null and b/ios/app/img/Icon-Small@3x.png differ diff --git a/ios/app/img/Icon-Spotlight-40.png b/ios/app/img/Icon-Spotlight-40.png new file mode 100644 index 000000000..eca13393e Binary files /dev/null and b/ios/app/img/Icon-Spotlight-40.png differ diff --git a/ios/app/img/Icon-Spotlight-40@2x.png b/ios/app/img/Icon-Spotlight-40@2x.png new file mode 100644 index 000000000..070d03753 Binary files /dev/null and b/ios/app/img/Icon-Spotlight-40@2x.png differ diff --git a/ios/app/img/Icon-Spotlight-40@3x.png b/ios/app/img/Icon-Spotlight-40@3x.png new file mode 100644 index 000000000..a3789dcb7 Binary files /dev/null and b/ios/app/img/Icon-Spotlight-40@3x.png differ diff --git a/ios/app/img/Icon.png b/ios/app/img/Icon.png new file mode 100644 index 000000000..9ca8194ee Binary files /dev/null and b/ios/app/img/Icon.png differ diff --git a/ios/app/img/Icon@2x.png b/ios/app/img/Icon@2x.png new file mode 100644 index 000000000..7c2e8ba03 Binary files /dev/null and b/ios/app/img/Icon@2x.png differ diff --git a/ios/app/img/TrackingHeadingMask.png b/ios/app/img/TrackingHeadingMask.png new file mode 100644 index 000000000..9ec0567a3 Binary files /dev/null and b/ios/app/img/TrackingHeadingMask.png differ diff --git a/ios/app/img/TrackingHeadingMask@2x.png b/ios/app/img/TrackingHeadingMask@2x.png new file mode 100644 index 000000000..0df8ccc22 Binary files /dev/null and b/ios/app/img/TrackingHeadingMask@2x.png differ diff --git a/ios/app/img/TrackingHeadingMask@3x.png b/ios/app/img/TrackingHeadingMask@3x.png new file mode 100644 index 000000000..e4b93e42e Binary files /dev/null and b/ios/app/img/TrackingHeadingMask@3x.png differ diff --git a/ios/app/img/TrackingLocationMask.png b/ios/app/img/TrackingLocationMask.png new file mode 100644 index 000000000..bb7348c48 Binary files /dev/null and b/ios/app/img/TrackingLocationMask.png differ diff --git a/ios/app/img/TrackingLocationMask@2x.png b/ios/app/img/TrackingLocationMask@2x.png new file mode 100644 index 000000000..35c5a293e Binary files /dev/null and b/ios/app/img/TrackingLocationMask@2x.png differ diff --git a/ios/app/img/TrackingLocationMask@3x.png b/ios/app/img/TrackingLocationMask@3x.png new file mode 100644 index 000000000..af523975a Binary files /dev/null and b/ios/app/img/TrackingLocationMask@3x.png differ diff --git a/ios/app/img/TrackingLocationOffMask.png b/ios/app/img/TrackingLocationOffMask.png new file mode 100644 index 000000000..87b26c571 Binary files /dev/null and b/ios/app/img/TrackingLocationOffMask.png differ diff --git a/ios/app/img/TrackingLocationOffMask@2x.png b/ios/app/img/TrackingLocationOffMask@2x.png new file mode 100644 index 000000000..232d534b4 Binary files /dev/null and b/ios/app/img/TrackingLocationOffMask@2x.png differ diff --git a/ios/app/img/TrackingLocationOffMask@3x.png b/ios/app/img/TrackingLocationOffMask@3x.png new file mode 100644 index 000000000..b609fbe84 Binary files /dev/null and b/ios/app/img/TrackingLocationOffMask@3x.png differ diff --git a/ios/app/img/iTunesArtwork b/ios/app/img/iTunesArtwork new file mode 100644 index 000000000..ac6a0c58e Binary files /dev/null and b/ios/app/img/iTunesArtwork differ diff --git a/ios/app/img/iTunesArtwork.png b/ios/app/img/iTunesArtwork.png new file mode 100644 index 000000000..b10824b04 Binary files /dev/null and b/ios/app/img/iTunesArtwork.png differ diff --git a/ios/app/img/iTunesArtwork@2x b/ios/app/img/iTunesArtwork@2x new file mode 100644 index 000000000..fae1dad8b Binary files /dev/null and b/ios/app/img/iTunesArtwork@2x differ diff --git a/ios/app/img/iTunesArtwork@2x.png b/ios/app/img/iTunesArtwork@2x.png new file mode 100644 index 000000000..fdee900aa Binary files /dev/null and b/ios/app/img/iTunesArtwork@2x.png differ diff --git a/ios/app/img/settings.png b/ios/app/img/settings.png new file mode 100644 index 000000000..5d7643eef Binary files /dev/null and b/ios/app/img/settings.png differ diff --git a/ios/app/img/settings@2x.png b/ios/app/img/settings@2x.png new file mode 100644 index 000000000..2bb9f0eba Binary files /dev/null and b/ios/app/img/settings@2x.png differ diff --git a/ios/app/main.m b/ios/app/main.m new file mode 100644 index 000000000..954584f14 --- /dev/null +++ b/ios/app/main.m @@ -0,0 +1,10 @@ +#import + +#import "MBXAppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([MBXAppDelegate class])); + } +} diff --git a/ios/app/mapboxgl-app.gypi b/ios/app/mapboxgl-app.gypi new file mode 100644 index 000000000..34381ca15 --- /dev/null +++ b/ios/app/mapboxgl-app.gypi @@ -0,0 +1,64 @@ +{ + 'includes': [ + '../../gyp/common.gypi', + ], + 'targets': [ + { 'target_name': 'iosapp', + 'product_name': 'Mapbox GL', + 'type': 'executable', + 'product_extension': 'app', + 'mac_bundle': 1, + 'mac_bundle_resources': [ + 'Not In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04299" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91636206355402, + 38.89569665945388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04451" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0238724795834, + 38.908392080284656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

Not In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H04488" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97787257022829, + 38.8489449722363, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

Not In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H04834" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03147970117229, + 38.96902788924794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04859" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9913552472916, + 38.83709694933415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H05056" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00040502778565, + 38.85974851759818, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H05098" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99323795575543, + 38.859058565652674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

Not In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H05136" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.959878452791, + 38.88617396045632, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

Not In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05165" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98698481952468, + 38.860417884264336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H05227" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98993851902051, + 38.839618544962086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05262" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98987381620425, + 38.84045690178814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05263" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91231659856827, + 38.89190091586272, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05286" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99348740940816, + 38.83986590773414, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H05391" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98601664025121, + 38.91047765444307, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

Not In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H05422" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98957955060457, + 38.837540182413264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05485" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98470810619855, + 38.84570928130159, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05572" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98317121239893, + 38.845981386046816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

Not In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05573" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98780462640617, + 38.834545599644464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05654" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9885525170853, + 38.83350723429082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05655" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93173574657547, + 38.908409952681225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

Not In Service


Last Inspection Date: 11/02/07

Report Problem", + "NAME": "H05703" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00455649194319, + 38.845714815307616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05706" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99855738244389, + 38.83314573676457, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05711" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99759077343545, + 38.83484620257337, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H05714" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99878902851339, + 38.83402379395176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

Not In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H05715" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99584213768712, + 38.84433254766388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05876" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99837327570914, + 38.83016139292818, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H05932" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94244722039106, + 38.8984667850143, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

Not In Service


Last Inspection Date: 05/08/07

Report Problem", + "NAME": "H06014" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93128596530984, + 38.88813824915444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06062" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.993404398372, + 38.83796673223114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H06138" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97881935219762, + 38.84695302166241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

Not In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H06198" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98093780382641, + 38.84810364743267, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06204" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99151276057596, + 38.84277892390687, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 12/26/07

Report Problem", + "NAME": "H06281" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94245572382569, + 38.89910077971911, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

Not In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H06284" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97686929496238, + 38.847532020368746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06351" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9908307093506, + 38.83445746759559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

Not In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H06371" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93099707003753, + 38.88749531288, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

Not In Service


Last Inspection Date: 01/16/08

Report Problem", + "NAME": "H06421" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99497416142488, + 38.83408459821604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06449" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99613574191525, + 38.83427919813744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

Not In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06450" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03172585575031, + 38.91692065774532, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 02/25/08

Report Problem", + "NAME": "H06618" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00485047487068, + 38.89142723809215, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 01/22/08

Report Problem", + "NAME": "H06681" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99666296819146, + 38.843205383344355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

Not In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06847" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.992343207122, + 38.86050844281507, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 10/17/07

Report Problem", + "NAME": "H06936" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99854678638224, + 38.84050507675981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

Not In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H07080" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9733590055815, + 38.850989827283605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07263" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01012243607381, + 38.8674809483319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07374" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05434791651238, + 38.89321416302191, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H07410" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94283195424802, + 38.89090011532114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07469" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98402442882518, + 38.841073903098554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07489" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98553461650069, + 38.834608525707, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07553" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98635144562992, + 38.83527938483727, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07663" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94277587834381, + 38.899779302608884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07664" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9761772397151, + 38.85176761201083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07676" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98828114282179, + 38.858208327743675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H07726" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.931872005955, + 38.881380159518855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07735" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98583667653341, + 38.91526521286277, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

Not In Service


Last Inspection Date: 02/26/08

Report Problem", + "NAME": "H07797" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98678399344202, + 38.91493268211026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

Not In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07799" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99000306666689, + 38.85427337296903, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

Not In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07843" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0006533530727, + 38.86585272764679, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H07851" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97602904220025, + 38.85269103611326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07897" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98793210310468, + 38.87652507359999, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

Not In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H07904" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99111619748747, + 38.85435082736918, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

Not In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07914" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99004411081333, + 38.858518228004314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H07919" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92398128690964, + 38.904010206187216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H08001" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98837064326993, + 38.83974025659751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H08151" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01504314794114, + 38.89115951512574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

Not In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H08225" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02875131595142, + 38.898418860484426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00030" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95764882330856, + 38.883691300595814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H00031" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0529977220696, + 38.96280384942628, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H00032" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0279853511952, + 38.92300810700433, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00033" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94119295857982, + 38.87978174909364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H00034" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94388454003413, + 38.87775490556381, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00035" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95085670222016, + 38.88763142914867, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H00036" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01632906577423, + 38.815379894850096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00037" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0161692070949, + 38.81496240082986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00038" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01736558362855, + 38.81439578430056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00039" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97584637824413, + 38.850562575855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00041" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01470069113194, + 38.902140123803925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00043" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00912452852958, + 38.82135233969486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H00044" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95592616553711, + 38.884011091508654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00045" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97148377126307, + 38.84925439555673, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00046" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01036125901071, + 38.82445226880478, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H00047" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01051174457935, + 38.825275620679086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H00048" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01418080489695, + 38.828572971819355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H00049" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97146849955459, + 38.84719842287334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00050" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96991534493175, + 38.847508707008586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00051" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01164835924266, + 38.939619564354835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00052" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97074915707135, + 38.84688159815845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00053" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96827883483726, + 38.84705917601572, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00054" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01048335544911, + 38.93900746204618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00055" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01043348675512, + 38.9397611453294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00056" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09837205432707, + 38.94626249795688, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00057" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1002431089394, + 38.94608328309577, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00058" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10073059458767, + 38.946548997829375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00060" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01446624081542, + 38.90114438742313, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00061" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01457754925728, + 38.89472288892249, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00062" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01266954068682, + 38.939815956010804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00063" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95160820241006, + 38.86900066345887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H00064" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9540042960017, + 38.88668825445605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00066" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94806876057358, + 38.8675158903519, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H00067" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97907649493274, + 38.86876087754535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00068" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97979279295288, + 38.8380891347343, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08319" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98591509719353, + 38.85459888533094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

Not In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08368" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96468572679832, + 38.92540502852441, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

Not In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08422" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9934888941163, + 38.83204805424982, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H08435" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9923916315782, + 38.83220582513475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H08436" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03181078795048, + 38.89578957105822, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

Not In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H08515" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97706625283728, + 38.84138399430156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H08517" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0323454934693, + 38.896124103023254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

Not In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08605" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91100970788654, + 38.89390220984717, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H08619" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04064814698516, + 38.90268562195885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08887" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99703717417856, + 38.86376791978137, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

Not In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H08962" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98479626988147, + 38.8497942055782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

Not In Service


Last Inspection Date: 03/10/08

Report Problem", + "NAME": "H09118" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02615757568168, + 38.89395356410638, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

Not In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H09350" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00734329985171, + 38.83646993289141, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00003" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98670067697417, + 38.86519768209315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H00004" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0203117912091, + 38.92266262008507, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H00005" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98622199688307, + 38.863276861458345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00007" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06871050072776, + 38.944957189195556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 11/10/05

Report Problem", + "NAME": "H00008" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98475995153744, + 38.864828271134506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00010" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0004914276414, + 38.83780381048957, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00011" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08564775375521, + 38.90964557354399, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00012" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06476139670181, + 38.94241042259082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00013" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00056245478972, + 38.83420877857179, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00014" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98659922647472, + 38.85547111685086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/21/07

Report Problem", + "NAME": "H00015" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94285288710866, + 38.87042235053403, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00016" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01418500520768, + 38.96804162964368, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00017" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99726767139077, + 38.832052708118574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H00018" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04892152546748, + 38.917154075179845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H00023" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99842514975484, + 38.82798879487114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H00024" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92931049765984, + 38.886476330156206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00025" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92706829183449, + 38.8861878004065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00026" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00448639241161, + 38.82109143641948, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00027" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03080027784384, + 38.898386908064644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H00028" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03096217970821, + 38.89823578603241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00029" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9882085093919, + 38.85522304522973, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

Not In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00002" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99337048103996, + 38.832965045867496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/30/07

Report Problem", + "NAME": "H00020" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98960814925373, + 38.83596304770729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00021" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99628444071986, + 38.83016409270196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H00022" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97907972723497, + 38.84794629413317, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

Not In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00059" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98310255748365, + 38.8535688576217, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00099" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98702802537683, + 38.840136216678005, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H00108" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98590954839855, + 38.84401352998382, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 03/07/08

Report Problem", + "NAME": "H00162" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00243586107831, + 38.860670144391996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

Not In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00242" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9883830443067, + 38.85180131847511, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

Not In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00295" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00186057274746, + 38.841555320984845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00377" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93114705048231, + 38.88879526557277, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

Not In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00407" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98775245098426, + 38.85402117476584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

Not In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00439" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01224787233296, + 38.86738702124701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

Not In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H00557" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03435214518555, + 38.90958196669992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

Not In Service


Last Inspection Date: 03/01/08

Report Problem", + "NAME": "H00916" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00745622900936, + 38.90778876724929, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

Not In Service


Last Inspection Date: 02/27/08

Report Problem", + "NAME": "H00926" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99605934440424, + 38.84661700609712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01000" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01432579829839, + 38.90474183677433, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01040" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03288981034959, + 38.9025928093699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

Not In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H01174" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99167910301576, + 38.896665588622305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

Not In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01520" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0004169171207, + 38.841816201702336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 10/05/07

Report Problem", + "NAME": "H01590" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97841081726658, + 38.86170400692483, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01954" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9974960635124, + 38.86079489154801, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

Not In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H02363" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99259102867128, + 38.92844863358593, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H02514" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99858811144134, + 38.846513115673616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02907" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91372890917275, + 38.89570302319379, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H02976" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02349137955831, + 38.931629593522736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

Not In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03110" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91488830659483, + 38.892943258230794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03216" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03207439428094, + 38.894753239540144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03569" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03210933995463, + 38.89420376454046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

Not In Service


Last Inspection Date: 12/14/07

Report Problem", + "NAME": "H03571" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08984295641454, + 38.92389463648992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 02/19/08

Report Problem", + "NAME": "H03846" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99973408710572, + 38.8592151743981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

Not In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03972" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02611904840202, + 38.89309439050424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

Not In Service


Last Inspection Date: 02/08/08

Report Problem", + "NAME": "H04031" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01362136786202, + 38.91814722262231, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00541" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01349750327192, + 38.917126106792715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H00542" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01069416546065, + 38.917051321550225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/18/07

Report Problem", + "NAME": "H00543" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98456614591932, + 38.891509061074494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/01/06

Report Problem", + "NAME": "H00544" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00596500742333, + 38.90362535603583, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00545" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97431451221271, + 38.93217484609292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/30/07

Report Problem", + "NAME": "H00546" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05530269530544, + 38.926836501875435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 02/04/08

Report Problem", + "NAME": "H00547" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01222712033929, + 38.91326101385692, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00548" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01066007478472, + 38.91254226596518, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00550" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01410302035261, + 38.9148683670127, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00551" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97905819445877, + 38.889579267396854, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H00552" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01060315063076, + 38.918052524624756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00553" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02081744766905, + 38.89282415955387, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00554" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0580317373795, + 38.904185188942485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00555" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05876849720363, + 38.90413805829549, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H00556" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00064318580094, + 38.90117898157355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H00558" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03864316498213, + 38.91042496027107, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H00559" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00357821847021, + 38.897471673295854, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00560" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00358232493264, + 38.89821155696173, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00561" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01705764608303, + 38.86377615224299, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00562" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0716960615629, + 38.96484371625319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00563" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02283656023243, + 38.914151121175266, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H00564" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01765757602736, + 38.88802508136319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H00565" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04728176774067, + 38.91762893071494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H00566" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03699845762682, + 38.935420954181026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H00567" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01062421523633, + 38.92027888571206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00568" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98753047577941, + 38.91386381710404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00256" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00380763913427, + 38.87318300584154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00257" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98032630731235, + 38.91728943401489, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00258" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97884164849171, + 38.917360439522476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00259" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01143896297877, + 38.93683360770177, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00262" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98487039704727, + 38.917215395627416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00263" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98530576893822, + 38.917790389827125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00264" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98572468372815, + 38.916337262896796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00265" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9862242551418, + 38.91664589425007, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H00266" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9868049342536, + 38.91642178893458, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H00267" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98694665721162, + 38.916751473748825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H00268" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98649088696031, + 38.916933399241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H00269" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9864570392697, + 38.91744240202542, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H00270" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94719326544984, + 38.87220963464331, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00272" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99634567566413, + 38.94269296839883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00273" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99727526617477, + 38.94268893102567, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00274" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95962196848646, + 38.873663784124524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00275" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01576688218383, + 38.87062427474521, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H00276" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01600386090753, + 38.870003293131596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H00277" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03672557398609, + 38.89188592903099, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00278" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94371693141385, + 38.867505883405656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00279" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01587309197622, + 38.863621897025915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00280" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01601303214005, + 38.866915912225586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00281" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95679786057359, + 38.871216829973505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00283" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92283554447167, + 38.883606961818316, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H00284" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97953430553923, + 38.84876394454315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00285" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99220698796537, + 38.90754303362449, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00286" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99431295277785, + 38.90823575276111, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00287" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0218231958979, + 38.89826036264599, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00288" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9957448593338, + 38.90712098582479, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00289" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92957016309505, + 38.885231086982714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00290" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01475614091855, + 38.92943572517179, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00291" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99861660534545, + 38.90624099360779, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00293" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97991711111005, + 38.85057043674555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/30/07

Report Problem", + "NAME": "H00294" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07589836785253, + 38.93573911403619, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00296" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08869950161862, + 38.93814995551608, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00297" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98716679418177, + 38.85734559990636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H00298" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99272928621342, + 38.95636171296229, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00299" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02818482633154, + 38.88369634398283, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00300" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96897278522113, + 38.8531391199942, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00301" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96750467981876, + 38.85346269981682, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00303" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00813961377256, + 38.85060081548807, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H00304" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10755770729163, + 38.937131878087186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00305" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10704444237716, + 38.936322340626795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H00306" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00918229614138, + 38.941318270327784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00307" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0091695963797, + 38.89674687962059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/01/08

Report Problem", + "NAME": "H00308" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10705187431056, + 38.93604077025528, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H00309" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9992170519996, + 38.845839551419765, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/25/08

Report Problem", + "NAME": "H00310" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00297270660255, + 38.910666916886385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00311" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0021802943481, + 38.91118632825825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00312" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01025315333591, + 38.935422180428716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00313" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05537847533314, + 38.974384806254754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00314" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97548607624007, + 38.86427141378945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00316" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0102462601637, + 38.934487686969774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00317" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99933858727306, + 38.92361853570536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00319" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00476454428953, + 38.910784911867616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H00321" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01347708245554, + 38.872523830158, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H00322" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06869665102082, + 38.92534159147757, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H00323" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04250828420079, + 38.909232246583436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00324" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01889359503039, + 38.86400139527415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H00325" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02369294362221, + 38.88295690634461, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H00326" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09036995997808, + 38.93650697620551, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00328" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95618281048186, + 38.920639360080045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/29/07

Report Problem", + "NAME": "H00329" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95666317316294, + 38.92979609799884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H00330" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01537305124363, + 38.8973986676926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00331" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03533097937942, + 38.87670357453863, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00332" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03786925162169, + 38.897017243828905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H00333" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03733396338757, + 38.903825654245956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00334" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03296804929205, + 38.87723707604876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00335" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03446942063209, + 38.87831786608508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00338" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03782073426443, + 38.8781924770099, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00339" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0155628569985, + 38.92646573306782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H00340" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00892532376703, + 38.90917472421178, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H00341" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00920006603344, + 38.941902519530075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00342" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.029820202144, + 38.89616771783067, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00343" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9806906561109, + 38.86216415983844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00344" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96786732214434, + 38.85145323507563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H00345" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96911550152376, + 38.85260936294394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00346" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04562391113357, + 38.943920923827434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H00069" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02884428137328, + 38.899911612945864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00070" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08919221658242, + 38.92148126406963, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/11/07

Report Problem", + "NAME": "H00071" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10044024780534, + 38.949247985252605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00072" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01434253792667, + 38.93896985697751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00073" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01072271592771, + 38.91912094646436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/03/07

Report Problem", + "NAME": "H00074" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05140781738709, + 38.89400154628643, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00075" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99480532988413, + 38.90716527790467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00076" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96168329394388, + 38.867990570706105, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00077" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08196384915904, + 38.95393408182062, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00078" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01399817662542, + 38.900671766939126, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00079" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99350470928859, + 38.90571236448279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00080" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03627823127259, + 38.93326317810749, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H00081" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96990073641807, + 38.853823634337516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00082" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96922712112944, + 38.85373850021674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00083" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96801989576917, + 38.85369475513178, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00084" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96792129365996, + 38.852814919623896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00085" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01122783997911, + 38.83318230245883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H00086" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01116943985605, + 38.82960423673855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H00087" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01267011779255, + 38.82629812897775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00088" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00137512739475, + 38.88765957778442, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 01/31/08

Report Problem", + "NAME": "H00089" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01275345631849, + 38.81711423940579, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00090" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03217511870507, + 38.89835366598179, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00094" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95786118894493, + 38.85655241831205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/27/07

Report Problem", + "NAME": "H00100" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01409014267682, + 38.892233206687834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00101" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00410454472694, + 38.85944279942364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/24/08

Report Problem", + "NAME": "H00102" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96852551838799, + 38.85144440594919, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00103" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03181484685275, + 38.90512353532609, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00104" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03086053488764, + 38.91922655336539, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H00106" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97588963989415, + 38.851132755659265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00107" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0767485924733, + 38.937601295254325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00109" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9770972901543, + 38.849803858246176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00110" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01448334419943, + 38.892263462756794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00111" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07438465119466, + 38.93626089311794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00112" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96856560928313, + 38.85196747343772, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00113" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07814558270415, + 38.93855273593855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00114" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01024814055796, + 38.936255772818505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00115" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04671075337184, + 38.90471109966362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/03/07

Report Problem", + "NAME": "H00116" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98018379838011, + 38.84270567203858, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H00117" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94751942978968, + 38.88420063031798, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00118" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99357708817912, + 38.84477729096918, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00119" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96186241344085, + 38.87386676687686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H00120" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94004624971504, + 38.888246679549276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00121" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95425937955709, + 38.87464137127418, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00122" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95537249147377, + 38.87455030363314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00123" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00298434436891, + 38.82506546490317, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00124" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97938931186481, + 38.86238359863203, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00125" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98201825306879, + 38.85228714716915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00126" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93777143950871, + 38.87524685211913, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00127" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98837569652838, + 38.880297887520015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00128" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97771001006961, + 38.86754646236409, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00129" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96692471794726, + 38.84980654513702, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00130" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98090277857703, + 38.865174987341696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00131" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97084763145918, + 38.87268148076737, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00132" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98375701162509, + 38.86891795431268, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H00133" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98037972997913, + 38.84557619192893, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00134" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93800802719893, + 38.883210911238, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H00135" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98524563899609, + 38.860024901296775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00136" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9506005301701, + 38.87180333326891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00137" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9532239833161, + 38.88368123450846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H00138" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96197631902415, + 38.869233484548666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H00139" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07716348694093, + 38.934740517019485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00142" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07839208956898, + 38.93675254156028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00143" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07824937420085, + 38.93973405954898, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00144" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01418898467888, + 38.892283668625964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00145" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.011409409811, + 38.934438330832734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00146" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07791650819983, + 38.925749713392534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00147" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98876879161352, + 38.876270399626904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/18/06

Report Problem", + "NAME": "H00149" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05244606758697, + 38.96160427976706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H00150" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98002742095711, + 38.88283768216455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H00151" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00011864938733, + 38.876478916455284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00152" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01229212334901, + 38.83161182222366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H00153" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10036145753229, + 38.94706963388548, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00154" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97871037060538, + 38.8647029186449, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00155" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98684375657275, + 38.90124365223176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H00156" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03907844803614, + 38.989393503894014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H00157" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05459386424639, + 38.97493890217225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/21/07

Report Problem", + "NAME": "H00158" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97431139178099, + 38.88747110735175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/06/06

Report Problem", + "NAME": "H00159" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92888796611612, + 38.8830643548754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00160" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95230945556914, + 38.86365794542221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H00161" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01145551537157, + 38.93482911542911, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00163" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97587730476666, + 38.88494169875132, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H00164" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97601809412953, + 38.88575813039, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H00165" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97508266360155, + 38.8858589996089, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H00166" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00499639843575, + 38.90895532585457, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H00167" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95350539572817, + 38.863316423222805, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/26/07

Report Problem", + "NAME": "H00168" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04782306063719, + 38.89741051957247, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00169" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01518868806883, + 38.863994702229185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H00170" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01087636205634, + 38.94190102433504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00172" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9297421383169, + 38.88445997368586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/18/08

Report Problem", + "NAME": "H00173" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00399840817738, + 38.91066981399904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H00174" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9879116750212, + 38.91663473050051, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H00176" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98578460926737, + 38.92229680993157, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/25/07

Report Problem", + "NAME": "H00177" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01079902681498, + 38.94072699013935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00178" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03328945585672, + 38.91562460835372, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H00180" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96105167707513, + 38.89247180719127, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00181" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97401398306715, + 38.88256312153113, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00182" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97355180925192, + 38.88239338085669, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H00183" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97388070108195, + 38.88181441375457, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H00184" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93790051446518, + 38.89028596502925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 11/26/07

Report Problem", + "NAME": "H00185" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97532470681075, + 38.88226215634162, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00186" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93498955252282, + 38.896603375266864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/15/07

Report Problem", + "NAME": "H00187" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9406267442465, + 38.89182535536861, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00188" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94150203726983, + 38.891825571780615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00189" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94256043501382, + 38.89138156080858, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H00190" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93768796897564, + 38.891124315390975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00191" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92984053568262, + 38.90131258081229, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00192" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96014255603326, + 38.88999564820024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, USP

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00193" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93762449042534, + 38.90069668953318, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H00194" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92740120700508, + 38.89922650165815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00195" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93616273371121, + 38.90442165709111, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00196" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92808163404881, + 38.89469275059905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, USP

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00197" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92998761313903, + 38.889932793951, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H00198" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06869847175086, + 38.92534016709285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00199" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02980271376337, + 38.89842786659362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H00200" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02933363140882, + 38.89843036352863, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00201" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97055289101735, + 38.86390449620404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H00202" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98373254958011, + 38.85612086378365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00203" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03690126059846, + 38.897222574965035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H00204" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03611144749854, + 38.89717469009673, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H00205" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03589500139472, + 38.897676108255936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H00206" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02606614777152, + 38.90630553957762, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00207" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98507420812717, + 38.85412452308332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00209" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0173067810556, + 38.94217394797017, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00211" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03839435134978, + 38.917538114824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00212" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05821410178804, + 38.95227231287798, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00214" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93528487102279, + 38.89934459522741, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00216" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00597057035456, + 38.96636700239988, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00217" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06890241705057, + 38.94419414644325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 11/10/05

Report Problem", + "NAME": "H00218" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0055542916195, + 38.8495445208484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00219" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0129859458632, + 38.92879006643523, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00221" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0373985480442, + 38.91622795073391, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00222" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06776439944746, + 38.94213282339662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H00223" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07600587709034, + 38.93826107090418, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H00225" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07464539247651, + 38.93693514232407, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/02/07

Report Problem", + "NAME": "H00226" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02823805697693, + 38.89824261997391, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00227" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05934433393793, + 38.912457984493045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00228" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0758885368004, + 38.95772215084292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00229" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01143304842086, + 38.94080497767452, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00230" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00793189101918, + 38.829123548710456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00231" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08084565509309, + 38.938359914690835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00232" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94083540044919, + 38.89508179812879, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00233" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94102513008227, + 38.893729026171556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00234" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94123945077173, + 38.89248856432943, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00235" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94309501188107, + 38.893190064075576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H00236" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95303850482532, + 38.8915753650969, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/28/06

Report Problem", + "NAME": "H00237" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00882879162891, + 38.91061905710018, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00238" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00181283627983, + 38.83464268527077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00239" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96964749770346, + 38.86249699656329, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H00240" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09295776572175, + 38.9161181284181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00241" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01446994649278, + 38.900657881629506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00244" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01063328287496, + 38.90243995748425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00246" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00079662454145, + 38.83268450077431, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00247" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9464390539857, + 38.89090581570778, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00248" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94478835184364, + 38.903767559143944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00249" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02012199961224, + 38.89621957115775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00250" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00720972052048, + 38.83390272006717, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/22/07

Report Problem", + "NAME": "H00251" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00010156022566, + 38.84515275035851, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00252" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99944051392958, + 38.92569877302764, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00253" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01208031394737, + 38.90787046469469, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H00255" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00866705467641, + 38.883805019399325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00527" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08187605088469, + 38.95338970142369, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00528" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05275825743661, + 38.917043008718245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H00529" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0351353106222, + 38.91816395795987, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00530" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03887333368164, + 38.922267472073464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H00531" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00959026346318, + 38.9213528484761, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00532" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06903003675079, + 38.9107348449838, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H00533" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06291833562312, + 38.90264884291127, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00534" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0238248431285, + 38.918309314133154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/02/07

Report Problem", + "NAME": "H00535" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00928441127117, + 38.89727314814548, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00536" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04172793539733, + 38.925516563401246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00537" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01211642021528, + 38.86474831802853, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H00538" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01210907436096, + 38.87449229747678, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00539" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98525877404899, + 38.866717984758424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H00540" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95217414060144, + 38.85961233496263, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/27/07

Report Problem", + "NAME": "H00429" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92687672045909, + 38.8885028797306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/16/08

Report Problem", + "NAME": "H00430" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95130901968231, + 38.8602779340048, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00433" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99170733798083, + 38.83177770542, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H00434" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92716397720932, + 38.88491508350542, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00435" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92955533814974, + 38.88730015048535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00436" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99006439803618, + 38.830060708127355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00437" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9672844518499, + 38.854389912092174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H00438" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98626578239839, + 38.86482887235028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00440" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97210596775659, + 38.871568556724625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00441" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98714488667319, + 38.85104297586446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/04/07

Report Problem", + "NAME": "H00442" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09222814167765, + 38.9140042243332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00443" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04014351051762, + 38.920703287681384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/18/07

Report Problem", + "NAME": "H00444" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04691221619966, + 38.92842015730996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/09/06

Report Problem", + "NAME": "H00445" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98862110852838, + 38.865636657788876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00446" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00991295946864, + 38.88456260644426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00447" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98097328380578, + 38.92901800516747, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00448" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03949788537298, + 38.89820151146847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00449" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08309822228358, + 38.95583880029729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00451" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00016916398467, + 38.93615738291501, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00452" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99731516469797, + 38.90443831907664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H00453" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0473504826842, + 38.91886420614517, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/31/06

Report Problem", + "NAME": "H00454" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03295566411798, + 38.89653415540334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00455" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03389096640534, + 38.89747251427745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00456" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03387295099684, + 38.89793909864431, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H00457" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.031864567533, + 38.89757868061877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00458" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02386963411597, + 38.89785670310835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00459" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02607378039431, + 38.89719134270353, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H00460" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0260855407902, + 38.896692682102554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00461" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02176073511433, + 38.896211268952726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00462" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02086210386048, + 38.89621576591644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00463" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07727501880086, + 38.96584663625259, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00464" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02545588300819, + 38.89409276329198, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00465" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01201875853117, + 38.942084168068654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00466" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01121533486227, + 38.941207345033476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00467" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99015250140971, + 38.90288808388267, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H00468" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00578517133305, + 38.90264670657341, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H00469" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01124529457459, + 38.94305895974434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00470" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04058153724093, + 38.89742157434607, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H00471" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0407174157212, + 38.89825063876422, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/22/07

Report Problem", + "NAME": "H00472" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06092418606342, + 38.934669197263865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H00474" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06857756478493, + 38.93261656788015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/25/08

Report Problem", + "NAME": "H00475" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02817853997549, + 38.895736840863236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00476" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0258225598813, + 38.89621380182162, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00477" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03659642809735, + 38.922561392155025, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H00478" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07670766441386, + 38.96716455620272, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00479" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0241586426541, + 38.89743017880579, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H00480" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03919622241256, + 38.92887361359118, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - JUMBO

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H00481" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03901413927103, + 38.92461154334142, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H00482" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02207583073152, + 38.89621359704856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00483" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06081355906596, + 38.933539424399484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H00484" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05861137787707, + 38.93352747841943, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/01/06

Report Problem", + "NAME": "H00485" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02530127041605, + 38.944088112135255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H00486" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99609624521014, + 38.88489097510951, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H00487" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03357254807193, + 38.9254748068058, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H00489" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04146675127683, + 38.93061303739658, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H00490" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03479306358672, + 38.93382801788214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H00491" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02280657678641, + 38.89387341630787, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00492" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97224782585256, + 38.92463332653775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H00493" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00849093256782, + 38.88913373237844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H00494" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00849101342658, + 38.889135191729466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H00495" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03531538315417, + 38.94830092313481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H00496" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98723919459903, + 38.90715805736616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 02/08/08

Report Problem", + "NAME": "H00497" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0284065576634, + 38.93578323967515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H00498" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03322413239843, + 38.88710630441911, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00499" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99958513570448, + 38.9167148535573, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H00500" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01058191558528, + 38.873091729747365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - JUMBO

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00501" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99017389550977, + 38.879476928858466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/08/07

Report Problem", + "NAME": "H00502" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06493506387731, + 38.934591539194955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H00503" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01061684626094, + 38.914776931836116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00504" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02335471479023, + 38.940975658402245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00505" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02317612065625, + 38.93973212634408, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00506" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98093954908359, + 38.88971702131883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H00507" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01751320993249, + 38.94000700008668, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H00508" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05489077157895, + 38.91551923072498, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00509" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98690928232688, + 38.879830899565206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/05/07

Report Problem", + "NAME": "H00510" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98803484510809, + 38.86125526613529, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H00511" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01930052394003, + 38.931424493893914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/08/07

Report Problem", + "NAME": "H00512" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01071714309293, + 38.8852602076266, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/10/08

Report Problem", + "NAME": "H00513" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98237317635046, + 38.881212298090894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/17/06

Report Problem", + "NAME": "H00514" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98094933322828, + 38.881349650627, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/17/06

Report Problem", + "NAME": "H00515" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99143154390538, + 38.886706959824046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H00516" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98372533177708, + 38.89550844659728, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - JUMBO

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H00517" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98624058132604, + 38.89483897087784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H00518" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07101762896404, + 38.93621500016529, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/20/07

Report Problem", + "NAME": "H00519" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07829633267208, + 38.96583511092745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00520" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0578063566818, + 38.92876439380731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/09/07

Report Problem", + "NAME": "H00521" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0207455996933, + 38.89314136605035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00522" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02003091776506, + 38.89346029698376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, UNKNOWN

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00523" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0268386306364, + 38.89972459094567, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H00524" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02825325281327, + 38.89990688385605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00525" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03253507965007, + 38.93766094301866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/31/07

Report Problem", + "NAME": "H00526" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98359301309151, + 38.88295557169683, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H00570" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03689006232764, + 38.906954908845705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00571" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01112939055602, + 38.91181116849666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00572" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07277946390602, + 38.96666344297844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00573" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07490356453572, + 38.964033467224915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00574" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07437660945044, + 38.96743807511667, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00575" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99514272375718, + 38.88754138504495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 10/23/06

Report Problem", + "NAME": "H00576" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98371942418198, + 38.879166859296646, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/19/08

Report Problem", + "NAME": "H00577" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02582003684756, + 38.95418408733482, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H00578" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98534863294992, + 38.88987979030678, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/21/06

Report Problem", + "NAME": "H00579" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99368737806073, + 38.880292782272456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/25/08

Report Problem", + "NAME": "H00581" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02193222762705, + 38.9208724995467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H00582" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0084327047177, + 38.913252620228725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00584" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00810064099802, + 38.91435520999397, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00585" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03516499770826, + 38.92187097438736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00586" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00722343538322, + 38.91687207863701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00587" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07248948360254, + 38.93733245905578, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H00588" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02332961738753, + 38.938762172867094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00589" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04062544590344, + 38.89908033187001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H00590" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03263089798043, + 38.939633318451996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/29/07

Report Problem", + "NAME": "H00591" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97412329737345, + 38.931228832661596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H00592" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03254573050256, + 38.932440854950336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/07/07

Report Problem", + "NAME": "H00593" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06374874040749, + 38.9084903267896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00594" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05907340453584, + 38.908541267108774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00595" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00471936337394, + 38.91190453325423, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00596" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02300846873308, + 38.900999982666754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00597" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03959710316732, + 38.8944165321469, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H00598" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03960246125648, + 38.89339524251815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H00599" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01829160326582, + 38.900982277219185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H00600" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99074778614116, + 38.90420289262141, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H00601" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0702573109951, + 38.90438443464286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/11/07

Report Problem", + "NAME": "H00602" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07531740639138, + 38.93333074137175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/14/08

Report Problem", + "NAME": "H00603" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04175557754553, + 38.89845483419036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00604" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01549171011582, + 38.9206655106053, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H00605" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0489028204688, + 38.89813239916177, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00606" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01546681279963, + 38.94006880640176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00607" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01629597759893, + 38.94004647929922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00608" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07689390504922, + 38.92622565158503, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00609" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07477146559653, + 38.926238289187225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00610" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07454940357962, + 38.92739184697904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00611" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03255194075274, + 38.92060408911481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H00612" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02460004799546, + 38.93876801101417, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H00613" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9914631784084, + 38.89368032658183, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/16/06

Report Problem", + "NAME": "H00614" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01625880008766, + 38.8996281351377, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H00615" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02203469935738, + 38.88553661951162, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00616" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99965038348607, + 38.9013821122493, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H00617" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97641196847428, + 38.93020882882853, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00618" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97913171479412, + 38.88861893360989, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H00619" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99581682191103, + 38.857838585699376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00620" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99537035242629, + 38.85879395718681, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00621" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97893632675547, + 38.88418446924292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H00622" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9917479239196, + 38.86407133943828, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H00623" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98804834503095, + 38.92671355351125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H00624" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0742129963924, + 38.963027784738486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00625" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99270276919138, + 38.884955393486855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H00626" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9901511706112, + 38.88672565035966, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/09/06

Report Problem", + "NAME": "H00628" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98217278014079, + 38.867129824301315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00629" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99257693968177, + 38.877116249773486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 11/06/06

Report Problem", + "NAME": "H00630" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99369801143564, + 38.88203683386349, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/13/08

Report Problem", + "NAME": "H00631" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99966281188446, + 38.886586858611366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/28/07

Report Problem", + "NAME": "H00632" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99956742604682, + 38.88600130456793, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/10/06

Report Problem", + "NAME": "H00633" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99479350035581, + 38.87921400998166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H00634" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99736034874054, + 38.88132362686992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/05/07

Report Problem", + "NAME": "H00635" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01072881291074, + 38.92231983796973, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 10/25/07

Report Problem", + "NAME": "H00636" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00188848819498, + 38.877471257018776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00637" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0075131256187, + 38.885119557566796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00638" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00594694070963, + 38.87913586286285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00639" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00744812762868, + 38.90473386568645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00640" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04704042398917, + 38.91373197778027, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00641" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0269677359348, + 38.94723847639023, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 02/15/08

Report Problem", + "NAME": "H00642" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99032265856465, + 38.88423614437471, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/27/06

Report Problem", + "NAME": "H00643" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03175208334801, + 38.93322537228224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H00644" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98358992951349, + 38.885237998472206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/24/07

Report Problem", + "NAME": "H00645" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03259401271161, + 38.933911284974236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00646" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02975734138879, + 38.90511948323334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00647" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00210297107746, + 38.88879206410491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H00648" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02695601930422, + 38.94724846026628, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H00649" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98235601331686, + 38.88415702883303, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H00650" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99287735931316, + 38.906567148130286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00347" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99220802648185, + 38.90700737938312, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00348" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00932069359708, + 38.927217222583195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00349" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99243417218278, + 38.90670031770109, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00350" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01130272309352, + 38.92825757988901, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00351" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01845705247615, + 38.8765884684711, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00352" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99151815785021, + 38.90632797580559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00353" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04767391193084, + 38.92883585294763, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/11/06

Report Problem", + "NAME": "H00354" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99130658219315, + 38.906636550222906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00355" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99110082719848, + 38.90694361128114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00356" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98973248345513, + 38.908454991405186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00357" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9896338844959, + 38.909235690844014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00358" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0130787064562, + 38.92810877550604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00359" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99270329545742, + 38.90956295273197, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00360" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99317734354747, + 38.90880953252853, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00361" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99201826830638, + 38.90728973320711, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00362" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01305669927427, + 38.92752707518816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00363" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01166529362663, + 38.92884343582412, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/25/07

Report Problem", + "NAME": "H00364" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99719344538849, + 38.92077274793784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00365" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09652327436493, + 38.91717414947395, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00366" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96727508938005, + 38.85272271013205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H00367" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.965226811923, + 38.92542641437083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00368" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01450243368396, + 38.92821858998992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00369" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0835746938527, + 38.956779626398635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00370" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01398314030503, + 38.92888344863874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00371" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0208161333214, + 38.88128750672352, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00372" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01080895255856, + 38.90728983015717, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00373" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96536542177824, + 38.918748045339555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/01/07

Report Problem", + "NAME": "H00374" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0103814941828, + 38.93021411718099, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00378" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99615314705265, + 38.95630614162345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00379" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96244490115862, + 38.87277754265664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00380" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01676474746395, + 38.92876837089944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00381" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01130702201235, + 38.94191306358582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00382" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05607500744702, + 38.973957646256444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00383" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01243921658218, + 38.876346839562224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00384" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01220696659455, + 38.94183242095408, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00385" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01228434161513, + 38.94189081358332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00386" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01921141820215, + 38.97739866543538, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/12/07

Report Problem", + "NAME": "H00387" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01111740753674, + 38.894925110940825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00388" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01048697759512, + 38.9418325879154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00390" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98212112473459, + 38.89669873957552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H00391" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96934599296084, + 38.851965518930356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H00392" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03447981496605, + 38.8759785719446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00393" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01114720644023, + 38.942438694526075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00394" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08953570644644, + 38.93584287756872, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00396" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01084556711778, + 38.94283343902372, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00397" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10159511332704, + 38.9468704670706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/24/08

Report Problem", + "NAME": "H00398" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03147854420091, + 38.877481353284985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00399" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06629844889184, + 38.942441981768084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 04/26/07

Report Problem", + "NAME": "H00400" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06781608380881, + 38.94377777007308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/26/07

Report Problem", + "NAME": "H00401" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.016392499733, + 38.92961197089285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00402" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92790652307717, + 38.883604445635456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00403" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02053614988436, + 38.915516914349716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00404" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97002822541879, + 38.9300446670204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H00405" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01137549088142, + 38.929678741932676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00406" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01002664703468, + 38.94204296283392, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00410" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03625981526396, + 38.977766274729134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H00411" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00924672621241, + 38.942801353788425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00413" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95871870489547, + 38.92377463928698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00414" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00994039988291, + 38.942704637938846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00415" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10776974802998, + 38.933626704075415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H00417" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00939868261503, + 38.92988479352073, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H00418" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1141503737422, + 38.935383194175174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H00419" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93136381320559, + 38.88685685273269, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00420" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11283075780725, + 38.93548727828825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H00421" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98273611208353, + 38.8546444285413, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/04/07

Report Problem", + "NAME": "H00422" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02287368070186, + 38.90783555532735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00424" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10133848008398, + 38.94624790197279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00425" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94180239725716, + 38.868618078148785, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00427" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01307372771403, + 38.942405911958566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00428" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97111302680491, + 38.870795934741, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00816" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02761138063899, + 38.951921980805395, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H00817" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02988723304331, + 38.950863480632385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H00818" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03486283339551, + 38.954119385323146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H00819" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03333417147122, + 38.95067959959026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H00820" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02833000238368, + 38.94514844910206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H00821" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99736081420201, + 38.89896419458266, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00822" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03080718503574, + 38.93642993191747, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - JUMBO

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H00823" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04137017307245, + 38.92981850270133, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H00824" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03794247041503, + 38.92546511903166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H00825" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06651433472665, + 38.96979780068285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00826" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07451311114325, + 38.969463086641134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00827" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07570320304505, + 38.968546382062804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00828" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03081572054886, + 38.935496588797925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - JUMBO

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H00829" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0281024642312, + 38.94608351869913, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H00830" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0268001813721, + 38.94620425622486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H00831" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02988084988567, + 38.94617651155082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H00832" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99162629589053, + 38.888996390132725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00833" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05127620162818, + 38.89952148885242, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00834" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01483064544254, + 38.918686422040935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H00835" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99204494183824, + 38.90475405601698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H00836" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0760366156829, + 38.94852421256546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00837" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07747882052871, + 38.951499060052555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, Metropolitan

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H00838" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07806369706799, + 38.94746234961837, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H00839" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01527261442573, + 38.91405865894837, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00840" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99627591930884, + 38.89550662022172, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00841" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99829557757407, + 38.8955072526926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H00842" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02269116104476, + 38.92422673833953, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00843" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00331141114258, + 38.90846845772506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00844" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07204917019278, + 38.961056122840226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H00845" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0250784294348, + 38.93096700005812, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00846" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08024236257697, + 38.956020266925755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H00847" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08196504045424, + 38.9560536366489, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00848" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08196270809631, + 38.95692493584346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00849" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0722209293094, + 38.90774716292588, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00850" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07345875370999, + 38.90771332157698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00851" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07466530957848, + 38.96104214920701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00852" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97606451668062, + 38.92837233305071, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 12/04/07

Report Problem", + "NAME": "H00853" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02088739795322, + 38.97587174488227, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/12/07

Report Problem", + "NAME": "H00854" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07724169280054, + 38.96404571970071, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H00855" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07981623966808, + 38.96406173692394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H00856" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0215177285729, + 38.942055402241564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H00857" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01615607764515, + 38.940929617522166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00858" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97790173749411, + 38.86435560214066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00859" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07285048879902, + 38.96313265987557, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00860" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03244726875441, + 38.90597957804404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00861" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9871504502469, + 38.93718986540383, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H00862" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97398010673248, + 38.928588924825554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H00863" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06848872802077, + 38.933546898735806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/14/08

Report Problem", + "NAME": "H00864" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09044072646705, + 38.95474165690618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00865" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03960509660374, + 38.892286887716025, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H00866" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01249142909948, + 38.89837604929189, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00867" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09791294282094, + 38.918241832211585, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00868" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10337071813137, + 38.92697821766792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H00869" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10118135519639, + 38.92494747805228, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H00870" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09098982220766, + 38.91268943687518, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00871" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09835740942346, + 38.92016374695341, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00872" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01293407256973, + 38.972032667715844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00873" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97221559434684, + 38.930224923257626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H00874" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0415155843193, + 38.91552200075751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H00875" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00537927481935, + 38.84230248961242, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00876" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9857026302258, + 38.86500605429688, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00877" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01878313883964, + 38.89989243113835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00878" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98591056676086, + 38.86430174772459, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00879" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05348645524667, + 38.926676855060656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H00880" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04895527572103, + 38.89410570064894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H00881" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0367537249266, + 38.92699648023964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/11/06

Report Problem", + "NAME": "H00882" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00334433402065, + 38.90367806922617, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00883" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02983369456861, + 38.92104346605919, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H00884" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00066942168479, + 38.925458682803686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00885" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99073939629218, + 38.86537192560533, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H00886" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02535362079801, + 38.91266687498987, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H00887" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02094017220237, + 38.92839147424518, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/13/06

Report Problem", + "NAME": "H00888" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04543976020092, + 38.934127799329964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H00889" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98931922178006, + 38.89210645105821, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/13/06

Report Problem", + "NAME": "H00890" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9894000134754, + 38.890713142485076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/02/06

Report Problem", + "NAME": "H00891" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9925404993397, + 38.932346975736394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H00892" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03471249738996, + 38.91034342550599, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00893" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97961865888138, + 38.931180626705576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H00894" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06327596685209, + 38.9727529398324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H00895" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06503298529833, + 38.97269086407926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00896" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03085709850097, + 38.92247777577873, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H00897" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0309378499679, + 38.92371343482643, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H00898" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0467341294854, + 38.93338634696887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/01/06

Report Problem", + "NAME": "H00899" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03302555312348, + 38.92454083613538, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/05/06

Report Problem", + "NAME": "H00900" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03096021289848, + 38.92480783156651, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H00901" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03140634873986, + 38.92761182105497, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H00902" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03108952924309, + 38.9257996940437, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H00903" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03368886955771, + 38.92868649864836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H00904" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03472141704026, + 38.92861862510296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H00905" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03579146033631, + 38.92787064840089, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H00907" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02718058233971, + 38.90233640398072, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00908" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03371620425382, + 38.93064172643669, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H00909" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03832187973492, + 38.9086342163582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H00910" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03712905045026, + 38.93075869189606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H00911" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9993832558833, + 38.90569120262682, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H00912" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03585400896552, + 38.93137047483482, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H00913" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02685787749867, + 38.907304413054646, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00914" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9936127848748, + 38.88277623759321, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 12/18/07

Report Problem", + "NAME": "H00915" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02950121154154, + 38.930650604515805, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H00917" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02872577477143, + 38.92960634730041, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/25/06

Report Problem", + "NAME": "H00918" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03181953803592, + 38.912745115962515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00920" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05044718973109, + 38.91679821894255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H00651" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04860836375371, + 38.90862195785906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00652" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0135072439775, + 38.90968280533327, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00653" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01222147706642, + 38.914174225516575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00654" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97412852985852, + 38.92484975046252, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H00655" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01207167253078, + 38.9190761966528, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H00656" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98102851307308, + 38.930194823690044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H00657" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99602272247685, + 38.932446066303335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H00658" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02983651692159, + 38.94903956113759, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H00659" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03226669234711, + 38.94903643837466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H00660" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00796022039897, + 38.886857118497275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H00661" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01631439358715, + 38.90569814568789, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00662" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00819987815059, + 38.88742572881885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H00663" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00074031013949, + 38.88873903936953, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H00664" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99838219156732, + 38.88955703607746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/08/06

Report Problem", + "NAME": "H00665" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00209774900779, + 38.891907186920946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H00666" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0551446200081, + 38.91013571869892, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H00668" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03985262477734, + 38.91562239209743, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00669" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02815352060524, + 38.904604756184035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H00670" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01760905858622, + 38.90851294008092, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00671" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03258517237938, + 38.9291798364562, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H00672" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03170847976189, + 38.89931333714904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H00673" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05975309290822, + 38.93563597824736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H00674" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06704842761827, + 38.90382319902977, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H00675" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06920830486993, + 38.90428668953538, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 11/09/07

Report Problem", + "NAME": "H00676" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06793574061754, + 38.904014609429645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H00677" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99631602832157, + 38.89362483664449, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H00678" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03073451170366, + 38.93461727391309, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H00679" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99136033344102, + 38.89472356908853, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H00680" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9870171388433, + 38.89088179993263, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/13/06

Report Problem", + "NAME": "H00681" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01143675331436, + 38.89897030373331, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00682" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0181366136296, + 38.96499577415655, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00683" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01974129301549, + 38.96500663943978, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00684" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04837279682933, + 38.916314429773294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/31/06

Report Problem", + "NAME": "H00685" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04748490780639, + 38.91658632312581, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/31/06

Report Problem", + "NAME": "H00686" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04760345898923, + 38.91553591222147, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H00687" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05073286386714, + 38.91171878072168, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00688" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01080088623986, + 38.92125108392233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00689" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04981244796014, + 38.911928368420995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H00690" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04684229124072, + 38.91488207059559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00691" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0473066258105, + 38.91331349608546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00692" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04894287727178, + 38.911637721456394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H00693" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05015678467589, + 38.91338920257348, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00694" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00572262543777, + 38.88608182622064, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/14/06

Report Problem", + "NAME": "H00695" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04951825089607, + 38.91117242341423, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H00696" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97479702297635, + 38.8707998778302, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00697" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05193596666396, + 38.91331208864754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00698" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97488724676622, + 38.869602536020736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H00699" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04909121826807, + 38.910374149198795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00700" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00577134864527, + 38.90264829272741, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H00701" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05139202933057, + 38.912585392246704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00702" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04867783837187, + 38.907942276232404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00703" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99041966812867, + 38.93738334397939, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H00704" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01367986739568, + 38.92086346947468, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H00705" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00479222837689, + 38.87853414635814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00706" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01883617478768, + 38.918209331479886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/22/06

Report Problem", + "NAME": "H00707" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00196492911333, + 38.913411490758584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00708" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04193796753975, + 38.9246632023148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00709" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08115360049952, + 38.951087320965186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00710" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08196250964956, + 38.9510835677228, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00711" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05255107323511, + 38.927720721550344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 01/02/07

Report Problem", + "NAME": "H00712" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05118960854304, + 38.927033198667196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/02/07

Report Problem", + "NAME": "H00713" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0552689971173, + 38.92824985932468, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/01/08

Report Problem", + "NAME": "H00714" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97299023244767, + 38.92719157399502, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H00715" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9761603492975, + 38.92759325971914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H00716" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02717051131606, + 38.92683502368891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/06/06

Report Problem", + "NAME": "H00717" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01595140325975, + 38.913654562403, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00718" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01126835334301, + 38.89846856342125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00719" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02615824515915, + 38.918163150410834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/02/07

Report Problem", + "NAME": "H00720" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02434593750515, + 38.94415403044285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, JCF&M - O'BRIEN

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H00721" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03675991251376, + 38.91817183593261, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00722" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9882139934856, + 38.94418448274824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H00723" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98556931625309, + 38.894687315099404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00724" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99488466513287, + 38.90119214066332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H00725" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08024468030992, + 38.95457417699644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00726" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08259050574149, + 38.95484507058237, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00727" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08009923423131, + 38.95068416204505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H00728" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01470350055722, + 38.92018815319445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00729" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9948801555543, + 38.896240442858776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00730" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01811746861144, + 38.941111585701336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H00731" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98692805158687, + 38.8887277884754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H00732" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99511043669797, + 38.89547870536883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00733" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02719732379923, + 38.92247923433971, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/21/06

Report Problem", + "NAME": "H00734" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98564170147857, + 38.88062981281078, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H00735" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00577557360182, + 38.88748069884412, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H00736" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98410952649787, + 38.87844934053881, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/13/06

Report Problem", + "NAME": "H00737" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04411354958891, + 38.932551034407645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H00738" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99010264068095, + 38.9008056451461, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H00739" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04810963114737, + 38.91852316502843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H00740" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03498069774, + 38.95085758142868, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H00741" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04921929493923, + 38.9181809448933, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H00742" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98918848999021, + 38.87844813749413, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/08/07

Report Problem", + "NAME": "H00743" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98461034794515, + 38.89895210340257, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H00744" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9936504823689, + 38.903781585645035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00745" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99382318129341, + 38.891429454604264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/17/06

Report Problem", + "NAME": "H00746" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08318931485202, + 38.950960729134344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00747" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00697621720708, + 38.92682257867399, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H00748" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0087335607862, + 38.926582884437835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H00749" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03095049295443, + 38.90259915863328, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H00750" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03184143618208, + 38.89294095457767, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00751" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0770773417392, + 38.963174675990146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00752" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08047884350839, + 38.94633493774677, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00753" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07755865841051, + 38.95079337087014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 02/22/07

Report Problem", + "NAME": "H00754" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03259168889524, + 38.93463087780487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H00755" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0328165523565, + 38.93693769626933, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H00756" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08406173938262, + 38.957753647254634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00757" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0805124581247, + 38.95216677544486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00758" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00995468624028, + 38.875584877343336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00759" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08130287042992, + 38.952240114305575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H00760" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07215872338939, + 38.96404119280406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00761" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07425508711292, + 38.964953497211376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00762" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07463274323176, + 38.96586265763995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00763" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07530113369386, + 38.96677149470722, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00764" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97402556881548, + 38.92241594081955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H00765" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97518271241512, + 38.92339139709763, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H00766" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97517039898017, + 38.923383602285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H00767" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0271003305908, + 38.94830526914321, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H00768" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03175978484622, + 38.920997322289296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 04/05/07

Report Problem", + "NAME": "H00769" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03071910738328, + 38.921136310668786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H00770" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02231848450276, + 38.979296218615936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00771" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02239895193948, + 38.98139980282216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H00772" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02618293472, + 38.94514650847371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00773" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0336193813073, + 38.933572408455916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H00774" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03291057567897, + 38.94622611721635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H00775" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03280701251039, + 38.945182167466186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H00776" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03286919244309, + 38.944064095799305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H00777" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03684059066543, + 38.90959015385614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H00778" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01633314884639, + 38.96499761641715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00779" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02698246571457, + 38.95521961333535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H00780" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0160530607214, + 38.963830240186354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00781" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08790215799044, + 38.93544022120361, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/25/08

Report Problem", + "NAME": "H01030" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0885802377269, + 38.933611392635385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H01031" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98242552832846, + 38.92733087662477, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H01032" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99628131815844, + 38.8861419660861, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01033" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08879400215685, + 38.93138872750128, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H01034" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09418149019496, + 38.95214948243766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H01035" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02607688010123, + 38.92065062892319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H01036" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00429660863546, + 38.917596681837956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01037" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07366503454432, + 38.920848889010955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00782" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02311197200497, + 38.9312850383782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H00783" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03456967680417, + 38.946192163588314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H00784" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01752308654319, + 38.91782115967092, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00785" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05072003616347, + 38.917741480339046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H00786" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02499203325878, + 38.94175694207643, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H00787" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9700043205496, + 38.92921471628457, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00788" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97023087536384, + 38.92780060437805, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00789" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07724499887098, + 38.962103078433984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00790" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0034438296227, + 38.89106698015863, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H00791" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0276437318776, + 38.975757046540714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H00792" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01119545368773, + 38.94439719035928, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H00793" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0352027278312, + 38.89958149725826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00794" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01725604780864, + 38.90046549918429, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00795" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03380368015252, + 38.89935024246808, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00796" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06159044574477, + 38.94112939177615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/20/06

Report Problem", + "NAME": "H00797" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03332190066826, + 38.95826442886073, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H00798" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04594972261398, + 38.91853859177208, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H00799" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97662668099572, + 38.91183928644571, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H00801" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05815709016022, + 38.91247061659439, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00802" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03831620453482, + 38.90970241868409, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/25/07

Report Problem", + "NAME": "H00803" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00715477418528, + 38.92612127057033, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/26/07

Report Problem", + "NAME": "H00804" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97338310345022, + 38.87345832211571, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00805" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00797054412702, + 38.925308793784666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00806" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00782794323808, + 38.89722115045011, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H00807" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00708180128606, + 38.89585581834181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H00808" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97312365293529, + 38.870860951015686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00809" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9925802833101, + 38.88186748259304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/27/06

Report Problem", + "NAME": "H00810" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97493868638968, + 38.87245824729695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00811" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97489907988236, + 38.87275139921586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00813" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0073439925139, + 38.8774693027581, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H00814" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00368889906899, + 38.87834510025877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00815" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99274255731177, + 38.90137404107174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H00991" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98923774692922, + 38.88165528208443, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/07/06

Report Problem", + "NAME": "H00992" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02175250644969, + 38.907294863283546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00993" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99623855782751, + 38.88284436498623, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H00994" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02478261045431, + 38.93978227925184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00995" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9882218181247, + 38.90199075414977, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H00996" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98738160293496, + 38.90169605715971, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H00997" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00304288131125, + 38.84210657711564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H00998" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99674922073514, + 38.84577667489998, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H00999" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99591095222571, + 38.848576624800614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/21/07

Report Problem", + "NAME": "H01001" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98461363601996, + 38.894183292076356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01002" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03669948111862, + 38.93274326742947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H01003" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03414805098019, + 38.93177263008724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H01004" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03548963652308, + 38.93227019155713, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H01005" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0328762150876, + 38.93127699738826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H01006" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98462473029034, + 38.89234132522096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/13/06

Report Problem", + "NAME": "H01007" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03829684485254, + 38.933363643320035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H01008" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04365062934166, + 38.90794355991402, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01009" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05521926492962, + 38.92599731754884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/09/07

Report Problem", + "NAME": "H01010" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00185804315322, + 38.89484108166827, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01011" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01160212742568, + 38.97129560044692, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H01012" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04823235215979, + 38.91452545961899, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/05/07

Report Problem", + "NAME": "H01013" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04248321942809, + 38.93062324809139, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 01/29/08

Report Problem", + "NAME": "H01014" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01980161884329, + 38.97373306460092, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/12/07

Report Problem", + "NAME": "H01015" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0772484593844, + 38.95837626009613, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01016" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00071482574262, + 38.902585617839584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H01017" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99485375203326, + 38.8451790317024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01018" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99610046779165, + 38.84516798160559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/07/07

Report Problem", + "NAME": "H01019" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06089373324902, + 38.911261230915514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01020" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02802666834747, + 38.905750729941865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/28/08

Report Problem", + "NAME": "H01021" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10590181734473, + 38.9288197380787, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01022" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03895275313891, + 38.91867848363708, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/30/08

Report Problem", + "NAME": "H01023" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06348330088213, + 38.93468953631698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H01024" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02324743229828, + 38.936668805394945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H01025" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97889371339274, + 38.896156474037824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01026" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02153046379266, + 38.937053815598304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01027" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02065347666459, + 38.91918660817023, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H01028" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02034003683659, + 38.937231960694426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01029" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95057939527733, + 38.8930201942944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01038" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9434106876319, + 38.901189339008056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H01039" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0019669411962, + 38.88728210024327, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/10/06

Report Problem", + "NAME": "H01041" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04701775736768, + 38.90595205703593, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01042" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00187411174693, + 38.88516672685189, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/06/07

Report Problem", + "NAME": "H01043" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97967713995875, + 38.93297493820744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H01044" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00499894837685, + 38.91704310102508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01045" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00445025736542, + 38.837914692815225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01046" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0213581074638, + 38.97370528856168, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H01047" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04646473758444, + 38.91265866645512, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01048" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02327438509997, + 38.935989997727084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01049" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02979822981926, + 38.90571464549881, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01050" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05029444906312, + 38.89962662882252, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H01051" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98109765783735, + 38.93118043385557, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H01052" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00210404395237, + 38.88335143456431, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 01/10/07

Report Problem", + "NAME": "H01053" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01423371113836, + 38.93926456758919, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H01054" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01352986367627, + 38.94000352934251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H01055" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04648883654312, + 38.911173920252565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01056" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01446585388359, + 38.9096964463205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H01057" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04889803446264, + 38.91266018681594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01058" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01745977582902, + 38.90649621892462, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/08/08

Report Problem", + "NAME": "H01059" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00064459995251, + 38.88289331228595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/07/07

Report Problem", + "NAME": "H01060" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03681213963031, + 38.905711583088326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/29/07

Report Problem", + "NAME": "H01061" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03997397268957, + 38.93294179939662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H01062" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01524617188079, + 38.90951290120818, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01063" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07039277179258, + 38.90676376517887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H01064" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07289165639922, + 38.92832674869288, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01065" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98623506690751, + 38.88643767998779, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01066" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07074745583294, + 38.92676534878509, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01067" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98245049266036, + 38.88029939056729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01068" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06851893637447, + 38.92514746743295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01069" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03434577597278, + 38.94515193510014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H01070" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0642517009663, + 38.90523347886796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01071" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06945885833555, + 38.92602000784756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H01072" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99712003778735, + 38.90558313162535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01073" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08044711284144, + 38.9539029757847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01074" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06739588664657, + 38.92455806652047, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01075" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07059506763527, + 38.97046281998418, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H01076" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02722480428261, + 38.91562280061169, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01077" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00705099832936, + 38.91800122026909, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/01/08

Report Problem", + "NAME": "H01078" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05632355420633, + 38.91622064944444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01079" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00601439986795, + 38.91815632957647, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01080" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01003853951129, + 38.95646008550201, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01081" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06318282606173, + 38.918515626831244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01082" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98559855134397, + 38.90438597958521, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01083" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05072469617849, + 38.914857775736934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H01084" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99930690189358, + 38.90653568082517, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01085" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04403760881928, + 38.93149802805645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H01086" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99998261203325, + 38.843219295039894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01087" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10376195473017, + 38.92579351099977, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01088" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10245132485421, + 38.92445367938406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01089" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04675304939533, + 38.92064142032478, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/07/07

Report Problem", + "NAME": "H01090" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03126739178111, + 38.95846256549808, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H01091" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99271121092832, + 38.88423067860804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H01092" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99968826612712, + 38.88549325027117, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H01093" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01714746631139, + 38.911077792000114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01094" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02099283069813, + 38.908490824132535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H01095" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0162303436936, + 38.91272933173848, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/30/07

Report Problem", + "NAME": "H01096" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98099700989233, + 38.882096615884365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01097" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99270877032149, + 38.88352625884904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H01098" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01206770019631, + 38.9180210696043, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01099" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96487669838466, + 38.87104558704628, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H01100" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04163387392822, + 38.89364972525527, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H01101" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04165868958425, + 38.89267844292344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H01102" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04083570445405, + 38.892230756222006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H01103" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05336016120515, + 38.903449730904676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01104" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03466550910261, + 38.95192067850163, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H01105" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02095068622666, + 38.97744299354791, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01106" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02605284269748, + 38.91422736149244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H01107" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99159379851616, + 38.892751284903305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/22/06

Report Problem", + "NAME": "H01108" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07774476196049, + 38.952706226427104, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01109" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00945227234384, + 38.96021602015782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01110" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9996852059546, + 38.9181614204952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H01111" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07105760964761, + 38.91457700196526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01112" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04015338137422, + 38.92574120589587, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H01113" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03660477102156, + 38.91668587040987, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01114" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98428969052102, + 38.92897056480209, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01115" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98621858165949, + 38.92888001340834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 03/07/08

Report Problem", + "NAME": "H01116" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98849020783051, + 38.92874746768866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H01117" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03610388193282, + 38.95830277983555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01118" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99623378515828, + 38.90273608891848, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H01260" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03784493973886, + 38.91548759226401, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01261" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0339911604111, + 38.8964932309644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H01262" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03461169584533, + 38.896333663756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H01263" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0346881138083, + 38.94967780984984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H01264" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03505196427452, + 38.897636817538846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H01265" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03506423683316, + 38.89720538532162, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H01266" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06126172689633, + 38.902658587561895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01267" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0385204501002, + 38.92796907942228, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H01268" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01744683670653, + 38.884753350369856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01269" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10245099692925, + 38.92574250041143, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01270" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05057597228914, + 38.915732621584645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/31/06

Report Problem", + "NAME": "H01271" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99257393611859, + 38.89346414757438, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/16/06

Report Problem", + "NAME": "H01272" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00134054455694, + 38.88988766496422, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01273" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0287532997781, + 38.93977761350051, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H01274" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02821991187203, + 38.93892302761489, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H01275" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03893123182971, + 38.92722597362507, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01276" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02211030576565, + 38.9346959742425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H01277" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03505864228194, + 38.896705476847394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H01278" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99479131113755, + 38.8774704444705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/07/06

Report Problem", + "NAME": "H01279" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02814783313852, + 38.907370870262305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 01/28/08

Report Problem", + "NAME": "H01280" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02301353427221, + 38.899942202257186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H01281" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01878796832919, + 38.90728654943058, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/04/08

Report Problem", + "NAME": "H01282" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06648399581624, + 38.96486080367615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01283" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02980330962586, + 38.918065384007974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01284" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02718157551762, + 38.918163889752904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H01285" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99728667693809, + 38.88685488993583, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/07/06

Report Problem", + "NAME": "H01286" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03133349487597, + 38.97944122809842, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01287" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05487479411555, + 38.90368554364328, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01288" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07073322685143, + 38.93352231152344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H01289" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01235997090174, + 38.965012778328564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H01290" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01376165638007, + 38.96500091104376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01291" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0697614609087, + 38.92475083468198, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H01292" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02949243392233, + 38.90845306252808, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01293" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0734675858721, + 38.96393850343997, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01294" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02981463399068, + 38.90728262542809, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01295" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9944952806497, + 38.903156701048964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01296" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02980137740762, + 38.91562145122284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01297" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05653768641652, + 38.92847400087578, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/20/08

Report Problem", + "NAME": "H01298" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03276206492265, + 38.90558663606525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01299" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05638572645356, + 38.927229503618705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/09/07

Report Problem", + "NAME": "H01300" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01511849538126, + 38.880429568481176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01301" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06853997896148, + 38.93736966779079, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 03/08/07

Report Problem", + "NAME": "H01302" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0318214772029, + 38.91125090216896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H01303" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03097123782356, + 38.91036370991568, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H01304" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99382600202773, + 38.89213396346672, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H01305" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0464904946613, + 38.91078139010919, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01306" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00334796081455, + 38.91487531381453, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01307" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04253965894844, + 38.929747142439545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/22/07

Report Problem", + "NAME": "H01119" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00367817964616, + 38.91632508697752, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01120" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00367735162028, + 38.917038519807605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01121" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00501181248865, + 38.916323785229494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01122" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02856741514455, + 38.92678457732254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00921" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02874768998996, + 38.92761027121273, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H00922" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02733406566726, + 38.928670195114464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00923" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04798171390973, + 38.91913754961618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H00924" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03108027692984, + 38.92669160083335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H00925" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02688437259697, + 38.92572037387635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00927" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02696301926464, + 38.922903931903974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00928" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03276934981878, + 38.904454095137545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H00929" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08228957627604, + 38.908698381034554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H00930" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02689912670301, + 38.92374441392029, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00931" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9963462050196, + 38.90378059302521, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H00932" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02817758611357, + 38.9238200437837, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H00933" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09869712061487, + 38.919018204308266, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00934" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02814555163172, + 38.92247991064203, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H00935" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02841847883096, + 38.925816336823786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H00936" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04179985906374, + 38.91878235683632, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H00937" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07449084634996, + 38.95974323350111, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00938" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10977213906301, + 38.92839117253699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H00939" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01066175761832, + 38.91338684248242, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H00940" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07703382475488, + 38.96034055394016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00941" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07625719896264, + 38.95905172873574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H00942" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0309389859885, + 38.932578100448914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H00943" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03079384352402, + 38.933820753227806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H00944" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02980907676186, + 38.93340777064042, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H00945" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99578145804072, + 38.85265546831029, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H00946" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03904529624903, + 38.91413853245932, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H00947" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05868767581333, + 38.94106986303479, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H00948" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02751582997492, + 38.932902165429724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H00949" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02814993274278, + 38.91800776234343, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H00950" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02715471529463, + 38.90976409105831, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H00951" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02529089784515, + 38.93292866601758, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/09/08

Report Problem", + "NAME": "H00952" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99382703525835, + 38.88592108476634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/12/07

Report Problem", + "NAME": "H00953" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97022530785893, + 38.925694873340795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H00954" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9963353109303, + 38.88873345308379, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H00955" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02438891265945, + 38.92653697560749, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00957" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99487386791456, + 38.88203364837203, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/04/06

Report Problem", + "NAME": "H00958" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00752284897247, + 38.875457968847684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00959" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02447817621386, + 38.92603925652625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H00960" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00209251840256, + 38.89003085103512, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H00961" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01070964913265, + 38.87557049620656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H00962" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02688802490417, + 38.92482427969066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/21/06

Report Problem", + "NAME": "H00963" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04340755980301, + 38.93065027568632, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H00964" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0019632067488, + 38.89105285326527, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H00965" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02835293489912, + 38.92481638449598, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H00966" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98565968938456, + 38.88540307026997, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/06/07

Report Problem", + "NAME": "H00967" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02591134002633, + 38.935109232923914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/13/07

Report Problem", + "NAME": "H00968" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02249891059371, + 38.92328069475677, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H00969" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99851457689392, + 38.8910540314067, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H00970" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06630055242039, + 38.933441556188804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H00971" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03460134517405, + 38.92528373759628, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H00972" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07974772374365, + 38.952739306941815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H00973" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01899127513543, + 38.909746803630455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H00974" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04729237131455, + 38.92012539555548, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H00975" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02816048892544, + 38.92059080755352, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H00976" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02300566269213, + 38.918751273729306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H00977" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02146631685001, + 38.97247180737497, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/10/07

Report Problem", + "NAME": "H00978" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0691127857704, + 38.91262541283799, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H00979" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02824315678856, + 38.91913087121627, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/28/07

Report Problem", + "NAME": "H00980" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98677527969163, + 38.86429693927759, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H00981" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00065269304154, + 38.88439791063407, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H00982" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03171952703623, + 38.91562833310763, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/22/07

Report Problem", + "NAME": "H00983" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08048426947165, + 38.94483666694808, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H00984" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02772843472025, + 38.95519414358661, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H00985" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09252511484338, + 38.95222693399096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, Metropolitan

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00986" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9916173110249, + 38.884238640698534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H00987" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09251860499913, + 38.9498157025937, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/12/07

Report Problem", + "NAME": "H00988" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09251818262467, + 38.95116131447385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H00989" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99229101073968, + 38.929444545981134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H00990" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99958535821078, + 38.884393921007955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H01346" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03324060932577, + 38.98043663254894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01347" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99861133887138, + 38.88657672542416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H01348" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99943350723875, + 38.89603904557128, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01349" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03972411624017, + 38.90970408347191, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H01350" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99958718845025, + 38.888782956821174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H01351" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00049205147249, + 38.894896496864035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01352" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05803198103061, + 38.90855168918467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01353" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01902032785169, + 38.91916356284706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H01354" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02098415370156, + 38.912465161891056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H01355" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06832022220472, + 38.91165236552843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01356" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99369075732835, + 38.93148955188863, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01357" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99375773210112, + 38.9322686568161, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01358" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03372254853788, + 38.9014539428181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01359" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00334336053685, + 38.902586121696324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H01360" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00338152084385, + 38.901382928635776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H01361" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98868669290609, + 38.93172728218154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01362" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01206340962221, + 38.92224165071239, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/25/07

Report Problem", + "NAME": "H01363" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0710942990464, + 38.91548998357376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H01364" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9846922033922, + 38.933894576575184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01365" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01656208341545, + 38.91011013735514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H01366" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99016655986281, + 38.92660222800276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H01367" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01209847417567, + 38.872872525187184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01368" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97639915775338, + 38.92563658509472, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H01369" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9743351566571, + 38.925639185851914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H01370" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01237230989125, + 38.8886653915865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01371" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01236788365296, + 38.88866472543537, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01372" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97451975942855, + 38.86365931031904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01373" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02180942036213, + 38.94309440910964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/15/07

Report Problem", + "NAME": "H01374" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98753200501619, + 38.89423311397515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01375" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05218711874285, + 38.90379169542129, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01376" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0422025297031, + 38.92063365753914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H01377" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01075657899649, + 38.81725804479435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01378" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04580450193221, + 38.931523932470704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/01/06

Report Problem", + "NAME": "H01379" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05032113866157, + 38.89493919609121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01380" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05175787121735, + 38.89464615671381, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01381" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0297996572156, + 38.97585854426577, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01382" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10872595112201, + 38.92708115180884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H01383" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9881627126412, + 38.87759875373104, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/03/07

Report Problem", + "NAME": "H01384" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10021213247848, + 38.923678229601464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01385" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0326625962599, + 38.92797885373859, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H01386" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98667823527371, + 38.862458652900116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H01387" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98841498850794, + 38.92776683344535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H01388" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06751739223722, + 38.96393841520778, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01389" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98543660046072, + 38.8987607726603, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01390" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01766936490385, + 38.93786092176164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01391" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98837354402993, + 38.899661982894166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01392" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98913303378683, + 38.88835697740303, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/09/06

Report Problem", + "NAME": "H01393" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02745507755345, + 38.92776620063168, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01394" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99443397184977, + 38.898861261364594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/10/07

Report Problem", + "NAME": "H01395" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9901654964023, + 38.900029102983225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H01396" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01854680747583, + 38.97476716305724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H01397" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01962004333944, + 38.976781011630656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01398" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03177395654339, + 38.916337256100114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01399" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0678677568178, + 38.91561253275963, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H01400" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06800519709321, + 38.91474776968932, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/15/07

Report Problem", + "NAME": "H01401" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03361769494192, + 38.95932557120131, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01402" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02977407831762, + 38.91635310596354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H01403" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01700160878998, + 38.976991349302246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01404" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04160161471164, + 38.8944693271625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H01405" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01391879717032, + 38.974665435911255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01406" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01368355595714, + 38.97284008956856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H01407" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02020450656448, + 38.93127801018239, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H01408" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01175073838544, + 38.97005024179373, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H01409" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99257141262353, + 38.88614869848065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H01410" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98537502061258, + 38.88665823573472, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H01411" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04149447307101, + 38.896122202421914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H01412" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9865526989882, + 38.88546701889877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H01413" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99708234145746, + 38.92747465510347, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01414" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99141696145851, + 38.88030415020904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/26/08

Report Problem", + "NAME": "H01415" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0457781695096, + 38.90126963768948, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H01416" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98967469590805, + 38.8630668262699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01417" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99504747482258, + 38.890813160068454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/23/06

Report Problem", + "NAME": "H01418" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0477808291248, + 38.899622882481616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01419" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0281554579527, + 38.90869507724731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H01420" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04543979651389, + 38.92229459652637, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/16/06

Report Problem", + "NAME": "H01421" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04657078787338, + 38.92243387037017, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/29/06

Report Problem", + "NAME": "H01422" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99036555788003, + 38.892765405265465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01423" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.982151279978, + 38.890805730653256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/11/06

Report Problem", + "NAME": "H01424" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0403422861527, + 38.93051964544143, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H01425" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04009472547922, + 38.911072152937386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01426" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99030917706406, + 38.889132206660484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H01427" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.027212265686, + 38.95616568010513, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H01428" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04014765030604, + 38.93149791561874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H01429" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02594020312957, + 38.92789592407714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01430" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0685070340173, + 38.91656352092913, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01431" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01603118828567, + 38.911065924355206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01432" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01714105631734, + 38.93895454434028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H01433" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01222852584014, + 38.911976280582394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01434" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07193166667204, + 38.95905565895274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01435" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02287358707981, + 38.90193504952017, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H01436" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03623161021987, + 38.91117416399947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/23/07

Report Problem", + "NAME": "H01437" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04285327470741, + 38.932412550168074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H01438" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06508381575985, + 38.912530904838825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01439" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98785773286018, + 38.86001891428376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H01440" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06952060676896, + 38.90592663689438, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H01441" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07032642117252, + 38.9063900216502, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01442" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03810283796157, + 38.93113988933674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H01443" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02250461193911, + 38.89972571342753, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01444" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98766571357488, + 38.906478567488165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01445" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98565706299972, + 38.925759736308656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H01446" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06975740648444, + 38.90676611908557, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01447" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9874357466905, + 38.885298471310634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/19/08

Report Problem", + "NAME": "H01123" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03473479504007, + 38.920474182194575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01124" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04567648666824, + 38.90711725152424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/08/07

Report Problem", + "NAME": "H01125" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07868683580811, + 38.95837812952171, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01126" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03675846776675, + 38.91266183485176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01127" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07587085633425, + 38.95149599785176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H01128" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03259602579837, + 38.947119484482364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H01129" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07476646354421, + 38.95145080318647, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H01130" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99965037822234, + 38.902456070358866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/25/07

Report Problem", + "NAME": "H01131" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07879088009778, + 38.95706111429798, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01132" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0772445172896, + 38.957059632852044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01133" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04039977163417, + 38.9176016410672, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01135" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0465816679434, + 38.909501934854696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H01137" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08018948214726, + 38.962096934343755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01138" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0403901572071, + 38.9266663234115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01139" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0198398537631, + 38.972249861467375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01140" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02165721981245, + 38.94102544074561, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H01141" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06222469940626, + 38.93001324432045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/17/07

Report Problem", + "NAME": "H01142" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97495691352685, + 38.9301968243122, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H01143" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0122352301828, + 38.894868237489746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01144" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00638766883195, + 38.916939887977165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/09/08

Report Problem", + "NAME": "H01145" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04183924980079, + 38.917033141238356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01146" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99369724074582, + 38.87471310962728, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/18/06

Report Problem", + "NAME": "H01147" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0335235866018, + 38.95720290975613, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H01148" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06649099215244, + 38.96317058138602, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01149" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03255845293785, + 38.941763277017365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H01150" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01676337231363, + 38.97516410969956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01151" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06789833588407, + 38.964845523718665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01152" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98272481650363, + 38.931021761135625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01153" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02983768153747, + 38.93969515006549, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H01154" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07105401617015, + 38.93257813652327, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H01155" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07265460464963, + 38.960340303320436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01156" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07152155648814, + 38.96034250626626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01157" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98226869040252, + 38.92814320456875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H01158" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97086276404467, + 38.93183369374606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H01159" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00637904618965, + 38.916323196105964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01160" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98584076213282, + 38.88132798724272, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/17/06

Report Problem", + "NAME": "H01161" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98535587196963, + 38.89543760439186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H01162" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02312111282507, + 38.907297077756155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/01/07

Report Problem", + "NAME": "H01163" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98558064267291, + 38.87908510053281, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/10/07

Report Problem", + "NAME": "H01164" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07230236585579, + 38.959718168041576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/15/07

Report Problem", + "NAME": "H01165" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05461672845477, + 38.905334994871545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01166" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0634239168755, + 38.930336952928, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H01167" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98621570565703, + 38.93170632479768, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01168" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01410263400096, + 38.90131034779346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01169" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93391721844836, + 38.910376899938775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H01170" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01909284938064, + 38.90258566337233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01171" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00055198441164, + 38.84303053977152, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H01172" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00897242916314, + 38.86935816038689, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H01173" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02480931418043, + 38.9408791952257, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01175" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03557587351888, + 38.92637909951481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/18/07

Report Problem", + "NAME": "H01176" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98240755930101, + 38.94248111496923, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01177" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02124245809424, + 38.9357085600342, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/09/07

Report Problem", + "NAME": "H01178" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02315500183269, + 38.908624027409545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01179" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03319232066133, + 38.91327003726308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01180" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03493483747779, + 38.900358800888, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01181" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02614239499393, + 38.96618006798379, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01182" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03793220575525, + 38.90038004469125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H01183" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07445316348512, + 38.930970190502315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H01184" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00909971517954, + 38.95774390271903, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01185" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05489072470027, + 38.90432689490299, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01186" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02784014951384, + 38.93073856373892, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H01187" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02788007461147, + 38.92975825203883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H01188" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06117406151326, + 38.907724570368615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01189" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99837130275425, + 38.891918040481904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H01190" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05927040113191, + 38.907753135151125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/03/07

Report Problem", + "NAME": "H01191" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00444872914262, + 38.84185591699355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H01192" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9737266148885, + 38.89829202979229, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01193" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02685264669319, + 38.908630658975376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H01194" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01777337435135, + 38.91941778497078, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/04/06

Report Problem", + "NAME": "H01195" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99381590740627, + 38.90034454669514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H01196" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02508851743735, + 38.919222331969785, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H01197" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02078822973674, + 38.92016996021241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H01198" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02686166102042, + 38.90140080684872, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01199" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99172116576136, + 38.88972662482251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01200" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07077388651813, + 38.92366107484999, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01201" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01209387625892, + 38.901432248879416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01202" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00714956660148, + 38.90259231066718, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01203" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00188687256431, + 38.91486989650086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01204" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0643494441716, + 38.908747852407146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/05/08

Report Problem", + "NAME": "H01205" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05714097454265, + 38.907572110254456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01206" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00064527452604, + 38.914154089657, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/25/07

Report Problem", + "NAME": "H01207" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98845944682753, + 38.9383852947033, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H01208" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02156351393934, + 38.91414938120975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "null

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01209" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00065274414288, + 38.881164746906826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H01210" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03661030143252, + 38.914251321398666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H01211" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0034386848095, + 38.890029819232915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H01213" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98530275963574, + 38.9017303251402, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H01214" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02612713971628, + 38.90571409180324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01215" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98095121523569, + 38.93210621172763, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01216" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0340216318606, + 38.920503903273044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H01217" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09434450959813, + 38.949827305338744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H01218" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02328979617391, + 38.94305691931498, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H01219" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08192767614064, + 38.958065388702295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01220" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00425559178476, + 38.877579610775015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H01221" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99859496410137, + 38.88872951141116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H01222" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04412538918903, + 38.93336255208931, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H01223" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04509550026437, + 38.89962279685093, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H01224" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00494192480275, + 38.911008716725306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H01225" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04757451242816, + 38.92828599002464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/09/06

Report Problem", + "NAME": "H01226" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04873063157197, + 38.92961008685809, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/11/06

Report Problem", + "NAME": "H01227" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04528224830476, + 38.93318976273631, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H01228" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04548743333663, + 38.91777328080344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H01229" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03945081564946, + 38.92602743220156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H01230" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98765131463672, + 38.90647231417365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/22/06

Report Problem", + "NAME": "H01231" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03450378388636, + 38.92154557464372, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H01233" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03332386123981, + 38.92161640720116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H01234" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03252860777019, + 38.957326964329766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/27/07

Report Problem", + "NAME": "H01235" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01052210812912, + 38.897954057398934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/06/07

Report Problem", + "NAME": "H01236" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0241095690236, + 38.88030765237457, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01237" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00596570977216, + 38.90457944856012, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01238" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0228721051199, + 38.88041442548278, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 11/18/07

Report Problem", + "NAME": "H01239" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02295620712553, + 38.88329230054347, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01240" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01884216381268, + 38.900768025034445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01241" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02205276216445, + 38.88035901030967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01242" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02342470883548, + 38.879366189702964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01243" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02285954294592, + 38.878508108208116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01244" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01436844599127, + 38.91694288159885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01245" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06421035163879, + 38.91369220270595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01246" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00049953651703, + 38.89214420592811, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01247" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03075271432112, + 38.980322539438426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01248" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0297649329638, + 38.97950786625973, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01249" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97912292411009, + 38.86938286232804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/04/07

Report Problem", + "NAME": "H01250" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97524297336714, + 38.92141320039317, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H01251" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04149196848284, + 38.91117984628575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H01252" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98158591364003, + 38.8996206356333, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01253" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99161932714492, + 38.885914172920906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H01254" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03681986525778, + 38.91042635981995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01255" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03622395785315, + 38.91190762544506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01256" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01372016991348, + 38.90713612142087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01257" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0415012735067, + 38.909575349081145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/08/08

Report Problem", + "NAME": "H01258" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01878975284264, + 38.9057013231001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01259" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99278668745065, + 38.89727609599099, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/13/07

Report Problem", + "NAME": "H01308" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01168605099308, + 38.89716571504747, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01309" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99382396376973, + 38.901431513499695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01310" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99610176250134, + 38.89719134983101, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01311" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98689393974941, + 38.8986078751824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01312" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01101709229322, + 38.90967841836587, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01313" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04670628539925, + 38.90711369146798, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01314" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02591361058987, + 38.90232301719525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/22/07

Report Problem", + "NAME": "H01315" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9850216760369, + 38.868276877879424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01316" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02576997642896, + 38.9036002443928, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01317" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02612844088057, + 38.904230389114375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H01318" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99609186327798, + 38.92953965544233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01319" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99606522675055, + 38.930500732997814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01320" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02511049571578, + 38.90245347140325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01321" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01606063786096, + 38.908514649565234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H01322" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0268485835777, + 38.9057083700895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H01323" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00335618698145, + 38.921349104023456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H01324" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0210386702432, + 38.90969574494479, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01325" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06330793988118, + 38.90765662770343, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01326" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99516617438064, + 38.88132275492173, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/04/06

Report Problem", + "NAME": "H01327" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98376480920346, + 38.86478025729087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01328" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00569804183291, + 38.87758217975662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H01329" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01013313215834, + 38.83154843890562, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01330" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01210408995168, + 38.87085599362729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01331" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01210158760601, + 38.87193295754201, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01332" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00379167621217, + 38.87422273786634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01333" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99478659119877, + 38.89727545466726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01334" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07144880328613, + 38.9631444878158, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01335" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07032797254784, + 38.91550556330122, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H01336" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03105081083292, + 38.90735687453357, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01337" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99170695159191, + 38.879331346061655, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/10/08

Report Problem", + "NAME": "H01338" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0241186677307, + 38.90729411953351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H01340" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01462896278859, + 38.919240144312646, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H01341" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03861932187694, + 38.914919246299405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01342" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00582141317908, + 38.88267767938914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/05/06

Report Problem", + "NAME": "H01343" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98090178865581, + 38.86607543205955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H01344" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04492837694538, + 38.91422924939429, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 01/31/08

Report Problem", + "NAME": "H01345" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0274274232013, + 38.952954480004486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H01518" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02789213881012, + 38.95608858931455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H01519" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99368965796253, + 38.902339962934875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H01521" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06780453741156, + 38.912753953630855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H01522" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04567623773461, + 38.92140182451452, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H01523" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0020985503904, + 38.89367958370827, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01524" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04352071452138, + 38.90648749904412, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01525" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07100721219906, + 38.91268027278722, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01526" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06654512384404, + 38.913794014809426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H01527" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0955303256683, + 38.95047605547877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H01528" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06510588263896, + 38.96499800906057, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01530" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02241726103647, + 38.95536863764007, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H01531" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02409937696957, + 38.95529958796547, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H01532" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00058364348007, + 38.87462519412972, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01533" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09681477779233, + 38.950921485142054, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01534" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0021005442548, + 38.903847121925295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01535" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99623492443291, + 38.88399116829376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H01536" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00049911119648, + 38.903845788489654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/03/08

Report Problem", + "NAME": "H01537" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01236060524063, + 38.89728325880814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H01538" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01071561323114, + 38.87215737514364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01539" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09873186521835, + 38.94875397605435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton, DC

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H01540" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04141639967317, + 38.9332376163356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H01541" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09671370542131, + 38.94801224556935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H01542" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03536159660199, + 38.92555740791575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01543" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02598165209017, + 38.95739610139378, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H01544" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99009071713085, + 38.93825695907212, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01545" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00290255506258, + 38.87743150920006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01546" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00067179956181, + 38.91712571332078, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H01547" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99031025293468, + 38.9401095599963, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01548" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0333796739256, + 38.97645537229134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01549" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01233725589168, + 38.907182434403545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01550" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01884370145609, + 38.903141212983364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/05/08

Report Problem", + "NAME": "H01551" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98896120106119, + 38.88916657111018, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/09/06

Report Problem", + "NAME": "H01552" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99957221375871, + 38.8833366519562, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01553" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0690804055293, + 38.90682454411589, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01554" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9814253514975, + 38.934058657717664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01555" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9953382742684, + 38.94367918676709, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H01556" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99359393078423, + 38.88404347308606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H01557" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99143299235081, + 38.8849150668084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H01558" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06915341289559, + 38.91371385746126, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01559" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02720670463127, + 38.9126397755058, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H01560" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02056219793224, + 38.9325948449953, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H01561" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08312317562422, + 38.90975480338903, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H01562" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08371159178213, + 38.91055534233563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H01563" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9938219439826, + 38.897464925569054, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01564" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97110493763128, + 38.92763022431628, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H01565" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99851730893323, + 38.8843887054874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H01566" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04148024770123, + 38.92885314210014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H01567" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99852600382933, + 38.88026352217019, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/05/06

Report Problem", + "NAME": "H01568" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99363750230991, + 38.88463700181735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H01569" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99043377188606, + 38.88530823215247, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H01570" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00931126655631, + 38.909692547707586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01571" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06898121262883, + 38.90876119043231, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 03/05/08

Report Problem", + "NAME": "H01572" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00188501310767, + 38.884216891798005, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H01573" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9868844925189, + 38.89738552951181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H01574" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99016175015956, + 38.88247254138519, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/19/06

Report Problem", + "NAME": "H01575" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07123390078415, + 38.91365396335679, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H01576" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0602461882709, + 38.94210084378007, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H01577" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99625064538374, + 38.87828802115672, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/04/07

Report Problem", + "NAME": "H01578" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99624980266789, + 38.87743778192459, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H01579" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99623547593237, + 38.88140254554251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01580" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99968797875567, + 38.88268049053276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01581" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00926405122772, + 38.917052930055696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM FOUNDRY - O'BRIEN

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01582" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97984169617975, + 38.88289318695628, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H01583" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98235973956673, + 38.88540169063197, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H01584" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98837626389289, + 38.89372389492191, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01585" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9839675264306, + 38.897446170234154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01586" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99842278956955, + 38.88009714486881, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/05/06

Report Problem", + "NAME": "H01587" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03948068361906, + 38.91969359906079, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H01588" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99943936139965, + 38.84199978425332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H01589" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9935939271112, + 38.8793346087374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 04/27/07

Report Problem", + "NAME": "H01591" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99962958298268, + 38.87758511978389, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY

In Service


Last Inspection Date: 01/31/08

Report Problem", + "NAME": "H01593" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00286170999833, + 38.96042850262832, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01594" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0678138123935, + 38.913644098299166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/15/07

Report Problem", + "NAME": "H01595" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0518080392284, + 38.909584313657874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01596" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05718846155007, + 38.90945253428917, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H01597" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05299033329835, + 38.9095371472348, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01598" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0122494174769, + 38.91492462588635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01599" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98961525573564, + 38.865421908806205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H01600" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05571815897147, + 38.90929308533062, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H01601" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99011971597042, + 38.86383704827926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01602" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05470388491976, + 38.90929950111312, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H01603" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98884673718555, + 38.8637690191821, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01604" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99044467093604, + 38.924499493826936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H01605" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97947198591969, + 38.93023592681651, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01606" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02092132873568, + 38.93401612939577, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H01607" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03731907659451, + 38.93469192756191, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H01608" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04378624701876, + 38.916896366047325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H01609" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06280619517617, + 38.90674540672929, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01610" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0821058647827, + 38.96092171128651, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01611" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04161027006936, + 38.92602856602167, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/23/06

Report Problem", + "NAME": "H01613" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99963606126447, + 38.91570978512348, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01614" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01860301895802, + 38.915703998866434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01615" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99942711977184, + 38.89188235926396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H01616" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01839824472057, + 38.94194151157028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01617" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0652346086041, + 38.96406529508177, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01618" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97602629784772, + 38.92456238445846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H01619" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02815428136125, + 38.908693627187326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/28/08

Report Problem", + "NAME": "H01620" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0020932818363, + 38.91565783390171, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01621" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01609708374991, + 38.91597748558224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01622" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06628873779425, + 38.965914897735864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01623" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99754224124091, + 38.87757968947337, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/06

Report Problem", + "NAME": "H01624" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05815809586969, + 38.90536133769514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01625" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98559181125505, + 38.8834748174605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01626" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01343665674496, + 38.91921949627376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H01628" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0228856126337, + 38.97592565451223, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H01629" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02406031726679, + 38.933576812023766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H01630" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02349781538757, + 38.93212029267016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/14/08

Report Problem", + "NAME": "H01631" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00344978674075, + 38.90007968759085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01632" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02277224553906, + 38.9734544217227, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H01633" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03227323060923, + 38.97858822714868, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01634" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00350796264058, + 38.90040712165783, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01635" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98818090200267, + 38.88161270536892, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/19/06

Report Problem", + "NAME": "H01636" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04464049479556, + 38.91516828052712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01637" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99257925214359, + 38.90231029622669, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H01638" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03866248906964, + 38.91561490064216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01639" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0147127635705, + 38.97347072110241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01640" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99030703075263, + 38.90145175964172, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H01641" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98372060626748, + 38.87984535346194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 01/03/07

Report Problem", + "NAME": "H01642" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9890179385195, + 38.866823635069444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01643" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00209494120463, + 38.90266791057591, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H01644" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00050923388295, + 38.90551495478924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/15/07

Report Problem", + "NAME": "H01645" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99358700004944, + 38.86190175083163, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H01646" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03669851533915, + 38.91329864410307, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01647" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03141139200164, + 38.93764673802807, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H01648" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04181785151341, + 38.91255484420992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H01649" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.040616215472, + 38.90720560938269, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01650" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0092781651967, + 38.91412868891223, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01651" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9964824502806, + 38.90662949691347, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01652" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03238185715058, + 38.92960817506793, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H01653" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9838104851095, + 38.89606749956819, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01654" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98582869823747, + 38.908877299695675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H01655" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98850646594799, + 38.86730598621084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H01656" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99165354597353, + 38.87558253505564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/10/06

Report Problem", + "NAME": "H01657" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00047229707197, + 38.930250187145035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/21/07

Report Problem", + "NAME": "H01658" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04086712878322, + 38.92034553244864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H01659" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0590875411829, + 38.93639204093927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H01660" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01080171742977, + 38.874587995820605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H01661" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98930821390543, + 38.893488712372125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01662" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01272994122674, + 38.97376000089939, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01663" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99515073499892, + 38.88380247473194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 02/12/07

Report Problem", + "NAME": "H01664" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98839456341526, + 38.90119883785697, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H01665" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0504940339849, + 38.91115494400008, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01666" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99224758580772, + 38.86285853465458, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01667" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05590409721444, + 38.908614911314615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01668" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98085018080076, + 38.86714016373777, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H01669" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98544401354457, + 38.89107440268359, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 04/27/06

Report Problem", + "NAME": "H01670" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06392701985482, + 38.96852383870974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H01671" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02314908783872, + 38.91562444483965, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H01672" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9904199285925, + 38.89896275958963, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01673" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93532007028486, + 38.90367575230827, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01674" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99851865020891, + 38.8814059749635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/05/06

Report Problem", + "NAME": "H01675" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01463410352588, + 38.91922930665154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/01/07

Report Problem", + "NAME": "H01676" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03104693028325, + 38.959230479260086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01677" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02880711752908, + 38.90260248137471, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01678" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02768141129852, + 38.93978066482626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H01679" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99032460467033, + 38.88356892955696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/21/06

Report Problem", + "NAME": "H01680" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03311777717754, + 38.91913055527483, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01681" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98879754423108, + 38.9362495686159, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01682" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04463791145075, + 38.918538893049295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H01683" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02338545407048, + 38.94424293111497, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H01684" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04027301163535, + 38.91821549441331, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01685" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05158199029682, + 38.916938370608754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01686" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0242392252846, + 38.95742266262686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/10/07

Report Problem", + "NAME": "H01687" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02758828649648, + 38.954133228144876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/08/07

Report Problem", + "NAME": "H01688" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00217981715464, + 38.89896795153512, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01689" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98356323265779, + 38.89080491992413, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 04/27/06

Report Problem", + "NAME": "H01690" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98591239779688, + 38.891626430115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/01/06

Report Problem", + "NAME": "H01691" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97641848751596, + 38.932187955212115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01692" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98555804638181, + 38.88880316235764, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/28/06

Report Problem", + "NAME": "H01741" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06145874622113, + 38.90919606953275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01448" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0252835385952, + 38.90186447681956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01449" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9409504710135, + 38.902987216402806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01450" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05588370239457, + 38.907792143714126, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01451" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00196807735378, + 38.844064648949136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H01452" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06300048113162, + 38.95801187242621, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01453" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93541109231491, + 38.90916086104742, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H01454" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9330719310103, + 38.91097668076586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01455" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0465688244757, + 38.908461052730786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/21/07

Report Problem", + "NAME": "H01456" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03215344820053, + 38.91922815957348, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H01457" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93760682389885, + 38.90378677173962, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01458" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.990191068769, + 38.87770765500455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/13/06

Report Problem", + "NAME": "H01459" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93861266755245, + 38.91045656364813, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01460" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98559254732817, + 38.882683439895004, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H01461" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99030880157443, + 38.90233385795482, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H01462" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0098343368453, + 38.87247878238873, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01463" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01744729481824, + 38.91594407805688, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01464" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01775579797457, + 38.90259492762752, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H01465" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06156712025975, + 38.94980910219059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01466" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0618047284287, + 38.947928408616704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01467" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99487732893802, + 38.89001247044877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H01468" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99730583940168, + 38.88363997902216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01469" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06630842048075, + 38.93260052726264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H01470" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02025374635168, + 38.93653103105635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01471" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03209738207916, + 38.910310085602454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01472" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99142988978875, + 38.8877155828476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H01473" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03305131392158, + 38.90853778835916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H01474" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9973608676341, + 38.889729861158415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/04/07

Report Problem", + "NAME": "H01475" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05323701371535, + 38.90711424031508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01477" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9819868861212, + 38.88637716933428, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H01478" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03436773063687, + 38.90730305792679, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01479" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03216384956264, + 38.90728829916347, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01480" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0173588432685, + 38.91680087367197, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/06/08

Report Problem", + "NAME": "H01481" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00367207498614, + 38.885997707352466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/05/07

Report Problem", + "NAME": "H01483" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00211182581772, + 38.886149960591936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H01484" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01733688731552, + 38.911910639121416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01485" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99391849974833, + 38.89896348055616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/08/07

Report Problem", + "NAME": "H01486" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0188553812113, + 38.91356942449031, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01487" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99831198273517, + 38.88277408488938, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H01488" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0007499462206, + 38.88545250336951, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/10/07

Report Problem", + "NAME": "H01489" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99601579046934, + 38.88972773308024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H01490" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99944503019721, + 38.887738750187445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01491" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07104221290884, + 38.97120115281191, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/30/06

Report Problem", + "NAME": "H01492" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99851547849545, + 38.88539358152677, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/18/07

Report Problem", + "NAME": "H01493" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06603503188138, + 38.90672324051473, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01494" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05245682870127, + 38.90346932779068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01495" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03545194335523, + 38.92472739919133, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H01496" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99632769954046, + 38.884332129561514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H01497" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06257831798364, + 38.91180381409284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H01498" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99514376059052, + 38.88873445459372, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H01499" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9950419148437, + 38.88805257022504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/23/06

Report Problem", + "NAME": "H01500" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04565143323003, + 38.920735443366056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H01501" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00343926714955, + 38.89469758757336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01502" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99391865698045, + 38.888735045837784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H01503" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05335318705667, + 38.90451426023783, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/25/07

Report Problem", + "NAME": "H01504" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99393597916979, + 38.88753745502592, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H01505" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99270997605161, + 38.888646109020634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H01506" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06870236760626, + 38.93803800620132, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/07/07

Report Problem", + "NAME": "H01507" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99270820337266, + 38.88772058821946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H01508" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00073257337448, + 38.89297914550857, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01509" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0355609222617, + 38.90245711772961, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H01510" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98289219661815, + 38.93299818097305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01511" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9685425609785, + 38.897471573424184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/07/06

Report Problem", + "NAME": "H01512" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9996748344389, + 38.88132912433841, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H01513" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02719927989881, + 38.904206272588084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01514" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0189908436443, + 38.908689170103735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01515" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06407254292458, + 38.912052391189455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/28/07

Report Problem", + "NAME": "H01516" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02505430258562, + 38.94504972759686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H01517" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06039152533941, + 38.9093334808122, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01850" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97785622069829, + 38.93021024643721, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H01851" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0332139179715, + 38.91817451912744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01852" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05717167514447, + 38.90613091251988, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01853" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98089132422619, + 38.924568046609465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/26/07

Report Problem", + "NAME": "H01854" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0622164792347, + 38.907678698923924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01855" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0602993754585, + 38.90769162211388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01856" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01232262481422, + 38.91265285997377, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01857" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02535176137408, + 38.9530433016341, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H01858" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0058108588899, + 38.88993176824665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01859" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99145585127567, + 38.9003830708077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01860" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98088103413968, + 38.92350539658201, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/04/07

Report Problem", + "NAME": "H01861" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0269717159178, + 38.97150832641371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H01862" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02580375634906, + 38.97151591365617, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01863" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98940855269164, + 38.9397200983521, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01864" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06477350896394, + 38.90984603268693, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/05/08

Report Problem", + "NAME": "H01865" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06124231051363, + 38.91292842955008, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01866" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04159549952469, + 38.91341931866978, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H01867" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98379593497012, + 38.88871910825257, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H01868" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00513059425955, + 38.88189960337566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 01/11/07

Report Problem", + "NAME": "H01869" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00358762274463, + 38.88206614496601, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/05/06

Report Problem", + "NAME": "H01870" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0318245077414, + 38.89664690243558, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01871" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05824451324324, + 38.90945039111792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H01872" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99145166591357, + 38.9023121469502, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H01873" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0028388564693, + 38.87360474365964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01874" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98605448122952, + 38.92681269430606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H01875" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99270873681986, + 38.88994461223659, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01876" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04145694480034, + 38.92332740407147, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H01877" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03113418085866, + 38.97487143513596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01878" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99487569648804, + 38.88032330683026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H01879" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.029472874992, + 38.89725265625571, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01881" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97004062530067, + 38.9331694445616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H01882" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0297324801001, + 38.89667228068078, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01883" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05002459084795, + 38.90171992692369, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H01884" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03504160592487, + 38.89825747880135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H01885" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06879026425989, + 38.94794144234897, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01886" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.072346848523, + 38.94799181370046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01887" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03892445470994, + 38.92981087502163, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H01888" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06613676820224, + 38.90769519284809, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01889" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00617798867312, + 38.95672016053897, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H01890" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04484937503277, + 38.89844994893373, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/22/07

Report Problem", + "NAME": "H01891" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06396843394204, + 38.965952295138834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01892" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99148225497008, + 38.924293157451906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H01893" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99982505781792, + 38.92191004630571, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01894" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99868239497337, + 38.92225162557698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01895" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99777707152788, + 38.92179213337697, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01896" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9992888319281, + 38.92193248400389, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01897" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99879730365795, + 38.92190006803476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01898" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99911010773754, + 38.921433827069045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01899" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99873029528702, + 38.92175795202872, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01900" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99960481882547, + 38.92089776246244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01901" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03435818337549, + 38.947272183671885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H01902" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98837569630015, + 38.89720733984544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H01903" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04861245289136, + 38.90969894882585, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01904" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02679224709911, + 38.97368104572896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H01905" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04064247054069, + 38.8944022641965, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H01906" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01020448988793, + 38.90462482756334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H01907" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04338169655762, + 38.89327761107908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H01908" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0742103828715, + 38.96211350255284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01909" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0260827944744, + 38.943631436496986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H01910" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99132732892684, + 38.90137541294538, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01911" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02458611557088, + 38.97238652469149, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01912" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01797587275935, + 38.86720615679607, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H01913" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03134659772964, + 38.93873443502276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H01914" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94761786452838, + 38.89678359993288, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01916" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02974706121714, + 38.9063171279233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01917" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9868983556459, + 38.9025585089257, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/17/07

Report Problem", + "NAME": "H01918" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04354314655554, + 38.89843568741387, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01919" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99264416900115, + 38.934512551328595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01920" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06627516633826, + 38.96853111631547, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H01921" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04659164435708, + 38.898457707894785, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01922" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93400654713926, + 38.89749714758739, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H01923" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97689820662369, + 38.87277938652282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H01924" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93400044348896, + 38.896306868765635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H01925" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97776244312972, + 38.873377775189276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H01926" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02712039889688, + 38.935437194072975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01927" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02806366613426, + 38.976607809693945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H01928" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01798537138136, + 38.86621513105002, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H01929" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01797769847835, + 38.86800404935802, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H01930" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01798120182136, + 38.8689658405201, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H01931" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01705934825965, + 38.8714278229092, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H01933" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01610090793427, + 38.87152401559676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H01934" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06250962803557, + 38.970866729736045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01936" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01550779831753, + 38.941036318439814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 05/09/07

Report Problem", + "NAME": "H01937" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03872020073588, + 38.920203184302636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H01938" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09692567097349, + 38.92029652794114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01939" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04167670249105, + 38.89200103397282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H01940" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04481085480157, + 38.89280739314633, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H01941" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02379837562194, + 38.91415217239058, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H01942" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03804254767822, + 38.89840065586897, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01943" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00196548993681, + 38.8981980287612, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01944" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02988570926301, + 38.937625680312635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H01945" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04484579513982, + 38.89200357173687, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/18/08

Report Problem", + "NAME": "H01946" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06171684803618, + 38.96983451822597, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H01947" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03446375381101, + 38.94816742238717, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H01948" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02415678949772, + 38.90223849892884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01949" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07724705645342, + 38.959051241103374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01950" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03558397993368, + 38.9593324391487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01951" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99633103943574, + 38.890881716115125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H01952" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06820555267512, + 38.95237791076059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, Metropolitan

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01953" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02989213617779, + 38.93765873010822, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/19/07

Report Problem", + "NAME": "H01955" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01146173191339, + 38.95663922808497, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H01956" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92976861602617, + 38.90857786446685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H01742" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97960349688758, + 38.865849677893586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H01743" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98214038896349, + 38.86634844781735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01744" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0382865914365, + 38.91413987353095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H01745" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00919102208019, + 38.881592853048325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01746" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98990188132304, + 38.86484672875232, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01747" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0593790325117, + 38.91132735701251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01748" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97629651682679, + 38.93126630874895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H01693" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99126011897111, + 38.923481410417075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H01694" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97945729296129, + 38.92899429989975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01695" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99931490267937, + 38.89098449420409, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01696" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05905675494256, + 38.90688313596674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01697" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9853380767704, + 38.89738515648231, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01698" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0591719773263, + 38.90921613151359, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01699" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02815495071376, + 38.91033090245102, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H01700" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.068710738805, + 38.93898066549607, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/28/08

Report Problem", + "NAME": "H01701" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93143174836734, + 38.90995544470618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H01702" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01933902264206, + 38.93674221436258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01703" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04504845363036, + 38.91117769143819, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01704" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93234362551028, + 38.909254271228384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H01705" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01482342007958, + 38.906504150169596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01706" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97567735794388, + 38.91360690695947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01707" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98128214317224, + 38.90486482825957, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01708" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02614179807715, + 38.96499315949469, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01709" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01329290025585, + 38.916334541161135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01710" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00882098852348, + 38.91632729822233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/26/07

Report Problem", + "NAME": "H01711" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03193287205347, + 38.92279570573727, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01712" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02081041072563, + 38.91414449111245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01713" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0220454239246, + 38.92240978462876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H01714" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01898916065501, + 38.9112455127532, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01715" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02984784911241, + 38.92381123336725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/22/06

Report Problem", + "NAME": "H01716" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01623699284768, + 38.89817688230593, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01717" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99360088025216, + 38.890988428750404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H01718" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98749322896427, + 38.86299081617016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01719" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99381692741477, + 38.89003968748024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H01720" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02315645056777, + 38.9207572090482, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H01721" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04157670360637, + 38.897237390722054, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H01722" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98752701892724, + 38.88622558765701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/09/06

Report Problem", + "NAME": "H01723" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98867660373392, + 38.86199177735186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H01724" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02197854895691, + 38.918923683630304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/04/06

Report Problem", + "NAME": "H01725" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03178121451911, + 38.90969863167442, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/08/08

Report Problem", + "NAME": "H01726" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99033929943232, + 38.86254535888564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/29/07

Report Problem", + "NAME": "H01727" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02187457445666, + 38.94423363878941, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H01728" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03523981175577, + 38.93458136547237, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H01729" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02956965114083, + 38.9286806049776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/14/07

Report Problem", + "NAME": "H01730" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02849317835151, + 38.92868458380273, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01731" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00064273768592, + 38.90006509817616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01732" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98737467269434, + 38.866336492279935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H01733" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0310766098877, + 38.92867694396942, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H01734" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98759348209485, + 38.86551920954452, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01735" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98546542020551, + 38.866002292385495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H01736" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02987316343312, + 38.924805799357166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/21/08

Report Problem", + "NAME": "H01737" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0298257070451, + 38.97873317065002, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H01738" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02985042211048, + 38.925798008254326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H01739" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98327833153981, + 38.866343508550926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H01740" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99102237985707, + 38.86445555784137, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01750" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97235675444279, + 38.92744092013259, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H01751" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99030866818313, + 38.88031989124227, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 04/02/07

Report Problem", + "NAME": "H01752" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01435948004561, + 38.94119315533904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01753" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00334741892169, + 38.914139269820616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H01754" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05581931667132, + 38.9335525280332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/27/06

Report Problem", + "NAME": "H01755" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05460063702039, + 38.900760433534494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H01756" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99271094748451, + 38.88139402798187, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/21/06

Report Problem", + "NAME": "H01757" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01243189517508, + 38.94340228048384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01758" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02208569774297, + 38.93225498997437, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H01759" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99042888376694, + 38.8860902583415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H01760" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02415949102253, + 38.90286254313056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H01761" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98579318734639, + 38.884158623541, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H01762" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02415720017746, + 38.9342250384963, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H01763" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98449555039457, + 38.88066005157696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/19/06

Report Problem", + "NAME": "H01764" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03590754984333, + 38.95301969099706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H01765" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08079387968955, + 38.95954337955969, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01766" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.988235093205, + 38.8842013695676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H01767" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02327670558091, + 38.93066181097579, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/05/06

Report Problem", + "NAME": "H01768" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01478458201592, + 38.971768299917585, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H01769" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02372150034742, + 38.92402762104677, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H01770" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01810874646442, + 38.963901213169635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01771" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02940662632399, + 38.92046683432597, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/28/06

Report Problem", + "NAME": "H01772" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0251099712243, + 38.931977959509766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01773" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.001971040758, + 38.88213993509908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H01774" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98837083938878, + 38.89624021944037, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01775" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02309552131985, + 38.91264953366015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01776" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04146652309007, + 38.91786544568448, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H01777" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05748839146487, + 38.905041332156635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H01778" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05696950857094, + 38.905045405866815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/21/07

Report Problem", + "NAME": "H01779" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03419582418493, + 38.92352850494571, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01780" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03329955797464, + 38.91691137369946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01781" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04484088422257, + 38.9231799585808, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H01782" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06625495525927, + 38.966824452628245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H01783" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02839211462425, + 38.933633619282936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H01784" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03639679107833, + 38.92098413310898, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/30/07

Report Problem", + "NAME": "H01785" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04012784887098, + 38.91633496516215, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H01786" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04187520368419, + 38.90650767554856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01787" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07505225108544, + 38.923931285599444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01788" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07045504315604, + 38.90873804235577, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01789" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02818228393636, + 38.903200653366774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H01790" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00641922111252, + 38.95771883045707, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01791" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04511345157735, + 38.910307982999875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01792" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03019786070082, + 38.97512259590143, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01793" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99776044340963, + 38.84429362970075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01794" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06399174013431, + 38.966823578102954, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H01795" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02410257265424, + 38.95622049318288, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H01796" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06115852518168, + 38.93590083404151, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H01797" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94444218399751, + 38.89911008306193, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H01972" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01086682128313, + 38.89489738875106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H01973" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03929272849666, + 38.897855191099325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H01974" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03806984520564, + 38.89710340669015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01975" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03953962276367, + 38.89555083118579, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H01976" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04032859305796, + 38.89537942953278, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H01977" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01624339659615, + 38.89744278998546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01978" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01737935850149, + 38.89726565722163, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H01979" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01033217717854, + 38.95527463542399, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H01980" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0241099502249, + 38.968685535140374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H01981" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07406856195156, + 38.93330919886083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H01982" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0171408395714, + 38.941123497818865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H01983" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01395599170118, + 38.943318772806364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H01984" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03800659703973, + 38.921929710850165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H01985" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98208976511503, + 38.881793602285335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H01986" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01894711050141, + 38.93997732834983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H01987" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04002101013288, + 38.916920957774074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H01798" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06720276007067, + 38.95064992078573, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01799" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04103208040618, + 38.912558464883155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01800" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03181558436431, + 38.91396265687283, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/21/08

Report Problem", + "NAME": "H01801" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.065320343352, + 38.90601839653121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01803" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07149826210423, + 38.91879901133891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01804" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07217549581509, + 38.91982867047362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01805" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00478879383267, + 38.886087480461576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/20/06

Report Problem", + "NAME": "H01806" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0708132847522, + 38.931864743574515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/19/07

Report Problem", + "NAME": "H01807" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03131578962383, + 38.90572644589639, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H01808" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03097885825605, + 38.931996612778406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H01809" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03309565150168, + 38.91414229688326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01810" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03127004213245, + 38.92971084826277, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H01811" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00670710879972, + 38.91189781493135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H01812" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07905049903106, + 38.96492906715615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H01813" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01196553285081, + 38.92027865697532, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H01814" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02279259670462, + 38.92736326116371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/05/06

Report Problem", + "NAME": "H01815" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99967679539412, + 38.919125176433404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/01/07

Report Problem", + "NAME": "H01816" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99958477011847, + 38.878501066031305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H01817" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06124336428864, + 38.905065052907304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01818" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02316957659161, + 38.93464453885302, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/15/07

Report Problem", + "NAME": "H01819" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99270839765217, + 38.89213538543092, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H01820" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0339084088944, + 38.92269694049385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/21/06

Report Problem", + "NAME": "H01821" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0261409505151, + 38.91923833428273, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H01822" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06923906129792, + 38.954298181932046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01823" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99858876829653, + 38.90244276602723, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H01824" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98350380920732, + 38.88972234819578, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/27/06

Report Problem", + "NAME": "H01825" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05820771527544, + 38.907775172336834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/07/07

Report Problem", + "NAME": "H01826" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02793926322623, + 38.957340681573775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H01827" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0258570564964, + 38.95525867525521, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H01828" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99018014684331, + 38.89049600077135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/16/06

Report Problem", + "NAME": "H01829" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.065264301912, + 38.95336004996607, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01830" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0670459301452, + 38.953343781818, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H01831" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06861667535924, + 38.95335077074285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H01832" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02378484169348, + 38.90970057814971, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H01833" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99915785875653, + 38.8434462057367, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H01834" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01743864110124, + 38.89988754984979, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H01835" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06033812666197, + 38.93823540071663, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H01836" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98844561612165, + 38.89896154504042, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H01837" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03151968812, + 38.935978678414585, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H01838" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03258178715464, + 38.936183163829355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H01839" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02574074476824, + 38.97370788321005, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H01840" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01222780408037, + 38.90648857794735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01841" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01498364604944, + 38.90729186466856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01842" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04160393396809, + 38.91028632308658, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H01843" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99851452205687, + 38.90033090913208, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H01844" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03829260606062, + 38.91340171943609, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01845" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99852832272505, + 38.90361785996193, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H01846" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99827666184842, + 38.9050159706863, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/03/08

Report Problem", + "NAME": "H01847" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99125600076194, + 38.92198715484397, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H01848" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99031378513881, + 38.92166728509103, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H01849" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03631031632304, + 38.91636513053023, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/17/07

Report Problem", + "NAME": "H02201" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03631506896545, + 38.91478377912791, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02202" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05024781612903, + 38.896187435987926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H02203" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05029103184319, + 38.89837693634458, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02204" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05274064035815, + 38.916344339398904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02205" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04896351569671, + 38.89741147045287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H02206" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01710996095403, + 38.94304666379311, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02207" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05090695816087, + 38.902900694397125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H02208" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.031307803453, + 38.9551947712948, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H02209" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02961568808855, + 38.95502686569453, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H02210" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02711253603198, + 38.91930960298251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H02211" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03640918755977, + 38.92035176283157, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H02021" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00762120200532, + 38.92136660505803, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02022" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93278514187459, + 38.90071614801195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/12/07

Report Problem", + "NAME": "H02023" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0639088091822, + 38.967724168792934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02024" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9865231920158, + 38.892793761859885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H02025" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97029850248663, + 38.924562528435814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/21/07

Report Problem", + "NAME": "H02026" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0363957525363, + 38.924100850732934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/28/06

Report Problem", + "NAME": "H02028" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03890313068506, + 38.923216596967656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H02029" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02371843552692, + 38.94615620532793, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H02030" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0251190942851, + 38.94625229235325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H02031" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95976169469112, + 38.88267940593603, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02032" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0403209075553, + 38.92316371498957, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/16/06

Report Problem", + "NAME": "H02033" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02791881707249, + 38.961194797764165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02034" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97799390592007, + 38.932179992831124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H02035" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97814440691053, + 38.931196133866045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H02036" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07477676683689, + 38.94714093883515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H02037" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03472560380943, + 38.91561818182411, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H02038" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06648448520178, + 38.9381858087151, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H02039" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01375746415471, + 38.9661773705575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02040" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01860847798358, + 38.94409470203794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02041" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01604122221272, + 38.96618846599088, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02042" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02740139650898, + 38.95070423788856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H02043" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0073339718771, + 38.91632205907361, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02044" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0717352739266, + 38.94623056694789, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H02045" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03249570494033, + 38.94088218462271, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H02046" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02799132687733, + 38.90385847120674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H02047" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02440035145413, + 38.97371624193505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H02048" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0272025847413, + 38.949028186655774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H02049" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02805792591415, + 38.958395385388215, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02050" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04283632585633, + 38.91971254175975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H02051" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02165365747527, + 38.97824966013551, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H02052" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03652476029528, + 38.943888141926635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/11/07

Report Problem", + "NAME": "H02053" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07449684718694, + 38.94964388803114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H02054" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99959130326096, + 38.84050973345047, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H02055" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99168475000235, + 38.89727239238158, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02056" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98358277442742, + 38.89213999947586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/01/06

Report Problem", + "NAME": "H02057" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06581360425771, + 38.903391094750354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H02058" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03767408103673, + 38.92684424392952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H02059" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00071474302833, + 38.89087894292024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H02060" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0893077075887, + 38.91397769329134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02061" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04303475872973, + 38.933338780457895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H02062" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02841464778555, + 38.95072893090878, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H02063" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00702920739757, + 38.88971816676756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02068" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11068097615896, + 38.92982224140037, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy, K81A

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02070" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93546440677869, + 38.89761458434923, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H02071" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01279298893496, + 38.970053987944816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02072" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01886411973993, + 38.97594601026155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02073" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01510427761703, + 38.91121076684343, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02074" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0258433151407, + 38.89743849331662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H02075" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96363594637835, + 38.92982781557876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02076" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03124248541948, + 38.9758425654708, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02077" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03313102750121, + 38.97584890997978, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02078" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0306355303094, + 38.89744309121334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H02079" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01443393948755, + 38.915792554597964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02080" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98624009700451, + 38.90332648549664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02081" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04355951281299, + 38.9004501398706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02082" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02380855600049, + 38.912663830912344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02083" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02871534096461, + 38.90066186080205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02084" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03075254648903, + 38.918162103708404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02085" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03181528597833, + 38.907917402405666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02086" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03361447407345, + 38.900705208311415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02087" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0561510368247, + 38.92123790355169, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/08/07

Report Problem", + "NAME": "H02088" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03393058018769, + 38.898790354085925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02089" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03211219285566, + 38.89880036289175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02090" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0122386304132, + 38.89661328362694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H02091" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01325012836391, + 38.90147950741581, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H02092" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04117485780813, + 38.9252185482281, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/16/06

Report Problem", + "NAME": "H02093" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04646969315603, + 38.91191167494785, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02094" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02413662584776, + 38.95106142388892, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H02095" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05700782847092, + 38.90857645285621, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02096" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05590996045036, + 38.90691662780565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02097" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0272324580154, + 38.91117676112862, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02098" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05818038207765, + 38.90616766409246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02099" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0610946029378, + 38.90402570196853, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/31/07

Report Problem", + "NAME": "H02100" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04763197885745, + 38.9072899624411, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darily

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02101" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04865085994038, + 38.90638797807777, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H02102" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99031178879729, + 38.87855697638659, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/10/08

Report Problem", + "NAME": "H02103" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06533689590646, + 38.933402777603625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H02104" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01396964136951, + 38.91302011575282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02105" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98837618739869, + 38.894900856166906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H02106" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99271483725506, + 38.89488319058328, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H02107" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02436776089716, + 38.93746773926977, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H02108" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99151756995002, + 38.93958044371077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H02109" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00668310530443, + 38.9126596604995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02110" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01509588956083, + 38.913199232576574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02111" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07302537132628, + 38.92356707506844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02112" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0575723541407, + 38.92769173627025, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/09/07

Report Problem", + "NAME": "H02113" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02582720764399, + 38.95639859664712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H02114" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03058637385794, + 38.91257550297117, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H02115" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0378605303757, + 38.93377852776354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H02116" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03076176729697, + 38.91181686469185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/10/07

Report Problem", + "NAME": "H02117" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0274564324348, + 38.96617803724361, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02118" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03073133751631, + 38.91553218098514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H02119" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02687525325523, + 38.97239092150284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02120" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0320867969527, + 38.91492174522641, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02121" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03323907281033, + 38.914796720750026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02122" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02670878225192, + 38.97480224732966, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H02123" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08903221648488, + 38.91006626473149, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02124" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03640515244933, + 38.91764286075749, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02125" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00218748943851, + 38.921348672319816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H02126" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98544126487761, + 38.89624057570366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/03/08

Report Problem", + "NAME": "H02127" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03400089118982, + 38.93422699451916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H02128" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02960748865249, + 38.953951911276405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H02129" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03657486154742, + 38.94969582787546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H02130" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04364077262919, + 38.92669473808517, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H02131" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02955678141574, + 38.98043313542413, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02132" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04288033549176, + 38.92887020300115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H02133" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04400623305133, + 38.92975164408644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H02134" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03865173289707, + 38.943000808381264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H02135" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01703578605907, + 38.870428821330094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H02136" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00604478727104, + 38.906490529810775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02137" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0182049262469, + 38.87078014386674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H02138" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01878861433661, + 38.906500084559404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02139" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01878598317823, + 38.91191873882881, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02140" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0387175452137, + 38.944941549684245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H02141" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04162614917688, + 38.8967882521077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/06/07

Report Problem", + "NAME": "H02142" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03635510774349, + 38.94836095988495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H02143" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99213385238693, + 38.93622897754184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02144" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04245885027528, + 38.897426555352695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02145" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07012749042492, + 38.93806974288582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/27/08

Report Problem", + "NAME": "H02146" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03771620511618, + 38.958473355730874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02147" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05628748429913, + 38.92606582966359, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/09/07

Report Problem", + "NAME": "H02148" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0389526346283, + 38.94406995606748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H02149" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03420260089324, + 38.93669585850738, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H02150" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08847030359233, + 38.954752361988504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/14/07

Report Problem", + "NAME": "H02151" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08508726950372, + 38.95475162102491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H02152" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04324745320626, + 38.9118196576921, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02153" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06890400781782, + 38.905977755219396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/02/07

Report Problem", + "NAME": "H02154" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06998948725547, + 38.90595148124361, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02155" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07139584191576, + 38.905910290901204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H02156" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07149471587194, + 38.90770461271906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H02157" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07197006315903, + 38.90577348908487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02158" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07039851059882, + 38.9077772370552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/18/07

Report Problem", + "NAME": "H02159" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98815055134135, + 38.8784488745766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/20/06

Report Problem", + "NAME": "H02160" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02989682974575, + 38.9451108456685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H02161" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06540582748619, + 38.90776099591915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H02162" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06530586633363, + 38.90671493028031, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H02163" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06330966725282, + 38.90918708185487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H02164" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06799228625695, + 38.90878857894755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/22/07

Report Problem", + "NAME": "H02165" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09994051170968, + 38.91960020280701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H02166" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98716697453132, + 38.89895685334767, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H02167" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06798400027944, + 38.91066751737259, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H02168" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02797789889527, + 38.97943563807483, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02169" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02613887142148, + 38.96380903479555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H02170" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01900918370542, + 38.896259979889884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H02171" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01536407089658, + 38.90569403159171, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02172" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08498011136442, + 38.94973727008438, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/07/07

Report Problem", + "NAME": "H02173" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0383050233257, + 38.91969029693658, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H02174" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07211013543095, + 38.92366007779364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H02175" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07228108336108, + 38.949722452911836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H02176" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07206835855597, + 38.92477052330977, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02177" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0686010738783, + 38.96592174351495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/20/08

Report Problem", + "NAME": "H02179" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04887104317531, + 38.90190913123874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/23/07

Report Problem", + "NAME": "H02212" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03476597403088, + 38.93530075715645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H02213" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01025778048266, + 38.911065015407424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02214" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07129942389474, + 38.971976200252676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02215" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99837980466911, + 38.897210708559165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02216" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04726285980533, + 38.90794181221872, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02217" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0472969765816, + 38.91265530573976, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02218" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98942147352926, + 38.9036356051964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H01957" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0631571534827, + 38.94318530156407, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/08/07

Report Problem", + "NAME": "H01958" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98902356187968, + 38.904507297697904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/02/07

Report Problem", + "NAME": "H01959" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02757047573542, + 38.9649962454915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/08/08

Report Problem", + "NAME": "H01960" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9945771025899, + 38.92283463384243, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H01961" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0385309248215, + 38.918007593046426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H01962" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0411883523277, + 38.91192440297233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/03/07

Report Problem", + "NAME": "H01963" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00043045788391, + 38.919257958827444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H01964" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98862964483567, + 38.93074143457421, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01965" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.040636396296, + 38.90029235783908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H01966" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02157512765002, + 38.974838015796365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H01967" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02803919716007, + 38.91128538206297, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H01968" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02253152430067, + 38.957483449624014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H01969" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06653554269433, + 38.93633869104572, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H01970" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06869395979669, + 38.93639869889583, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/06/08

Report Problem", + "NAME": "H01971" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01152851233472, + 38.910429664761125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H01988" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94089019499285, + 38.911214375772396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H01989" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04138129021726, + 38.942992865530066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H01990" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08025761988256, + 38.908573497441154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H01991" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9942430741517, + 38.86293060932371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H01992" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05135984983349, + 38.898448961626094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H01993" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02982220409694, + 38.97802934999025, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H01994" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03181370793966, + 38.94966703374758, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H01995" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07475851651334, + 38.946326304443325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H01996" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07711304159017, + 38.94716766205143, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H01997" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.967520986969, + 38.930954620042776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H01998" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02248486873098, + 38.92684122591908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H01999" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.036271452233, + 38.919143671935224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02000" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96646320438947, + 38.92463621475183, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02001" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01616873388167, + 38.93900814710454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H02002" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03660342018057, + 38.91569397232699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02003" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02515982000193, + 38.96996254732763, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H02004" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0375566625569, + 38.920811806185306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H02005" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02256408737978, + 38.96996118526378, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H02006" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03875551766804, + 38.921490318110834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H02007" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11180658507733, + 38.93407922806082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H02008" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98280708620482, + 38.93201242573101, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02009" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03543304230105, + 38.947240234753686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H02010" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07891400537676, + 38.959601874909225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02012" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02950880433558, + 38.95295467583174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H02013" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0690084666058, + 38.966841137811286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H02014" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03283045891598, + 38.93855793352463, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H02015" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99032363698532, + 38.89750333405455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H02016" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0295067617474, + 38.957328846992304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02017" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02961941889164, + 38.95634217050676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02018" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02016868063262, + 38.94427192448788, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H02019" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0318281675755, + 38.90306707799152, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 02/04/08

Report Problem", + "NAME": "H02020" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07208174668037, + 38.92742798694648, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H02180" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0145632670662, + 38.910421903042455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02181" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00344645438211, + 38.92034688929146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H02182" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0021272623016, + 38.9202774215236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/25/07

Report Problem", + "NAME": "H02183" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07094136439243, + 38.924772230811264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02184" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07094319360175, + 38.92610084869127, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H02185" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06627664070031, + 38.91269273578324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H02186" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06570383789055, + 38.91172554545512, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02187" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10873919584331, + 38.92874085915821, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02188" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9962337831072, + 38.89622438738672, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/01/07

Report Problem", + "NAME": "H02189" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96893566778297, + 38.92662307882042, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02190" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06629309703835, + 38.9276310651576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/12/07

Report Problem", + "NAME": "H02191" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04997279803068, + 38.90534685658149, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02192" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00196887277293, + 38.900473423214414, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/28/07

Report Problem", + "NAME": "H02193" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0235377836542, + 38.94715885445253, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H02194" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01430750265538, + 38.9444052015688, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02195" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0692826441224, + 38.91447182354517, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02196" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07494620895606, + 38.95707490232092, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02197" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06945067919192, + 38.915561777553435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H02198" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02797705271975, + 38.98042565079019, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02199" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02601972222021, + 38.9584925694157, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02200" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06624618189082, + 38.93471894654501, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H02357" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06787968304695, + 38.96857024659039, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02358" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96798934459109, + 38.93222581232258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H02359" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07286764970894, + 38.96868836065294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/26/07

Report Problem", + "NAME": "H02360" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02896394982665, + 38.915627319032964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02361" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08116003122717, + 38.96212589286107, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 02/15/08

Report Problem", + "NAME": "H02362" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06580430208457, + 38.92961147680641, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/18/06

Report Problem", + "NAME": "H02364" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06511632318453, + 38.92910428879062, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/17/07

Report Problem", + "NAME": "H02365" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93264391094284, + 38.89984674186864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 01/11/08

Report Problem", + "NAME": "H02366" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96237761379567, + 38.93415531387043, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02367" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96512484852082, + 38.93416388599946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H02368" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03878279699964, + 38.950510275064076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 02/06/08

Report Problem", + "NAME": "H02369" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03762467602706, + 38.95152121964144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 02/26/08

Report Problem", + "NAME": "H02370" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05525993258135, + 38.91691035781633, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H02371" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02235032865342, + 38.9585893024244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02372" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08372579015492, + 38.954532748106296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H02373" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02324613211594, + 38.96869367333492, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02374" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99044739086317, + 38.89472569604125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Dariling

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02375" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95968505551676, + 38.875735602629504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02376" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02716475075219, + 38.90656711695723, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02377" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06020846411761, + 38.9238749078651, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/10/07

Report Problem", + "NAME": "H02378" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99228035134483, + 38.92659551340002, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H02379" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05526351497318, + 38.94376505555505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/22/06

Report Problem", + "NAME": "H02380" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05845632205478, + 38.942097365523594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H02381" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0618067352162, + 38.92480334481349, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/16/07

Report Problem", + "NAME": "H02382" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05639066405435, + 38.94201891814282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H02383" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06274865251294, + 38.92546017090525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/16/07

Report Problem", + "NAME": "H02384" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05524760081336, + 38.94377088243079, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H02385" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02557271942077, + 38.94907192939675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H02386" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07593972509883, + 38.944680522088724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02387" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05613018236808, + 38.931691920728454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/02/07

Report Problem", + "NAME": "H02388" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0514492669259, + 38.92548648280563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/02/07

Report Problem", + "NAME": "H02389" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05214180884387, + 38.92667391344616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/11/06

Report Problem", + "NAME": "H02390" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05833191858744, + 38.92270059788185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/08/07

Report Problem", + "NAME": "H02391" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05798642473613, + 38.92315542887408, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 11/08/07

Report Problem", + "NAME": "H02392" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98069784544856, + 38.92547621536049, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/26/07

Report Problem", + "NAME": "H02393" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99081645338033, + 38.92863924959949, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H02394" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03345040785578, + 38.93419903844846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H02395" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00071776984767, + 38.92134527643473, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/28/07

Report Problem", + "NAME": "H02396" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9899552805556, + 38.93252538980631, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02397" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05517070320607, + 38.930112833667756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/02/07

Report Problem", + "NAME": "H02398" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05406379803276, + 38.92818587849188, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/04/08

Report Problem", + "NAME": "H02399" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03683464682743, + 38.927662259256216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02400" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03788948094103, + 38.92462147121205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H02401" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06090752725551, + 38.937175828684694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H02402" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06480849052048, + 38.93541460796952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/02/07

Report Problem", + "NAME": "H02403" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06114502837157, + 38.91965176037061, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H02404" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01737612934939, + 38.9459119164944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02405" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02086631242742, + 38.94528553123113, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02406" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02106790249516, + 38.9159947567893, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H02407" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07408843066628, + 38.91450287268788, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H02408" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02105765418624, + 38.94740164121435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/14/07

Report Problem", + "NAME": "H02409" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97024663019756, + 38.93415475330891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02410" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01903270144265, + 38.900197341701514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02411" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06776526294668, + 38.954727559802464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/20/08

Report Problem", + "NAME": "H02412" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07440743585417, + 38.95838066997117, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02421" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07403691578973, + 38.91347333331429, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02422" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04887270704579, + 38.91603208976537, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H02423" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04660436917379, + 38.91685887340063, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/31/06

Report Problem", + "NAME": "H02424" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07440050690725, + 38.959059861300844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/02/08

Report Problem", + "NAME": "H02425" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0418288310343, + 38.91189108781008, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02426" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07440789403914, + 38.960344731782484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02427" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07697852448487, + 38.95971133638402, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02428" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01452770270629, + 38.91265562440944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02429" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00046835359005, + 38.92335358393619, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02430" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08016263512539, + 38.96314549567846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H02431" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96387072005342, + 38.92241534145313, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H02432" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03870952103543, + 38.94622449397238, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H02433" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02529445304734, + 38.93602534998112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H02434" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01610001900536, + 38.967339171096654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02435" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01605837851449, + 38.968688692625655, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02436" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00335620439954, + 38.92294433372741, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/30/08

Report Problem", + "NAME": "H02437" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0196032378562, + 38.947449638029866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H02438" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03128825325167, + 38.95628426309762, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02439" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01500843801678, + 38.9196932330382, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, USP

In Service


Last Inspection Date: 09/05/06

Report Problem", + "NAME": "H02440" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05070923922946, + 38.91413585438477, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02441" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04028689659664, + 38.90470499652097, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H02442" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07018142390883, + 38.91648482138983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H02443" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99171211351711, + 38.937189422078106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02444" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06217911326354, + 38.965845809911194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02445" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08384763625851, + 38.96083239246911, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H02446" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03568650686427, + 38.934172865590604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H02447" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99443233256763, + 38.92193237155208, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02448" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0210696245563, + 38.94828630604302, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/21/07

Report Problem", + "NAME": "H02449" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06397683775366, + 38.96501788287509, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02450" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0707783822129, + 38.93721832759821, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 03/20/07

Report Problem", + "NAME": "H02451" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97222328355343, + 38.9350000923356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H02452" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07284995431041, + 38.91824666844355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02453" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0741262932378, + 38.915408997293135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02454" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04119815131878, + 38.940865037156996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - MEDALLION

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H02455" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02437582316252, + 38.964388844260206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H02456" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06629700670452, + 38.92908244645568, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/16/07

Report Problem", + "NAME": "H02457" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99228131837913, + 38.927463500539794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H02458" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03791652876262, + 38.96870165558358, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02459" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03664144386782, + 38.968808071060444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02460" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02423965294152, + 38.9250595707303, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/06/06

Report Problem", + "NAME": "H02461" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02261173782628, + 38.935495995555456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H02462" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9843739735885, + 38.92996681409685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02463" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02638157920737, + 38.97738657505648, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H02464" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03694884375898, + 38.92612746760467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H02465" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02388281636263, + 38.949868140968334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H02466" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98494300643884, + 38.90498684403374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/26/07

Report Problem", + "NAME": "H02467" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04895649402714, + 38.91340109817856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02219" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05032851993882, + 38.91244446928459, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02220" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06330655798459, + 38.92780607709113, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H02221" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0635092693931, + 38.92659036696649, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/12/07

Report Problem", + "NAME": "H02222" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04014221930245, + 38.928857302742976, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H02223" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04414980494309, + 38.92607822493934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H02224" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06317246562452, + 38.92910585111905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/17/07

Report Problem", + "NAME": "H02225" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01065584985925, + 38.914130364055296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H02226" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0694028255111, + 38.96767236555518, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/29/07

Report Problem", + "NAME": "H02227" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06418130826363, + 38.914129762646525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H02228" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0657510637312, + 38.91476324797256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02229" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03785235162083, + 38.94500788177779, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02230" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9760509669522, + 38.9331757762038, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02231" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0362845838172, + 38.93747386292969, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H02232" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03423322680514, + 38.93737431847327, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H02233" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99598866810791, + 38.8989607863988, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02234" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06007690283022, + 38.97110904727206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02235" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02410937544778, + 38.954229728164975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H02236" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99956787931444, + 38.8948964971011, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H02237" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99828669360583, + 38.92655172315786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02238" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05834402244399, + 38.97414129513569, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02239" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06099566046568, + 38.97187921742923, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02240" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02934472035942, + 38.936933106376976, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H02241" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99729640967367, + 38.896767702243615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02242" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99381980947587, + 38.89469213275735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H02243" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06502655078577, + 38.97133029950638, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02244" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05061488150095, + 38.92608851267201, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 01/02/07

Report Problem", + "NAME": "H02245" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03122529735126, + 38.94607300633347, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H02246" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0314603455025, + 38.94515329675618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H02247" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01538670093865, + 38.94309870097209, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02248" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03436989678288, + 38.94297480560888, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H02249" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02013907402738, + 38.943145020096026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/07/08

Report Problem", + "NAME": "H02250" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03758425684003, + 38.94619154854148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H02251" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9994416480855, + 38.89720594402789, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H02252" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03776603140655, + 38.92014033018421, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02253" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04182126609734, + 38.91415039073886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02254" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02332500499988, + 38.97240085388782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H02255" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08493324637763, + 38.948474559508874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02256" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06022581086036, + 38.922321287608035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 01/10/07

Report Problem", + "NAME": "H02257" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10692036614934, + 38.92817447276545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02258" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06633129672237, + 38.931366538258196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/17/07

Report Problem", + "NAME": "H02259" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06633059309861, + 38.93039940652756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 01/17/07

Report Problem", + "NAME": "H02260" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01884826427401, + 38.90147361260865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02261" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0258357780549, + 38.90167766683046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02262" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98094018829131, + 38.88024831951317, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/17/06

Report Problem", + "NAME": "H02263" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9720699562511, + 38.93207567230303, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H02264" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96621951204449, + 38.93265792905006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H02265" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02986846324326, + 38.940869084765204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H02266" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99015621764943, + 38.94170542879607, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02267" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01510655783609, + 38.9120689099893, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02268" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99828332149815, + 38.89895939230843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02269" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07314550691709, + 38.9570768534689, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02270" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03547263104721, + 38.935945746295154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H02271" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02765378008552, + 38.98297411648219, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02272" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.025554511874, + 38.94822538053987, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H02273" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03057836393977, + 38.90502680952106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02274" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02565999860138, + 38.95088985218283, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H02275" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0294930842031, + 38.90782293758968, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02276" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03156043923946, + 38.95414331253165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H02277" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02794418175219, + 38.963824003386094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02278" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06742687452288, + 38.927632524480764, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02279" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97424452074037, + 38.936089127149835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02280" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02816223051872, + 38.90975818631079, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H02281" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06470375789152, + 38.92745334801983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/12/07

Report Problem", + "NAME": "H02282" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05167636864402, + 38.91633042860268, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/30/07

Report Problem", + "NAME": "H02283" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09958301496812, + 38.947841588884124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H02284" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07454623149088, + 38.94561523595463, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H02285" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02429440018354, + 38.965994374180255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02286" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00800824107726, + 38.8832903723711, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02287" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02020227033456, + 38.93885363989355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H02288" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02135296883517, + 38.971345114051275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/10/07

Report Problem", + "NAME": "H02289" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02235773506352, + 38.971202866376885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/06/07

Report Problem", + "NAME": "H02290" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06472127670968, + 38.93021139551453, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/17/07

Report Problem", + "NAME": "H02291" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0237139993211, + 38.94821730059552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H02292" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00047803721469, + 38.92459222775901, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/31/07

Report Problem", + "NAME": "H02293" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01556874615575, + 38.942082677175044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H02294" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97228141047655, + 38.93317017762421, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H02295" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02307885555554, + 38.91117447543661, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02296" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03672352022497, + 38.93180919767034, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H02297" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96639061943615, + 38.92231479476334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H02298" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06984662657405, + 38.96867886274308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H02299" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03639217625027, + 38.92332992881701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02300" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05623907199511, + 38.94104019533707, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/20/06

Report Problem", + "NAME": "H02301" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10756082886142, + 38.929552418819014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H02302" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05661376747125, + 38.916823337844626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H02303" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10929937797565, + 38.929453750262994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02304" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10813979189241, + 38.93155736050178, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02305" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08495580620318, + 38.95096802566599, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/16/07

Report Problem", + "NAME": "H02306" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08158371393276, + 38.90771320054227, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H02307" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03652520878843, + 38.94071087339788, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - JUMBO

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H02413" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04116500907743, + 38.94191904581673, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - MEDALLION

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H02414" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03865462892603, + 38.948320702843226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H02415" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05882737349081, + 38.93563111491473, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H02416" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02467758786067, + 38.908524876182675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H02417" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07007617893264, + 38.95905705599412, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02418" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05254115011057, + 38.914738675618416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02419" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07265025843519, + 38.95837427113736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02420" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05732157760308, + 38.950518491681315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02638" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01843436347409, + 38.94320120678365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02639" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01379072420467, + 38.94235063579019, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H02640" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0202476609033, + 38.92480939485326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/22/06

Report Problem", + "NAME": "H02641" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0126518743266, + 38.94432730867445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02642" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07467168795272, + 38.955555653699165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H02643" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0004700148885, + 38.91821011899874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H02644" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02623425495086, + 38.93432873572846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H02645" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02590411626575, + 38.96440099210452, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02646" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01481201080135, + 38.96265679101783, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/26/07

Report Problem", + "NAME": "H02647" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98823858597284, + 38.89084077004873, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/13/06

Report Problem", + "NAME": "H02648" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08219097651164, + 38.946350006466254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02649" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08417049107285, + 38.91174525813888, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02650" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04360486231961, + 38.92158702518876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/30/07

Report Problem", + "NAME": "H02651" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06422458346891, + 38.95857512363125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02652" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99390912333604, + 38.88132483111803, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/27/06

Report Problem", + "NAME": "H02653" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08748491167783, + 38.90934062209095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02654" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08346140696953, + 38.90780850688067, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02655" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02494432152615, + 38.8974392292383, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H02656" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0547514876217, + 38.94528244492111, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/19/06

Report Problem", + "NAME": "H02657" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.007302717981, + 38.87922114947467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/31/08

Report Problem", + "NAME": "H02658" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00397984441919, + 38.90570008176016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H02659" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04447500880534, + 38.92136548885368, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H02660" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02253206450379, + 38.96006821634684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02661" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01062932859072, + 38.971683110127216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02308" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94401534744019, + 38.898300829267846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02309" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99750516074612, + 38.924556529167454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02310" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98371769316162, + 38.89488442698911, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H02311" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0200052271911, + 38.97120577875481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/05/07

Report Problem", + "NAME": "H02312" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03357376185724, + 38.90088891845056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H02313" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0019698162964, + 38.923369801265956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/04/07

Report Problem", + "NAME": "H02314" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00196983806445, + 38.92248794071405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/28/07

Report Problem", + "NAME": "H02315" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08217914356655, + 38.94306008018525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02316" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98063486816388, + 38.92712991542751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H02317" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02459980455362, + 38.97827773271868, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02318" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02555529091498, + 38.972409098743746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H02319" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09251870746847, + 38.9534322731507, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/12/07

Report Problem", + "NAME": "H02320" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97740173531604, + 38.8886205214979, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H02321" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04438494321283, + 38.91795087159957, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H02322" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03243162777484, + 38.9847965751539, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02323" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93512672537646, + 38.90710618769946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02324" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10781993691059, + 38.927391706227155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02325" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99391201805774, + 38.92263674232255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H02326" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99254426826764, + 38.94119475442937, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02327" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01289192339381, + 38.9086596441178, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H02328" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0171289132211, + 38.9441509236998, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02329" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07132006855714, + 38.96858615234745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H02330" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99731398980849, + 38.8450141155974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02331" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04220339865742, + 38.943867294271804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H02332" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04845967087124, + 38.915246437773575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02333" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07390424568763, + 38.907095806549556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02334" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0736850536795, + 38.90658617145866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02335" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02738498096726, + 38.937523301100654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H02336" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02210405876517, + 38.97444338354282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02337" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01540317949495, + 38.94419583591626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02338" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98102919648814, + 38.93313137847946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02339" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03325253716923, + 38.97874261500374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02340" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02270380188011, + 38.948318853281684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02341" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05852972304771, + 38.94960475114349, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02342" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02265472074242, + 38.94720796189297, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02343" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06004257485797, + 38.94974622462952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02344" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02229117767558, + 38.95435528586214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H02345" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02437869634737, + 38.963815603690286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H02346" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0863398599611, + 38.93140770002392, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H02347" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07446003484272, + 38.941327354464335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, UNKNOWN

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02348" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96154788233297, + 38.88008251981319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02349" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96154002356586, + 38.87888276159043, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02350" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93908433394238, + 38.8934714628045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H02351" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07696174519677, + 38.94465288288187, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H02352" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98452707218469, + 38.901437705643566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H02353" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98307120359952, + 38.90081204453013, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/28/08

Report Problem", + "NAME": "H02354" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93102057926296, + 38.89633370372234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H02355" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07686396891907, + 38.94557105371419, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H02356" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01993727557146, + 38.95435635055435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H02537" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02209995807004, + 38.953183598728174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H02538" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06995344197567, + 38.96318493822173, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER

In Service


Last Inspection Date: 01/30/08

Report Problem", + "NAME": "H02539" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05797381075922, + 38.947811245690204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02540" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04449249888805, + 38.925093566962765, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H02541" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0437313994238, + 38.92561112986625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H02542" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00197057048362, + 38.90475721992508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/22/07

Report Problem", + "NAME": "H02543" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02375637682073, + 38.95183478987163, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H02544" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99837148869801, + 38.925685088396534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02545" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08481166732525, + 38.931418250656556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/21/07

Report Problem", + "NAME": "H02546" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08629146874243, + 38.92899860671544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02547" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02112517659566, + 38.94632188757306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H02548" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02736025955492, + 38.936883015159765, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H02549" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98936423250684, + 38.90719653759504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02550" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02207064350374, + 38.94975706476989, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02551" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01812887101255, + 38.97134578442292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02552" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00739160628679, + 38.87830452196592, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02553" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07163552106215, + 38.93798426750831, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/27/08

Report Problem", + "NAME": "H02554" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06756916848134, + 38.93547454431843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/06/08

Report Problem", + "NAME": "H02555" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01651326188556, + 38.972391069128726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/10/07

Report Problem", + "NAME": "H02556" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0585651147206, + 38.94678061981897, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02557" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0684987768037, + 38.97208718020293, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02558" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97931488199157, + 38.88543187362759, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/24/07

Report Problem", + "NAME": "H02559" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99225677604774, + 38.842720862144745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H02560" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01994621168303, + 38.96600593455622, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H02561" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02298645342249, + 38.95102629822155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H02562" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00066602198648, + 38.91583061255836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H02563" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02178695993496, + 38.94844942256115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/21/07

Report Problem", + "NAME": "H02564" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99012191567768, + 38.940768527745675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02565" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06699514622558, + 38.905166258010226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02566" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06787837762634, + 38.90495225024058, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02567" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06206805278661, + 38.90527136838642, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H02568" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06339878951073, + 38.90505979534415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02569" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04119047446572, + 38.944128490494286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H02570" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06536083795007, + 38.931337510721534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H02571" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08735842976952, + 38.92953195304519, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H02572" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97886664211478, + 38.88691051908534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H02573" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02234745800985, + 38.96205548185861, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02574" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05264608758037, + 38.931277610454146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/11/07

Report Problem", + "NAME": "H02575" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0499058828883, + 38.93111799632543, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/11/06

Report Problem", + "NAME": "H02576" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98576094399658, + 38.90093807891935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H02577" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07034337570465, + 38.96586660483941, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H02578" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03356365134552, + 38.98233090562, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02579" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03356402105845, + 38.9814006899206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02580" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03462407441155, + 38.982331452288975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02581" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07589391357558, + 38.94120904523332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02582" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07909860910051, + 38.94706214563604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02583" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07723277946742, + 38.94306461496949, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02584" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07656531354291, + 38.94229559292867, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02585" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07567379257732, + 38.94045803139844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02586" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07413278665766, + 38.93770752485326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02587" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07331951862218, + 38.93623038838182, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02588" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0245030808214, + 38.97139829362167, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/09/07

Report Problem", + "NAME": "H02589" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01990199905, + 38.94986527411361, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H02590" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01789066704265, + 38.97350309510924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H02591" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0007294738845, + 38.922415780367054, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02592" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0272675620226, + 38.938548247373376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H02593" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00916266815548, + 38.95876382199242, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02594" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9357146481344, + 38.89978131465113, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02595" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03664550685504, + 38.967845349898745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02596" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07328740185461, + 38.92905439999068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H02597" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97604628676176, + 38.934164130205055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H02598" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95972973043133, + 38.88297298724842, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02599" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95997294891637, + 38.88359457741618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H02600" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02201973572386, + 38.951891125277406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H02601" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97984624043404, + 38.934947902801184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02602" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0625062994089, + 38.93843053414935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 01/26/07

Report Problem", + "NAME": "H02603" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96592309936018, + 38.9351485936903, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H02604" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98429827931386, + 38.90578355671845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/26/07

Report Problem", + "NAME": "H02605" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96284765886905, + 38.93293790192038, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02606" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09418305797594, + 38.95109207168437, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/12/07

Report Problem", + "NAME": "H02607" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99234638111264, + 38.92385113399154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H02608" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96024224750482, + 38.86058591036806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02609" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97424814716976, + 38.9382155544687, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02610" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9752600565698, + 38.93821872774666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02611" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97208111033463, + 38.93607823484159, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 02/20/08

Report Problem", + "NAME": "H02612" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04881156595594, + 38.89358395097665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H02613" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07703142445881, + 38.95630483572565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02614" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01982393727567, + 38.96999904805907, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/03/07

Report Problem", + "NAME": "H02615" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97429970712867, + 38.93728397289016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02616" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08615064137359, + 38.95454302150347, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H02617" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98822548703528, + 38.941713664002535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02618" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99114896058126, + 38.93529353037824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02619" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99104248181496, + 38.936285939543026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/03/08

Report Problem", + "NAME": "H02620" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08826919835818, + 38.907729970032534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02621" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.080677145523, + 38.949630408745456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H02622" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98465105467753, + 38.90264300390329, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H02623" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02712628166776, + 38.94395715481392, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H02624" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02333724266687, + 38.96558114465148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02625" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08870407217199, + 38.93039269272922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H02626" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07343974357367, + 38.95162130597298, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H02627" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9761044289552, + 38.89954085591208, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H02628" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0781152624224, + 38.95890564928163, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02629" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03573578521663, + 38.906870048628264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H02630" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07553694946108, + 38.91524895262129, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02631" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06302838633292, + 38.91333295411593, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02632" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05397875475903, + 38.91777949496411, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H02633" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.981249544108, + 38.93488892478633, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02634" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0243342749057, + 38.95915744459947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H02635" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02398777772999, + 38.958520578233106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02636" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0287741749278, + 38.96183474398523, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02637" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02237690928489, + 38.96674090982503, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02662" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02304635422067, + 38.978263032441106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H02663" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03630327820098, + 38.93441061193483, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H02664" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0273384955068, + 38.967236452604865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02665" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02581937400355, + 38.96732372744953, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02666" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97793423332969, + 38.93403952970115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02667" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97977231362411, + 38.93602750772483, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H02668" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98468499851424, + 38.937099260193314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02669" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00797525587318, + 38.95867309675644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02670" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02960082318928, + 38.98312918478488, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02671" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02960259495912, + 38.98147660893936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02672" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99131299040658, + 38.94120618200432, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H02673" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99287880185298, + 38.92456820278567, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H02674" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08248717048006, + 38.91174893592211, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02675" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05379829564731, + 38.95061637448283, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 03/10/08

Report Problem", + "NAME": "H02676" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05708032507926, + 38.94972104399757, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02677" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97411396213127, + 38.93956547173503, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02678" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05337147216997, + 38.90160242723158, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H02679" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07455248321001, + 38.94389393758971, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02680" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07574402514736, + 38.92745986634318, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02681" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98664967428418, + 38.90137634132128, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H02682" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96547678509202, + 38.92666725791586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02683" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06913209618116, + 38.96104876759208, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02684" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0415338475478, + 38.9197369200528, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 10/23/07

Report Problem", + "NAME": "H02685" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98835980872528, + 38.942789699430485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02686" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01354477416085, + 38.96275094578935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H02687" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02587272128599, + 38.960082658725554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02688" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06967068092413, + 38.96198036107136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/03/08

Report Problem", + "NAME": "H02689" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02288262501449, + 38.90024466559525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H02690" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06598766397853, + 38.9586972127499, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02691" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06571669484644, + 38.959878960853544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02692" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03608807839835, + 38.970773372655756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02693" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00703976734135, + 38.835064416182405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H02694" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00624204787314, + 38.83476679510385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02695" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9850618348579, + 38.900697522529086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H02696" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08652146281827, + 38.93701534412659, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H02697" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0210259953851, + 38.953136052981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H02698" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07304574402293, + 38.9194310966336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02699" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96245836531008, + 38.93097153451782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H02700" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96520489309603, + 38.92012397459474, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H02701" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02797906534607, + 38.98123057075456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02702" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9660450441877, + 38.92122865140622, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H02703" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01754489592821, + 38.94741380583731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02704" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07454823026318, + 38.944702632269674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H02705" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03606783135201, + 38.96998530213775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02706" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01796820270324, + 38.96278505851114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02707" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02717417225318, + 38.89846227093731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02708" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02690274488064, + 38.89906856041094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02709" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02126259584207, + 38.9672276079961, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02710" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02681234424902, + 38.8974490669438, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H02711" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0121051916335, + 38.87449751374221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02712" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01979880651939, + 38.95937432761223, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H02713" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96149342565168, + 38.93176697841911, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H02714" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01998635169623, + 38.960232305185635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02715" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07549380151357, + 38.91446445342166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02716" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96026513547736, + 38.85954099530886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/18/07

Report Problem", + "NAME": "H02717" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04246905200324, + 38.922676225441805, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H02718" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05754488275126, + 38.959587734298275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02719" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96158842123879, + 38.85954069045356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H02720" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02125660353127, + 38.9686858544096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02721" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09095103126786, + 38.930336438438886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02722" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97603374596963, + 38.90013634801519, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, ALorton

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H02723" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10634529491905, + 38.926696218793246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02724" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06292700337468, + 38.96457792209319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H02725" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01733118435389, + 38.94841755808591, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02726" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06149210630153, + 38.964874687582615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02727" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0757762150883, + 38.92630087141769, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02728" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99381977499158, + 38.88684027247317, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02729" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96073549382282, + 38.879231947439266, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02730" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02962030494675, + 38.94412082455208, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H02468" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01787494925566, + 38.97239819261687, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H02469" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05243315647581, + 38.917893523510216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 04/10/07

Report Problem", + "NAME": "H02470" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05231553649288, + 38.918769852511254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H02471" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99959125427705, + 38.9174707876315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02472" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99024512411675, + 38.906418140100186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02473" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98902682534181, + 38.90450224431941, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H02474" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02870471880496, + 38.982184671468154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02475" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02713414932595, + 38.96999227447476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02476" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03356480911077, + 38.97944754535645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02477" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07295081865969, + 38.91707568445428, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02478" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0125781038407, + 38.97131856063084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H02479" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08210481711443, + 38.95895057851505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02480" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07023686575405, + 38.96482982831641, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02481" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96878861215555, + 38.872989279174504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02482" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07155048194703, + 38.90859926968672, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02483" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98536050657182, + 38.85852835561634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H02484" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98235192635182, + 38.86829500818065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H02485" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0617300239778, + 38.95084857131873, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02486" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01958554387404, + 38.94833879409187, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02487" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98389137909558, + 38.928002639573705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H02488" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06032114428511, + 38.947910311200225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02489" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98255158013245, + 38.92987446429014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "null

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02490" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02074332933599, + 38.94904158230055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H02491" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00335184310933, + 38.92338755222246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/28/07

Report Problem", + "NAME": "H02492" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07453920271344, + 38.92072243430179, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02493" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02395728255865, + 38.95312804822754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02494" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92454893113323, + 38.8877063556372, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H02495" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98504739161407, + 38.867635572547385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02496" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96141689939331, + 38.86160613865794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02497" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96470789694999, + 38.860826203846194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02498" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9615870524531, + 38.86054263367201, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H02499" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01377791304122, + 38.967142484485365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02500" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99159569783862, + 38.89189301251123, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 11/16/06

Report Problem", + "NAME": "H02501" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0081087729727, + 38.91265720106606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02502" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02386091420239, + 38.94912544014645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H02503" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01981977463699, + 38.91524145511604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02504" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04653791578609, + 38.93440476891451, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/01/06

Report Problem", + "NAME": "H02505" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0386704240855, + 38.94715544969017, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H02506" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9853012082339, + 38.903105026892945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H02507" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98476570891793, + 38.903874668000846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02508" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9841988909006, + 38.904671678696246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H02509" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08614169405193, + 38.93254277613375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H02510" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08635531173482, + 38.93033880742206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy, K81A

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H02511" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99136181329705, + 38.9056356457202, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H02512" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99361190640226, + 38.92850485165855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02513" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96407524474564, + 38.93292952060768, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H02515" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07286678357575, + 38.92995519697157, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02516" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07291624480223, + 38.93068437990354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02517" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09691804556762, + 38.94973736942091, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H02518" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01659968397014, + 38.94648048790097, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02519" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05583635193537, + 38.91732244921431, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H02520" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01926967817015, + 38.94514473561404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H02521" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03400513235559, + 38.927473059401436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H02522" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00461969193535, + 38.91253773335434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H02523" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97907626040227, + 38.88315960146201, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H02524" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0223726676866, + 38.96506522365824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02525" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02237380545215, + 38.96604305965153, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H02526" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02105290772236, + 38.96558644269551, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02527" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96175158600312, + 38.92230999037113, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H02528" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02429424818841, + 38.96483765219254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02529" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08384401659636, + 38.92899800094187, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02530" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97407244182004, + 38.934161925371164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H02531" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04776528729575, + 38.90158273835266, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02532" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0477741582394, + 38.90074758788903, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H02533" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08878949369527, + 38.93234353971116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H02534" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0194803771406, + 38.94642281374821, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H02535" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07049248536562, + 38.95798521892536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02536" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02459890932167, + 38.95198242334732, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H02902" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0143887434619, + 38.96856663211834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02903" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02180522638218, + 38.91772886939987, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H02904" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01940475425917, + 38.949154055270625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H02905" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.040897844142, + 38.98695363977869, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02906" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02313489206699, + 38.94977973101786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/14/08

Report Problem", + "NAME": "H02908" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00003065967012, + 38.84738203330689, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H02909" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01970155064404, + 38.950887314757594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H02910" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08736464203297, + 38.92760844786164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02911" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96011631015338, + 38.8573554648712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H02912" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08850282097029, + 38.92756926109673, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02913" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96386257262297, + 38.88012288687299, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02914" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0699376582201, + 38.94974596661718, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H02915" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99163012405444, + 38.888394991187646, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H02916" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06702757555705, + 38.949749536027184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02917" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07733838562105, + 38.967086534709644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H02918" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0885831439012, + 38.92877448591992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H02919" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06973636272916, + 38.94885014153114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02920" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06651544284968, + 38.94884236163414, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02921" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06802568692844, + 38.95146170298381, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H02922" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06524231015274, + 38.95176906625256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H02923" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06665594828573, + 38.951909851851, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H02924" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03176816151006, + 38.89721848945617, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H02925" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06509575606306, + 38.950803415889446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H02926" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99382306172488, + 38.89281046491458, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H02927" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02882609154034, + 38.90570689899109, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03087" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04776698264268, + 38.90850458380797, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03088" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02815455389718, + 38.90652160667121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03089" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0447434790466, + 38.90784136120179, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03090" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07078317429435, + 38.93560885666946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/20/07

Report Problem", + "NAME": "H03091" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03341630351177, + 38.919804401258716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H03092" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03208475040314, + 38.90186314024949, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 10/05/07

Report Problem", + "NAME": "H03093" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03037686585058, + 38.905609116809615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H03094" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0425887405051, + 38.9163995937398, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H03095" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05466293887393, + 38.918395878206084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H03096" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05296743828444, + 38.91890325145118, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H03097" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04041173538481, + 38.91415293161991, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H03098" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03164030582494, + 38.899632314630544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03099" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0433075056648, + 38.91604122130108, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H03100" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01772139508522, + 38.892333362761406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03101" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03208871737974, + 38.89953363185921, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03102" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0813364855882, + 38.9107543116095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03103" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02305874662248, + 38.894909950671675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03104" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03469703694248, + 38.932553578595794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H03105" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02306608203807, + 38.89599191704609, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03106" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02341688809271, + 38.93110941478698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H03107" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08140393638062, + 38.91174491219483, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03108" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02307672864536, + 38.928904419535314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H03109" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02321323735772, + 38.929736751362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H03111" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02363740761078, + 38.932757521025074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H03112" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02108444452564, + 38.96020832152155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H03113" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9751703353952, + 38.939563106514754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/11/08

Report Problem", + "NAME": "H03114" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01742002027113, + 38.89345571587333, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03115" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08744946688167, + 38.9470383515712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03116" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08848230121285, + 38.94713986344964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 07/28/05

Report Problem", + "NAME": "H03117" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0479340301891, + 38.90643934270487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H03118" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04285137720532, + 38.98895768083349, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03119" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94193495963901, + 38.90569577398126, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H03120" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98230029298894, + 38.89551555416437, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/07/08

Report Problem", + "NAME": "H03121" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02365560071762, + 38.89401038185349, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/28/06

Report Problem", + "NAME": "H03122" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98807822613291, + 38.86387088247043, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03123" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01971398518002, + 38.89252267868498, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03124" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97983242169656, + 38.864979964405556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H03125" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07296261495479, + 38.96986861548283, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03126" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09585423574843, + 38.93338040076271, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03127" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09741394888795, + 38.933635001211, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H03128" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0200994217569, + 38.89296300519965, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03129" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02608030639787, + 38.89599669701374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03130" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02608327485271, + 38.89626499248735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03131" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0260869710429, + 38.894929600508185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03132" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07032810487607, + 38.96981385598583, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03133" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99106326491763, + 38.93160310137425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03134" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99244617314679, + 38.93153137570906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03135" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99361543002202, + 38.93049740888045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03136" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06999632434669, + 38.94401711428125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03137" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09425666496513, + 38.93503335500786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03138" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09611635346562, + 38.93598523441239, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03139" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09610696448924, + 38.935959352268156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03140" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07011629969837, + 38.944717310565544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03141" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99236947888178, + 38.930541628026205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/08/07

Report Problem", + "NAME": "H03142" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09794780001978, + 38.935872065100014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03143" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02854188135831, + 38.98408985876794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02928" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94027872795944, + 38.901433086539136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H02929" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05837722138072, + 38.97263133631645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02930" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06137547955139, + 38.923426389022524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/16/07

Report Problem", + "NAME": "H02931" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9451951819191, + 38.89968399208242, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02932" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06402924165414, + 38.97130562674562, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02933" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0200050247894, + 38.96723731558112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02934" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06623855970695, + 38.96765773369292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H02935" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02000738459866, + 38.962654657219545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02936" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08852181372436, + 38.95709113065836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H02937" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02187068391794, + 38.9491867343747, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H02938" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01762649204353, + 38.94994516439553, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H02939" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08852757171282, + 38.95600494548803, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H02940" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02215820738881, + 38.95088274915812, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H02941" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97110287178758, + 38.86829860368583, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H02942" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.101181272711, + 38.92303626298996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02943" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03668272521205, + 38.9472520915482, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H02944" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9827990160731, + 38.935010991342544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02945" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98292247631936, + 38.93399192734275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02946" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9862392881322, + 38.92987011919891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 12/21/07

Report Problem", + "NAME": "H02947" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96580306856188, + 38.931464603772504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H03227" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02092291998343, + 38.950915451586106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H02731" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99504803004115, + 38.886799640154344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/23/06

Report Problem", + "NAME": "H02732" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03356052041585, + 38.98325528461156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02733" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97735925089813, + 38.90376141255918, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H02734" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05700505788282, + 38.929619667189975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H02735" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98823540752882, + 38.88690853239119, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/09/06

Report Problem", + "NAME": "H02736" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99369186423148, + 38.888211782237654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H02737" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98847055158396, + 38.885407291194156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H02738" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0644464776546, + 38.975088712227425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy, K81D

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02739" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04781167214053, + 38.92154345500451, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H02740" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04792649812599, + 38.92060728084153, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H02741" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04697267821008, + 38.91787419006351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H02742" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08377053342369, + 38.949734683898505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02743" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92615456755493, + 38.89730507398183, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H02744" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04023335344576, + 38.94750085820114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02745" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04991627848544, + 38.914764554297705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02746" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98939281339175, + 38.88541362139925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/28/06

Report Problem", + "NAME": "H02747" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03317375143408, + 38.91266352015362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02748" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9893943475846, + 38.88416452819514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/28/06

Report Problem", + "NAME": "H02749" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0498702157463, + 38.91585565446687, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/31/06

Report Problem", + "NAME": "H02750" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98935164636526, + 38.94277262419313, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H02751" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98558657960098, + 38.87850638413591, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H02752" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98920779018394, + 38.94171793866747, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02753" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05958974015776, + 38.93686741519019, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H02754" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96386806478893, + 38.923377069036455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H02755" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96500196998929, + 38.92349271161427, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H02756" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99623721789736, + 38.9051931170514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H02757" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1041711439131, + 38.93034687873001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Super Centurion

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02758" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10567693920379, + 38.93034570706572, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02759" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06978821523562, + 38.95321953843046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02760" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0182030047528, + 38.95784771400652, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H02762" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06113582979371, + 38.908504650197806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02763" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02846546381095, + 38.96597802008824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02764" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02851827276753, + 38.96498652348279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02765" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98822260263263, + 38.939553142292176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02766" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05418627623949, + 38.94846208211238, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/13/06

Report Problem", + "NAME": "H02767" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98958252679594, + 38.88913655821772, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/09/06

Report Problem", + "NAME": "H02768" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9874939143268, + 38.889722239991485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/13/06

Report Problem", + "NAME": "H02769" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98821542043567, + 38.88963535716788, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/13/06

Report Problem", + "NAME": "H02770" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02429468621548, + 38.96023289465471, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02771" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02097121178902, + 38.95197530217497, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H02772" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01810356806486, + 38.966000198826286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/25/08

Report Problem", + "NAME": "H02773" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98838392888722, + 38.8881346416142, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H02774" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02408738607409, + 38.96662288628026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02775" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97849885896642, + 38.935017233813696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02776" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99015482688863, + 38.882948561934825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H02777" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01355757632085, + 38.963875020878895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H02778" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0620770271892, + 38.93738847588149, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H02779" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0645353958969, + 38.93715377542695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/26/05

Report Problem", + "NAME": "H02780" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99142816172018, + 38.88300746006085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H02781" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99389191034899, + 38.88354791080574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/31/06

Report Problem", + "NAME": "H02782" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9936908099422, + 38.88527491529525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H02783" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99487984117705, + 38.88536244485919, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/20/06

Report Problem", + "NAME": "H02784" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9577998695163, + 38.92928478786997, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H02785" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99736249516249, + 38.888732606981996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/23/06

Report Problem", + "NAME": "H02786" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03606541976758, + 38.98042876017387, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02787" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03664211062159, + 38.98092221336629, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02788" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03840386489804, + 38.98111491950425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02789" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06459310015308, + 38.96299674096101, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02790" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06400379625342, + 38.964058777672626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02791" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0862127218135, + 38.949601792913846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H02792" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00210435365605, + 38.88681820235681, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H02793" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01761415501166, + 38.9493189740229, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H02794" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08633562595578, + 38.94872322377017, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02795" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02811227340482, + 38.97806615772773, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H02796" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03267863074426, + 38.97804039652529, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02797" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02287541079497, + 38.89859864151087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H02798" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00337703261773, + 38.88742496789653, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H02799" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01564936281108, + 38.97381538961255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02800" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07231816644787, + 38.944053706900114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02801" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02504822445354, + 38.970792022856486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02802" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00480546922454, + 38.883310042204364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H02803" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00708853196168, + 38.88435647499218, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02804" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03507066553969, + 38.9583983566694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02805" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06049350439324, + 38.908516443147796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02806" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96497734743998, + 38.93622278809826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H02807" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03606738466014, + 38.983261699971635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02808" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03517450948188, + 38.957169778796455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02809" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96355366677835, + 38.92123712547026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02810" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00914653023953, + 38.88443489407119, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02811" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02886988744604, + 38.9498790328301, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H02812" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0376500024943, + 38.96976644371336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02813" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99159666743031, + 38.89129452337258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02814" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03755681828297, + 38.925968484214685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02815" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0386499319476, + 38.92640204939267, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H02816" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9883723361935, + 38.89681694406874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H02817" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05920013940896, + 38.96484396320037, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02818" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03981729799737, + 38.98593162585151, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02819" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03666006178169, + 38.98577612233834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02820" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95936042291098, + 38.89707316470831, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02821" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09662060489372, + 38.91815114002967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02822" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.038639075481, + 38.92535102565968, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H02823" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0160874479547, + 38.95755364327408, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02824" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98358950539925, + 38.883975023099254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H02825" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0115096236005, + 38.95771178306311, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02826" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02872088746602, + 38.98327030166299, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02827" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98838783107377, + 38.90544650991937, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02828" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03497602345617, + 38.979443789792036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02829" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98450900238207, + 38.89365593737253, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H02830" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9845065187825, + 38.89468862931972, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H02831" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06116240964118, + 38.930197061130215, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/17/07

Report Problem", + "NAME": "H02832" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04515146176038, + 38.919536178937236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H02833" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05939895076244, + 38.91197129015594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02834" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98681380517935, + 38.907733012885835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H02835" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00553069177245, + 38.91190689388572, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02836" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99250686626317, + 38.903827856858626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H02837" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04962914635318, + 38.90316895449359, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H02838" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05247266824095, + 38.9001298416467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H02839" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97604911519802, + 38.936216266633835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02840" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03042100750358, + 38.89976240391909, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H02841" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04001351905193, + 38.924347387804595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H02842" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.034326080924, + 38.91816797296458, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/09/06

Report Problem", + "NAME": "H02843" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05135344376176, + 38.901848683339836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H02844" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9848926326764, + 38.906201235112746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H02845" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03861924822975, + 38.91190855187142, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02846" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01981758338732, + 38.95213004931649, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H02847" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9873312335747, + 38.94188502526387, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02848" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06897721180758, + 38.90789082427492, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02849" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96011635569127, + 38.85842863853633, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H02850" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01714663297176, + 38.94540403641226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02851" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03627110790353, + 38.960841399367695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02852" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03836330202999, + 38.940738804845225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - MEDALLION

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H02853" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03606371287357, + 38.98232375662743, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02854" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01373058280289, + 38.97003265820491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02855" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04075901523107, + 38.94781493894056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02856" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03961425219778, + 38.94896500493843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H02857" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08188400494964, + 38.94799114368281, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02858" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07126631225275, + 38.96218720187305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02859" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0733276710173, + 38.927413438138814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H02860" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07332082549893, + 38.92609469685907, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02861" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97739677370338, + 38.88354364027425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H02862" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05943070770421, + 38.928994642311245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H02863" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01816270221923, + 38.961417233318755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02864" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08637538061116, + 38.94795314850212, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H02865" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08271188351608, + 38.9107572646946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02866" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03633603086506, + 38.924808373675376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H02867" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03638060500347, + 38.928564926314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H02868" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03638443136809, + 38.92763329442551, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/11/06

Report Problem", + "NAME": "H02869" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03632638903728, + 38.92634597927871, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/28/06

Report Problem", + "NAME": "H02870" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03636657586856, + 38.93375563460904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H02871" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08613134814472, + 38.927644486717035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02872" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07055680850449, + 38.93900010465631, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/27/08

Report Problem", + "NAME": "H02873" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98357520181932, + 38.92538268942487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H02874" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07522495460594, + 38.921755168866255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02875" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08636657697011, + 38.95098914331841, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02876" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01999650957241, + 38.96674601639446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02877" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.063921121912, + 38.91985356575158, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/28/07

Report Problem", + "NAME": "H02878" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98236021192426, + 38.88871250430753, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H02879" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10673440451829, + 38.93022662910844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02880" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07237723894121, + 38.93190779112898, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02881" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02483786340854, + 38.94303296288861, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/15/07

Report Problem", + "NAME": "H02882" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00135270385104, + 38.9013738532868, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H02883" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01979605834092, + 38.96136044139613, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02884" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06269314730781, + 38.94076765411844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/23/07

Report Problem", + "NAME": "H02885" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01477651850657, + 38.95675570231492, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H02886" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99367237037428, + 38.89955134402845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H02887" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98708760656741, + 38.93836563023403, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02888" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99368665608712, + 38.89822197206655, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02889" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03614336191062, + 38.97518158899454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02890" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06458191801624, + 38.91046945310282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/09/07

Report Problem", + "NAME": "H02891" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04547516810061, + 38.912661596130256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02892" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9906903057795, + 38.9276797012508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H02893" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99689708810793, + 38.892597584106376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/22/06

Report Problem", + "NAME": "H02894" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98086376687272, + 38.89670413456619, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H02895" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02254618472847, + 38.96724671726225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02896" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06269067060322, + 38.95323311748991, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02897" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06168986025702, + 38.95274852743326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02898" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02410692005859, + 38.9673348398549, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02899" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06073249159013, + 38.92543132842902, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/16/07

Report Problem", + "NAME": "H02900" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02364450237229, + 38.95095242526244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H02901" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03523052530355, + 38.95175756798051, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H03297" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03423424607234, + 38.91708507249467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/03/07

Report Problem", + "NAME": "H03298" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98973078274481, + 38.9068140489427, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H03299" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98885272304648, + 38.90644633779362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03300" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03428090131767, + 38.93596628949295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H03301" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06431463065022, + 38.95987453370289, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H03302" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04372931068744, + 38.92239311552636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/31/06

Report Problem", + "NAME": "H03303" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11076819424653, + 38.93302548786255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03304" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97476030792609, + 38.8994430757703, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H03305" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05016570493255, + 38.90641621823128, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03306" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10074616355688, + 38.92244171100309, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03307" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0359774153151, + 38.917496742990586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03308" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06401258157139, + 38.94512770751248, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/19/06

Report Problem", + "NAME": "H03309" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.972553090231, + 38.89710844848632, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03310" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04823409827345, + 38.904661304085934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03311" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0579089958781, + 38.919203379751934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/16/07

Report Problem", + "NAME": "H03312" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03471726719849, + 38.918058171978856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H03313" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05929658158536, + 38.92003715234638, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 01/16/07

Report Problem", + "NAME": "H03314" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0491928417682, + 38.91921631032356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H03315" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99755014156088, + 38.90963021299381, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H03316" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02324493312351, + 38.971208837008994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/31/07

Report Problem", + "NAME": "H03317" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97334939813467, + 38.86956466614988, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H03318" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9295753801931, + 38.90712992640007, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H03319" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0013728864496, + 38.93113383195846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03320" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96556233456266, + 38.87207556892842, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03321" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00068902400164, + 38.931156331733064, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03322" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96461037011889, + 38.87828911533239, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03323" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02609296347707, + 38.94182111077709, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H03324" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00070550430765, + 38.91476881807865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03325" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98784616603112, + 38.867320684134896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03326" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.033996320508, + 38.934752188852485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H03327" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9858320785056, + 38.866959102776605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03328" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00803190570673, + 38.910447640819484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03329" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04408417959783, + 38.90728380595576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03330" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02936940340913, + 38.899748340725566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03433" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02793236450039, + 38.89990313246803, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03434" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99764032626777, + 38.93266149871578, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03435" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06139588781582, + 38.96683331148713, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03436" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05998637153127, + 38.967377411437006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03437" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01780065176634, + 38.95746199717616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H03438" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0850621258863, + 38.92664400433839, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03439" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01811267022678, + 38.91473332884798, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03440" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98001187991588, + 38.903631671757026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H03441" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03166179652261, + 38.94831104108468, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H03442" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09926604370759, + 38.94976474827561, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03443" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94082029569975, + 38.898296416762875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/08/07

Report Problem", + "NAME": "H03444" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96694238720148, + 38.871877728830235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03445" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98865543317764, + 38.907761222173676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03446" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10668063271588, + 38.93213531451373, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03447" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06378603850308, + 38.962212835309344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03448" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93794536763046, + 38.89830002372759, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03449" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04117553848172, + 38.92703646224849, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H03450" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02667355546363, + 38.98298752315273, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03451" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07005082813194, + 38.97295400624552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03452" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97412353447909, + 38.94080864514366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03453" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04214917276605, + 38.98661722539487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03454" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93476525744737, + 38.893516667819924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03455" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97748181777493, + 38.927778093133114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H03456" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97085947471197, + 38.87144759376663, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H03457" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94331158360622, + 38.90472201663022, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H03458" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05783447726918, + 38.971482776529804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03459" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06009025073817, + 38.96966792018786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03460" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03254673160264, + 38.94820231137163, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H03461" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07712061955102, + 38.94639891718966, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03462" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9860802044197, + 38.93712239682275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03463" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05382961284064, + 38.91634468059244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03464" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98755501515522, + 38.90393692183332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/14/07

Report Problem", + "NAME": "H03465" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04347281206081, + 38.92345821105997, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H03466" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01610489144294, + 38.906536915075314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03331" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03469643328886, + 38.95624689896507, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03332" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01716911321745, + 38.960098025323695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H03333" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06523098739477, + 38.96856797063749, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03334" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04234996255478, + 38.911180808629, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03335" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02567608034323, + 38.97667218153771, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03336" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0463103182848, + 38.91918370699859, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H03337" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02583510740307, + 38.959222423474095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03338" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04085210627483, + 38.91980728118933, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H03339" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01451198699614, + 38.96507280523883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/22/08

Report Problem", + "NAME": "H03340" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01270880921302, + 38.96384837071562, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03341" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01371332989149, + 38.95755259459596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03342" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10136443028597, + 38.940135366154614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H03343" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97010657452317, + 38.870666572975466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H03344" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02413036517737, + 38.95952384371296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/12/08

Report Problem", + "NAME": "H03345" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0363991665629, + 38.9186570383677, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H03346" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03026347006455, + 38.94830869093847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H03347" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97441343227625, + 38.90013628363326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H03348" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99606881935534, + 38.93123222569328, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03349" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00813613177841, + 38.898990605817986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03350" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98074488060112, + 38.928314031291514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H03351" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03216073892442, + 38.89629815961426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H03352" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98089050300352, + 38.88593258465733, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/17/07

Report Problem", + "NAME": "H03353" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9827160037569, + 38.899863115137556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H03354" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97785202396865, + 38.93317642864588, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H03355" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98064753189516, + 38.88658736383662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 04/02/07

Report Problem", + "NAME": "H03356" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98452687382702, + 38.89087227202959, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/01/06

Report Problem", + "NAME": "H03357" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0408396518367, + 38.99040349653492, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03358" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00136040600324, + 38.903853240550944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03359" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04178691624276, + 38.98969959429973, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03360" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98950462436757, + 38.89043620750151, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, USP

In Service


Last Inspection Date: 11/02/06

Report Problem", + "NAME": "H03361" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98930192604975, + 38.900290368575824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H03362" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08196364767504, + 38.96213651154911, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03363" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00217201741032, + 38.894579887660605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H03364" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00073257896204, + 38.89352328704712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03365" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00129488980372, + 38.88681949332545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H03366" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99818834996307, + 38.893656671220334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/17/06

Report Problem", + "NAME": "H03367" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9827738929664, + 38.87940478842192, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/19/06

Report Problem", + "NAME": "H03368" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02978944986528, + 38.89747306465408, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03369" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00263207647633, + 38.89093485744887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03370" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9970116738263, + 38.89352236830028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/17/06

Report Problem", + "NAME": "H03371" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99382340425214, + 38.87740396939212, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/07/06

Report Problem", + "NAME": "H03372" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99609680847905, + 38.89187101697557, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H03373" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00143943869173, + 38.8908449026043, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03374" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9938183830671, + 38.89532289850454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/10/08

Report Problem", + "NAME": "H03375" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98059207362998, + 38.89483170998907, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03376" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99726706755538, + 38.89206273034278, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/22/06

Report Problem", + "NAME": "H03377" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99270926672081, + 38.896038702323644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/04/07

Report Problem", + "NAME": "H03378" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99382389041337, + 38.89681954852394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H03379" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99957258814449, + 38.880482794892494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H03380" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00463628183971, + 38.89193024724656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03381" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00266135903874, + 38.89198713374388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03382" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00357609404077, + 38.88337790143777, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03383" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00649776234197, + 38.91980883631186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03384" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93158734956272, + 38.89876956558682, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H03385" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02408775649945, + 38.92709242768263, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/06/06

Report Problem", + "NAME": "H03386" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98826504237935, + 38.90687277145959, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03387" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01524786921011, + 38.95773998356088, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03388" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01510927572625, + 38.95864329582148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03389" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01601229071359, + 38.958674803639504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03390" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04425217960876, + 38.90034251792656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H03391" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97995818439382, + 38.89318979179849, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/01/06

Report Problem", + "NAME": "H03392" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06516252786108, + 38.94676396739446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/14/07

Report Problem", + "NAME": "H03393" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03218546279713, + 38.985667403902205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03394" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03041646992394, + 38.985505531321294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03395" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98578779691665, + 38.94292929569741, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/01/08

Report Problem", + "NAME": "H03396" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09914738347675, + 38.93457083996036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03397" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08851498953393, + 38.95539577085225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/14/06

Report Problem", + "NAME": "H03398" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98716895522595, + 38.944152924790885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03399" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02342075674645, + 38.963814087919516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H03400" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0337478416161, + 38.90033240399695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03401" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02427068161309, + 38.96282511490076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03402" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06308281390493, + 38.951898655356715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 09/28/07

Report Problem", + "NAME": "H03403" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94205693021019, + 38.904697303774235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H03404" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98044613797795, + 38.941511295281714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H03405" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9659531069675, + 38.93609799616704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H03406" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92633030369664, + 38.89446299077991, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H03407" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06267732645263, + 38.90390466511905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03408" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97735007187362, + 38.89607085770454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03409" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9973775533355, + 38.88609521532298, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03410" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02982017295054, + 38.98373785017111, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03411" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06847002137327, + 38.927590641890546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H03412" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06287644500546, + 38.903333941911434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03413" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03360247456936, + 38.89901966666405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03414" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08615235336855, + 38.92662663943616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03415" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93156893220028, + 38.90066374296222, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H03416" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02580865941684, + 38.96797541316662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03417" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10759934927498, + 38.92589935689342, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03418" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03519530289861, + 38.89850501841142, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03419" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03502880919689, + 38.8984907271415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03420" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99360730840769, + 38.929493891838334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03421" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96082276272078, + 38.931304809550554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03422" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00546675425886, + 38.927512173372406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03423" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00465765290892, + 38.928481619922515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H03424" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92341534107159, + 38.90081623862845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03425" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92454528284608, + 38.90107387430716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03426" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03565234909287, + 38.91042511841834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H03427" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04618683047882, + 38.92317331773082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H03428" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01718318174782, + 38.95772095094627, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H03429" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02503023342399, + 38.89989009760997, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03430" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02380387978829, + 38.899896524653215, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H03431" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02589135426061, + 38.89966971861209, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H03432" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96888924928506, + 38.93032416746363, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03228" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94244393855773, + 38.89603332682141, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03229" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06686883146358, + 38.96027083349703, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03230" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9982990173124, + 38.896766676174806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03231" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0318548600467, + 38.96025676191078, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03232" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94092887782952, + 38.89573406927598, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03233" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05310225265829, + 38.90379200372231, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03234" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97530695718312, + 38.937280892983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03235" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02984975618305, + 38.9297171290891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H03236" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98613881982891, + 38.93072204107117, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H03237" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97137625642253, + 38.89786249033922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03238" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97024276680973, + 38.93622643622479, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03239" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93767823438161, + 38.89527454800895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03240" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04891458948948, + 38.9140520942187, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03241" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94050592034135, + 38.89435393475314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03242" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01422850545389, + 38.950169969405366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03243" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98910193086898, + 38.905895789060146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03244" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01562374262963, + 38.950124867004895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03245" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01575827746454, + 38.95100529057552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03246" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01464972767037, + 38.95122219179631, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03247" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05803106258423, + 38.90464530893065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H03248" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00061885650385, + 38.907315047410485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H03249" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02131049663008, + 38.96997450039332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H03250" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04055047279483, + 38.927947880767114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03251" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07081194986277, + 38.934782660775284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/20/07

Report Problem", + "NAME": "H03252" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93729333939501, + 38.899674198487396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H03253" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01603393578681, + 38.957137847287456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/04/08

Report Problem", + "NAME": "H03254" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02358998154966, + 38.93010707057808, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/05/06

Report Problem", + "NAME": "H03255" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02191745636011, + 38.933068867912276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H03256" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.022497638117, + 38.93397815488185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H03257" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.031922700864, + 38.96607360569486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03258" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92616527381887, + 38.88987904756654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03259" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04001458312968, + 38.94073239584887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - MEDALLION

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H03260" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09691833606425, + 38.91922675867083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03261" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09545286852136, + 38.91921827195258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03262" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92737624913352, + 38.903540382115466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H03263" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02976871844585, + 38.959369574895995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03264" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99271603523866, + 38.880327507124356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/04/06

Report Problem", + "NAME": "H03265" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02413506064522, + 38.96115808459131, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03266" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07221836024834, + 38.921208692754206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H03267" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92604935599762, + 38.89183160280566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H03268" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07230046925673, + 38.93466808271233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H03269" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04456011873708, + 38.9224091607994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/16/06

Report Problem", + "NAME": "H03270" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0121012816985, + 38.905738204688184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03271" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04018867609298, + 38.913248814745145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H03272" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09863817425865, + 38.94207134705794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy, K81A

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03273" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0401485840224, + 38.91488549911225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H03274" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99067203042787, + 38.86161732073139, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03275" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00335825259928, + 38.88513816406251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/07/07

Report Problem", + "NAME": "H03276" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06763283633927, + 38.92623420665324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/21/07

Report Problem", + "NAME": "H03277" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0332973706502, + 38.91190541524462, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H03278" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09099443256319, + 38.93144978695123, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03279" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0036762592087, + 38.88264829117101, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/05/06

Report Problem", + "NAME": "H03280" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00064494982652, + 38.88334813664974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/29/07

Report Problem", + "NAME": "H03281" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03646717927317, + 38.976908113652264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03282" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06378028903576, + 38.96964855288482, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03284" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.998286048646, + 38.88573273493939, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H03285" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96527873609115, + 38.86153717534136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H03286" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93060495846773, + 38.90712227279393, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H03287" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08522915921506, + 38.95961080136902, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03288" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0346558187928, + 38.981274373552864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03289" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07692993278623, + 38.920731532738714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03290" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01791361191718, + 38.9746634328977, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03291" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01322022632348, + 38.97327780788181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03292" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00933043029164, + 38.911905724386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H03293" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01055762599105, + 38.97094233330344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03294" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02256016501191, + 38.968688754063066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03295" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02303479238186, + 38.97716281514932, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03296" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02498461340262, + 38.89198192469661, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03863" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97990996049893, + 38.92444369334872, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H03864" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92994573477426, + 38.89711938638032, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H03865" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97640335154595, + 38.89902273779327, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H03866" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01041302258128, + 38.890311457901525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03867" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02612604776414, + 38.89237705239765, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H03868" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99102877721856, + 38.93446957700486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03869" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03402348109263, + 38.92447660881721, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 08/29/06

Report Problem", + "NAME": "H03870" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06124243085797, + 38.92911490482321, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 01/17/07

Report Problem", + "NAME": "H03871" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04295605152053, + 38.985655944987855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H03872" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10076522575906, + 38.931459797065465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03874" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0004716434192, + 38.92035297474018, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H03875" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97347967764179, + 38.86340106868082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03876" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96643237263883, + 38.9300391403663, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03877" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07921944603848, + 38.943220705359096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03878" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02168194233691, + 38.89195749610055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03879" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07588599138984, + 38.952145385513234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03880" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04727774979757, + 38.92308294239803, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H03881" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0853625024635, + 38.90862976680895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03882" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03964665004801, + 38.9846076838793, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03830" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03908392320625, + 38.98395121053371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03831" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96321353390363, + 38.86359825445163, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03832" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02797877832664, + 38.978736122347094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03833" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03223348196782, + 38.93156513595735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - MEDALLION

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H03834" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96158654258512, + 38.869860621375096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H03835" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08636091099869, + 38.957082089979814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03836" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96822075371378, + 38.92445615217211, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03837" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09544953554047, + 38.95204335448902, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/16/07

Report Problem", + "NAME": "H03838" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08615751312666, + 38.944918346126705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H03839" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02886218470458, + 38.8860928408347, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03840" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01334858680185, + 38.913399619508205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03841" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09600278938973, + 38.91565811486848, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03842" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0967897385974, + 38.91513128862411, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03843" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01591880173525, + 38.976191084700844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03844" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98418601929126, + 38.86652599227564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03845" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02460898749625, + 38.97656312313311, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03847" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09213751094268, + 38.91488682483357, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03848" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01901399351266, + 38.90357978409401, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H03849" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04161429804053, + 38.895542102096144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H03850" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01021326302616, + 38.8923027582499, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H03851" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09011456122073, + 38.92748236935688, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03852" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03252375811546, + 38.92659747651678, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H03853" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99000709490832, + 38.939065455355845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H03854" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03167043335802, + 38.891956503212036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03856" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09099426570121, + 38.93231315252996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H03857" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04337483415686, + 38.892323437960094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H03858" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04650464095003, + 38.9879141621054, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03859" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99711523397714, + 38.89465596591057, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03910" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99428317455563, + 38.89799081219083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03911" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97836606831018, + 38.86545894951317, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03912" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03707457511283, + 38.961072110034124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03913" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99729511234159, + 38.89541195232633, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H03914" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99731536566578, + 38.898179682432804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/22/07

Report Problem", + "NAME": "H03915" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09634210368928, + 38.929647910327986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03916" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03616492698073, + 38.979448887186656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03917" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03625476942405, + 38.98649405887124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03918" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08686362531986, + 38.95341327109391, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H03919" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93377621621066, + 38.874790865740515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H03920" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09549553322232, + 38.92783750122455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03921" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10923121922406, + 38.93252609933625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03922" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05419366790687, + 38.95196349631073, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03923" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9588419117385, + 38.861817506729984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H03925" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93620427886142, + 38.87641616150902, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H03926" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04694119757379, + 38.987019544734004, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03927" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95152028721222, + 38.86542853072662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/19/08

Report Problem", + "NAME": "H03928" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95574889530575, + 38.863987737400656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/28/07

Report Problem", + "NAME": "H03929" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0854956302458, + 38.93843440169358, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03930" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01532876019056, + 38.88827218569448, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03931" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06501039288709, + 38.96986047000123, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03932" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01745467700397, + 38.88891084251656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03933" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98225786810792, + 38.86540278965049, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03934" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02300351982935, + 38.90288464874361, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 08/25/07

Report Problem", + "NAME": "H03935" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98270217181815, + 38.90855545191018, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03936" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93786398290078, + 38.89682821189746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H03937" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04666180513155, + 38.9885525741736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/06/07

Report Problem", + "NAME": "H03938" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1116466981253, + 38.93561441448011, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03939" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11219363916346, + 38.93730801054442, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03940" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04757570923891, + 38.987569969160624, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03941" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02823779857899, + 38.88684356270815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03942" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0282309115219, + 38.886187556095436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03943" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00495713826047, + 38.89117948535643, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03944" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00500178262007, + 38.88988113358681, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03945" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00984618617153, + 38.87216582049221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03946" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98823781582459, + 38.89530238124047, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/29/08

Report Problem", + "NAME": "H03947" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04572655821386, + 38.98716398606276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03948" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98106120425996, + 38.897430457030836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03949" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08464504993837, + 38.91460424377495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03950" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03861614220645, + 38.90391449224204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03951" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99737101257563, + 38.905014089088816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H03952" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98449943972014, + 38.90832927041487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03953" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01073416861786, + 38.87048679200491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03954" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02285070196406, + 38.91787464961466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/26/06

Report Problem", + "NAME": "H03955" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10747703024757, + 38.937333945470286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03956" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96147869503832, + 38.93350089214056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03957" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99277574731735, + 38.903198343075225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03958" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97908142675853, + 38.89344943044639, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 08/11/07

Report Problem", + "NAME": "H03959" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08995721371068, + 38.925913061278344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03960" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01579209668822, + 38.91692364525055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03962" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96281527751978, + 38.8750967026841, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H03963" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09670906799096, + 38.942093921271976, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H03964" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08013863133662, + 38.95336272738712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H03965" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0660259256967, + 38.90870570386126, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H03967" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01079539551675, + 38.86829708593764, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H03467" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01201818903515, + 38.86829535398415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H03468" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98800133220846, + 38.90303708811884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/28/08

Report Problem", + "NAME": "H03469" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0445791473415, + 38.92423719413861, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H03470" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06739893007835, + 38.95538959098755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03471" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04329340794283, + 38.925014140566084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H03472" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09547235984488, + 38.92096937637083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03473" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99091673282062, + 38.93261067803325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03474" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03561761563257, + 38.92710714782879, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H03475" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09810802359775, + 38.947861978639196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/27/07

Report Problem", + "NAME": "H03476" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09670806383083, + 38.9486836465249, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03477" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09682813870131, + 38.94704998506508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H03478" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9888624176088, + 38.93370164910796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 12/27/07

Report Problem", + "NAME": "H03479" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01224225159582, + 38.91690852269912, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03480" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03213043256787, + 38.89808908467546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03481" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03626563882898, + 38.93041037748961, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H03482" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01409257250101, + 38.9141623940784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/17/07

Report Problem", + "NAME": "H03483" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97751802616081, + 38.87080205490014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03484" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03778147839239, + 38.93005594281548, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H03485" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03360436617929, + 38.98594498021841, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 02/25/08

Report Problem", + "NAME": "H03486" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03901929060466, + 38.93149678437457, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H03487" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92116154998111, + 38.89293295892934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H03488" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06993720598565, + 38.95146033188334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03489" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0648778039224, + 38.95892147295136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H03607" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04176746414652, + 38.928147977220306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H03608" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02961774516223, + 38.94279062562233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H03609" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03289675476479, + 38.93557440283326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H03610" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0687630936708, + 38.95557981693206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03611" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98615011023337, + 38.938265701996706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03612" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01248667909704, + 38.95863384036325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03613" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98094488213499, + 38.897887657549866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/17/07

Report Problem", + "NAME": "H03614" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97848309145489, + 38.94293098092975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03615" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02326747336885, + 38.970016925534274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H03616" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02123102130753, + 38.923717610292435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H03617" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01791989150955, + 38.955487980242914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H03618" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04275495061151, + 38.945085221162486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H03619" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06857757212204, + 38.93172482649028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 11/02/06

Report Problem", + "NAME": "H03620" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06976366098428, + 38.90863433874821, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H03621" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02410955535525, + 38.892410132338334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03622" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0386894040868, + 38.93255967598979, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H03490" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04115347643652, + 38.931492160799195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H03491" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10086253282172, + 38.936857743065055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy, K81A

In Service


Last Inspection Date: 07/20/05

Report Problem", + "NAME": "H03492" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92435148839108, + 38.88694422693056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H03493" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01372085823124, + 38.95668417023782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03494" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0997752917991, + 38.93582170338214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03495" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0931650833886, + 38.93267259442051, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03496" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92073814069416, + 38.89404085533239, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03497" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01668371123995, + 38.916861634116884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03498" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06847798975795, + 38.93468727528434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/06/08

Report Problem", + "NAME": "H03499" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06994033852389, + 38.95961481171528, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03500" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0700326822772, + 38.91837021050567, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03501" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07119585400345, + 38.91973315256621, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03502" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01624996062424, + 38.91856654864214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03503" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91533726488154, + 38.89709851513759, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H03504" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0719586462016, + 38.95066023327597, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H03505" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06976552667464, + 38.953954780000906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03506" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06395599340895, + 38.92439308451422, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H03507" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06403904663674, + 38.925894158326486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/18/06

Report Problem", + "NAME": "H03508" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9991027660933, + 38.84778999505156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H03509" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97312787861743, + 38.86998259643053, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H03510" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99498873935342, + 38.85973167311152, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03511" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02095755775508, + 38.90730002623178, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H03512" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96502790165346, + 38.92881473337035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03513" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98822607764494, + 38.908173716881976, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/23/06

Report Problem", + "NAME": "H03514" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.986788771045, + 38.909433731469726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. PIPE

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03515" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0217678007848, + 38.89972227672309, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03516" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02097771900802, + 38.8997218177079, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03517" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02233393008127, + 38.9643956569575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03518" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10996084388502, + 38.93205912695095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03519" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9835867974813, + 38.89679894753847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/15/07

Report Problem", + "NAME": "H03520" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99256406835455, + 38.942793447610214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H03521" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0277269091157, + 38.96275021750744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03522" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93896208746283, + 38.87157923201205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03523" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02073157901705, + 38.90423525494305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H03524" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04437360904353, + 38.89827069305227, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H03525" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99263604315881, + 38.93356622869363, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03526" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99124428129417, + 38.93356573635454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03527" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01645539326304, + 38.95436758528171, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/09/07

Report Problem", + "NAME": "H03528" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98657249782944, + 38.93380238253051, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03529" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9872753008676, + 38.9453083118496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03530" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0327429624509, + 38.8919515591772, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03531" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99258526421836, + 38.940629838151104, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03532" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03327068465558, + 38.984067746213725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H03533" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00782919903669, + 38.893223111341605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03534" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00722571707709, + 38.89375455391396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03535" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00818319153815, + 38.89227793789439, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03536" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00611604125696, + 38.893755031669244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03537" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97018782938873, + 38.937110901958384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03538" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10113057907711, + 38.92702125554618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03539" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05450915260506, + 38.92823876662402, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H03540" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00064685369448, + 38.889943027327455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/03/07

Report Problem", + "NAME": "H03541" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99504653391331, + 38.93225566550957, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03542" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04775599202239, + 38.89837482021134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H03543" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01374021929531, + 38.95866633669406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03544" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04572830838023, + 38.89826512594186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03545" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97732647684614, + 38.884241019733444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03546" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07263374916317, + 38.935573021349896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03547" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07688469443129, + 38.91922331602368, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03548" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06855101713087, + 38.95830295071001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H03549" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0761135742582, + 38.91922445141739, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03550" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0966488045416, + 38.92537947996271, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03551" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09772203483506, + 38.923645674339994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03552" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0961516317116, + 38.92618920663205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03553" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97510464986044, + 38.94021241925771, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03554" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92998715624509, + 38.896341782002246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H03555" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01776505953998, + 38.95658617430043, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/08/07

Report Problem", + "NAME": "H03556" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08350418811625, + 38.914294412090925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03557" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97628105960614, + 38.939733999281444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H03558" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09072308463259, + 38.94402779179968, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03559" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00640052318134, + 38.839306354002446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03560" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03161045862089, + 38.89617030995506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03561" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03801328331464, + 38.94924861256427, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H03562" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03350551320615, + 38.8948737301164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03563" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0335328033324, + 38.89414833247011, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03564" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03211037259001, + 38.893450358329694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03565" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96498579366997, + 38.930532371271475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03566" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06883084150009, + 38.96961954726777, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03567" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03483103176875, + 38.98616942125019, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03568" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03353093077355, + 38.89281301338369, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03570" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03352935056255, + 38.8934976139276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03572" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03210758664463, + 38.89294615162206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03573" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98210916758026, + 38.86880949547161, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03574" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98083421247642, + 38.89617984291388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03576" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.073723600765, + 38.91877161250799, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03577" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03627502423484, + 38.934939371976625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H03578" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00196989818596, + 38.90713099191895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H03579" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97030744562417, + 38.89904102170986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H03580" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01772316190412, + 38.951135133712526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H03581" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97030685493905, + 38.900460099398536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/24/07

Report Problem", + "NAME": "H03582" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98412242592256, + 38.92691358413429, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H03583" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06869098110673, + 38.950785765423596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03584" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07482935147564, + 38.919209200965525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03585" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06175018721785, + 38.96296459500961, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03586" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.078610480102, + 38.9226014616886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03587" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07721011013284, + 38.922601764718415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03588" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.996237336026, + 38.89464853605419, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/17/06

Report Problem", + "NAME": "H03589" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98094061209993, + 38.88871499281592, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H03590" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10462878785783, + 38.93153283774806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03591" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10579525899973, + 38.93147391829147, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, Metropolitan

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03592" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03515977974857, + 38.984191209676595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03593" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98699175805315, + 38.884048464528746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/28/06

Report Problem", + "NAME": "H03594" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93051093669813, + 38.900045262021244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03595" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09924264907829, + 38.92766583372402, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03598" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05915347544803, + 38.970458519593265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Am. Darling

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03599" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98767458054587, + 38.909808890628184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H03600" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06918313232683, + 38.94319846573763, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/23/07

Report Problem", + "NAME": "H03601" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09820310633214, + 38.93672710819925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/30/08

Report Problem", + "NAME": "H03602" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09640769656482, + 38.93689336470722, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/10/08

Report Problem", + "NAME": "H03603" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99513930911083, + 38.92835761224649, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03604" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0161162222745, + 38.95561371890085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H03605" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01801310619798, + 38.97783561092687, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03606" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0241161346038, + 38.892947894666534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03623" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06080593579244, + 38.91195520720525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H03624" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00349951129549, + 38.90179401247429, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H03625" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03603311313024, + 38.92861706597699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H03626" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98706064919195, + 38.90011391132168, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H03627" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99251046407925, + 38.87933429204732, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03628" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02340590137683, + 38.94204977857756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H03629" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99503666664481, + 38.90036731500801, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H03630" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9947877391105, + 38.88266900606166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H03631" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99270242324893, + 38.89814173130459, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H03632" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9913498446408, + 38.90317578837661, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03633" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98250128690327, + 38.86280263754207, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03634" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98453132964869, + 38.88972583089636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/01/06

Report Problem", + "NAME": "H03635" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98709658955805, + 38.86323840536412, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H03636" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9817391517061, + 38.898515838365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03637" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01780522474259, + 38.91831272856207, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03638" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05057805248413, + 38.901935141495144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H03860" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08284878024966, + 38.93576238291455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H03861" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08409890038097, + 38.93668000362474, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H03862" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05770442299941, + 38.91611569521685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H04040" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08662125231317, + 38.92436624935645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04041" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98371465716961, + 38.89899349249849, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H04042" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04177175090446, + 38.89932046886113, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04043" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01103386883443, + 38.831798486191275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04045" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00995084093915, + 38.83288575170231, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04046" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02854884668233, + 38.894980786862554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H04047" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02514928775247, + 38.94260309290333, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/15/07

Report Problem", + "NAME": "H04048" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05702232323367, + 38.97194758603748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04049" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05629909667, + 38.97266068612665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04050" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97425492349903, + 38.94171353886082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H04051" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07573085679125, + 38.95248056685318, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H04052" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01643052574566, + 38.947537705491264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04053" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01586649186335, + 38.94863270354359, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04054" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0684167028383, + 38.97057009668146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04055" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95978665670779, + 38.866650130056975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04056" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95997011447649, + 38.867589509105336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H04057" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01487219659207, + 38.961449290097285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H04058" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01355819790655, + 38.95543634649551, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04059" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04419602781695, + 38.919716197268066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H04060" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02005767147647, + 38.96869166031924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04061" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01375133712867, + 38.96145372422804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H04062" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03975031325787, + 38.98718292495032, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04063" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0388952422845, + 38.98778543811387, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04064" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06067002568248, + 38.96367401986806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04066" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9791710704358, + 38.86830932097184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04067" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05669197844536, + 38.948006462190435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H04068" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95635154378483, + 38.8574793712542, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/19/07

Report Problem", + "NAME": "H04069" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05886548933277, + 38.974784329722446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04070" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9572988108649, + 38.857506773850666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H04071" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95650687754384, + 38.86473471172185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/03/08

Report Problem", + "NAME": "H04072" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98332298599779, + 38.903261353463854, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H04073" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05973347103077, + 38.97541950141029, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H04074" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04447098000675, + 38.98757801898338, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04075" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0789281388047, + 38.944837782033424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04076" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06968110563282, + 38.95456296060451, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04077" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97888279186657, + 38.8862037515252, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H04078" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98212771509833, + 38.896160382711955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H04079" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04238191531039, + 38.940834544272654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H04080" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97006383997629, + 38.93762528004567, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04082" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07155691243143, + 38.9583234992033, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04083" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99816703591898, + 38.84521429970991, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/17/07

Report Problem", + "NAME": "H04084" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07713768504172, + 38.931925348225796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04085" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07852847850171, + 38.932540716448024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H04086" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05216429665562, + 38.93550136105225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 12/27/06

Report Problem", + "NAME": "H04087" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03352291853086, + 38.960320686584865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04088" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05388161748036, + 38.93504170813739, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/28/06

Report Problem", + "NAME": "H04089" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07870202301126, + 38.91929192074877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04090" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09251282938644, + 38.94208533657608, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04091" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98397296793766, + 38.90909195392388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H04092" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99787141723502, + 38.84706921384978, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H04093" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01323041960103, + 38.951106514649524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04094" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95853381973963, + 38.86747746576027, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04095" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09065436896263, + 38.94973380945873, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, 13843

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H04096" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0664335955175, + 38.97044425092554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04097" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07563919776541, + 38.930486340266896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H04098" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09972541822468, + 38.93809722509768, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER

In Service


Last Inspection Date: 01/30/08

Report Problem", + "NAME": "H04099" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04078943476497, + 38.988175695037896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04100" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04185893638387, + 38.98760633181776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04101" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05663744327478, + 38.97557317276737, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04102" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03331745963929, + 38.967670405478614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04103" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06104480063263, + 38.97674652924848, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04104" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97840451796174, + 38.940633483429274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04105" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06770001660747, + 38.96105156933964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H02948" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00221244259393, + 38.905694795654476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H02949" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04156597768267, + 38.91473781631745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H02950" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03434655343527, + 38.911904796252664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/24/07

Report Problem", + "NAME": "H02951" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94185353379996, + 38.87095546114053, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02952" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94422238688007, + 38.87068867061388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02953" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03064494329088, + 38.98139730236563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02954" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96472342470437, + 38.86279193559433, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02955" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99256887443242, + 38.89657497042028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02956" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03646264841899, + 38.90037117994516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02957" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03989327314353, + 38.949413134877766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H02958" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93649035427315, + 38.894421401238304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H02959" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93787631808944, + 38.894603665178266, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H02960" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97396896606872, + 38.91569954439072, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H02961" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9702417662267, + 38.93514179165418, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/10/08

Report Problem", + "NAME": "H02962" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93669390087652, + 38.90154269543422, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H02963" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9763044924441, + 38.934995973348904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/26/08

Report Problem", + "NAME": "H02964" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93649024941064, + 38.90070270858288, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H02965" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9752576216346, + 38.936128225814585, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H02966" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08969568447627, + 38.928812030810974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02967" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09060295034901, + 38.9288113309887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H02968" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10062932746031, + 38.92577087392711, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02969" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0999641554701, + 38.92639025337231, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H02970" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01571697210065, + 38.94543686536992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H02971" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06409720135247, + 38.906055783001875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H02972" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02973342919985, + 38.90271086302745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H02974" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02948487020159, + 38.90345979949418, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H02975" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97229268802785, + 38.86817630563903, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H02977" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02947389315197, + 38.901976973057096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H02978" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08395005293166, + 38.92758994312347, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02979" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08490699611133, + 38.92878907840041, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H02980" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0263575848704, + 38.98028491319458, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H02981" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97312498181334, + 38.87210576858482, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H02982" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02255583510971, + 38.9678782563258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02983" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02409493213075, + 38.967884408231924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H02984" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02978067986126, + 38.958505706828696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H02985" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0759482629434, + 38.921640439414546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02986" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0753347203405, + 38.920626417876086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H02987" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9873322250439, + 38.94279688930142, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H02988" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99137291222536, + 38.94226925460015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H02989" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99016741744016, + 38.94279727927315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H02990" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02460274115977, + 38.97735697440674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H02991" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06532711131152, + 38.9385468922548, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H02992" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97827601281539, + 38.88501275921611, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H02993" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06103787674311, + 38.93941398009788, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/23/07

Report Problem", + "NAME": "H02994" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9874904167884, + 38.9483891668096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H02995" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05022434699933, + 38.899021540353786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02996" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06290389927247, + 38.94000924979791, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/23/07

Report Problem", + "NAME": "H02997" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95116096184061, + 38.89185398085343, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H02998" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06206069015427, + 38.95443700347486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H02999" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98229656724462, + 38.894828332352944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03000" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03198973846924, + 38.9840865974315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03001" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03146467084993, + 38.982369413712924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03002" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0580820494067, + 38.92976971084407, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H03003" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0212889498334, + 38.96123611742944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H03004" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06174761456867, + 38.95273689429035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03005" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07116792920074, + 38.94407248345832, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03006" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07252430746055, + 38.946246889557514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/27/07

Report Problem", + "NAME": "H03007" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06390743607209, + 38.947817674296836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03008" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0317115825553, + 38.98331185864448, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H03011" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0746864483502, + 38.94225883853485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03012" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04660697225161, + 38.915883972564075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H03013" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05504206511793, + 38.922077052115164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/09/07

Report Problem", + "NAME": "H03014" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05420279506004, + 38.92118215207154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/08/07

Report Problem", + "NAME": "H03015" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96158803992253, + 38.8584722823408, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H03016" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06420009266469, + 38.91459228540269, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H03017" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97985765635987, + 38.93414049072257, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03018" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04185247563534, + 38.90029193751483, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03019" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03781470311527, + 38.98413658441228, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03022" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03655960121773, + 38.98422727278148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H03023" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0258980132094, + 38.89819715647122, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03024" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02589090923084, + 38.8991105788257, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03026" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97265336894158, + 38.89623892163102, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03027" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99593299847837, + 38.847614992775895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H03028" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98722162081393, + 38.94063985150541, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03029" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98720564624243, + 38.93973400298994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03030" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07254358027352, + 38.94557482355423, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H03031" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96030138624464, + 38.855432859360555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H03032" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02543039027128, + 38.93744058711033, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03033" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02340156988542, + 38.96455719127427, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03034" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98831228616139, + 38.868264650840004, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/29/07

Report Problem", + "NAME": "H03035" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03489267189798, + 38.97863815525506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03036" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01121501130028, + 38.86457728425669, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H03037" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0627498346912, + 38.96271200287118, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H03038" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03161623059155, + 38.95086298079314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H03039" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07698095184269, + 38.92737933453517, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03040" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05625682098265, + 38.922018396979134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/02/06

Report Problem", + "NAME": "H03041" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0562799401089, + 38.9219865864635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/08/07

Report Problem", + "NAME": "H03042" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0324021280902, + 38.88703742305465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03043" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98384903271742, + 38.902332702098725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H03044" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07689570971831, + 38.92167502435756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03045" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97742065292081, + 38.870291727982654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03046" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91988640097766, + 38.89138571378376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03047" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98783083546893, + 38.905937255126915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H03048" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91935850525131, + 38.8928769031489, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03049" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98234413229171, + 38.88987833884194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H03050" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02210590270623, + 38.891961443379316, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03051" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98371962752331, + 38.89368192726817, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 11/02/06

Report Problem", + "NAME": "H03052" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02229788417795, + 38.9626276865333, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03053" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99145719128774, + 38.896028383967334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03054" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07118207234939, + 38.94557519209683, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03055" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02589261985113, + 38.898455922851475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03056" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07252535397834, + 38.944860378728514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03057" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01121321152814, + 38.89587848417434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03058" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09862948149636, + 38.93542112168419, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03059" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09429926442536, + 38.933423734469294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03060" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09690891832666, + 38.93459711185135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03061" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92801999809289, + 38.89199576822766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03062" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0616879339619, + 38.90975680831896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H03968" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03606786536979, + 38.9787393214202, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03969" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0525084929729, + 38.9072960431751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03970" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03016400705357, + 38.96458551370847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03971" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09668170160201, + 38.94302560853069, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H03973" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09671075726781, + 38.94411299327274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/24/08

Report Problem", + "NAME": "H03974" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09803281476682, + 38.94317677742152, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03975" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97540058984123, + 38.9125489999525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03976" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03460529069865, + 38.96865568635638, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03977" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08783395031158, + 38.92581868369559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03978" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08632753819212, + 38.92547903942986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03979" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97822738811706, + 38.93822279533832, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03980" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97991455023197, + 38.9383644646014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03981" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00674117092807, + 38.88337491499376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H03982" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98597813021148, + 38.90590420302283, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H03983" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02301107047627, + 38.88472800998696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03984" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06305918575342, + 38.97514923810629, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03985" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02675503132782, + 38.88116717029896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H03986" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0665521850546, + 38.964065273251784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03987" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09241363308224, + 38.943228008750694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/10/07

Report Problem", + "NAME": "H03988" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06376949697231, + 38.95820712399084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03989" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06031583923898, + 38.95782405161072, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, OTHER, SEE FLD NOTES

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03990" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09427905928855, + 38.937236803935924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/28/08

Report Problem", + "NAME": "H03991" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08883645267849, + 38.94875196927613, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03992" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07869497771303, + 38.96202180294453, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03993" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0429748838458, + 38.893376574264394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H03994" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00637765657599, + 38.958679293406085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H03995" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08982996756723, + 38.92506344929522, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03996" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01602771740421, + 38.95642084448925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03997" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06292550685887, + 38.905942662484556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H03998" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01980276107504, + 38.89034543915308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03999" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01357395614416, + 38.956034187140546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04000" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06269138832498, + 38.905029026189716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H04001" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02204024219837, + 38.8890403824405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04002" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00191570334259, + 38.92447347439483, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 07/04/07

Report Problem", + "NAME": "H04003" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97424444409062, + 38.91267366044658, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04004" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00521851748582, + 38.96191074751201, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04005" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96614379977014, + 38.86332439318026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H04006" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01604768424016, + 38.96998161076748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H04007" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01798979967707, + 38.96999639890795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/08/07

Report Problem", + "NAME": "H04008" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03328315926508, + 38.96422308535336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04010" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0238265466472, + 38.89338067113388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04011" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99370727002821, + 38.94263119441689, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04012" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93060463282256, + 38.8991854425678, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/10/07

Report Problem", + "NAME": "H04013" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01590225628522, + 38.94936853072098, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04014" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00597295640206, + 38.96275739706677, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04015" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00493167869334, + 38.96275936437879, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04016" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07785319025015, + 38.92053735034512, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04017" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07863753641577, + 38.92073190951478, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04018" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9639708265334, + 38.927918526610114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04019" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04357751409007, + 38.89440173764898, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 05/22/07

Report Problem", + "NAME": "H04021" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06345914346076, + 38.9544323792256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04022" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07782609452616, + 38.92260089669057, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04023" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97809766570585, + 38.87216301954785, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04024" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99170790665153, + 38.881327767439224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H04025" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00914027167185, + 38.95937947515001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04026" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96765966457971, + 38.872845621288775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04027" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01250568837185, + 38.95078117056552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04028" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01127409964606, + 38.893323732400454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/27/07

Report Problem", + "NAME": "H04029" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0298103442541, + 38.903666872988985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04030" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01580450973327, + 38.952071863715666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04032" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99164721389013, + 38.874741483565835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04033" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98601578552778, + 38.93959433725474, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04034" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02127026646194, + 38.96327450830563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04035" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03208252955329, + 38.90648623624658, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04036" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04629683964683, + 38.986346257729046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H04037" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01349904007813, + 38.95460841265484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04038" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08855635198329, + 38.94975116399902, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H04039" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.983107967382, + 38.881095468785446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/17/06

Report Problem", + "NAME": "H03677" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93649173908001, + 38.8719792391055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H03678" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08495111066085, + 38.95338792184123, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton, Jumbo

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03679" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99014864329517, + 38.88850120150739, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03680" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06649007812808, + 38.926274012544695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/21/07

Report Problem", + "NAME": "H03681" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97228728616999, + 38.89802257240617, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03682" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97305461341588, + 38.89815158049901, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03683" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07194684810413, + 38.95402424498342, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03684" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0704029814852, + 38.96767312792083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/05/07

Report Problem", + "NAME": "H03685" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06819964179292, + 38.95970487763922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03686" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06857977859936, + 38.92611669080908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/18/06

Report Problem", + "NAME": "H03687" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97335088000865, + 38.89716489944282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03688" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06939470842758, + 38.96580666327167, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03689" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96647728455709, + 38.923312842592246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03690" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99159495079708, + 38.89412463786989, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03691" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93521318221076, + 38.87287414331036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H03692" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01092779574589, + 38.89388438312533, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03693" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05694661152383, + 38.91986118140679, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/16/07

Report Problem", + "NAME": "H03694" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94029933366774, + 38.9027639647087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H03695" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97314431741103, + 38.937179315985574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H03696" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0205514687882, + 38.92702235174442, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H03697" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0853824635693, + 38.95215701440594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03698" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9783843125799, + 38.89911538475254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H03699" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02234943910024, + 38.963810532145374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03700" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.980472508922, + 38.89947491577438, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H03701" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02006437787375, + 38.96382170242456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03702" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0200717411199, + 38.96440122888235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03703" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97362628962821, + 38.89622811909845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03704" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07334808038217, + 38.922589118554164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03705" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08853939694403, + 38.93443787261761, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H03706" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0135852712972, + 38.892217321679375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03707" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9692144008831, + 38.9351346612466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H03708" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96144233639275, + 38.8563659923698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H03709" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0207600042742, + 38.90560467234774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03711" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02171332822185, + 38.90569951012563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03712" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01965967869721, + 38.905688685374685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H03713" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02500514892911, + 38.905713526572235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H03714" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06996003837614, + 38.95214374893433, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03715" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0691474798505, + 38.91160221589817, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H03716" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0275442165845, + 38.94192542711134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H03717" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0659115101399, + 38.948024220431506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03718" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03089662049607, + 38.909121929570325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03719" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92005501407913, + 38.893834818771566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H03720" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9208296184903, + 38.89132150558269, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03721" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01179322841816, + 38.89621411476836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03722" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.920399197111, + 38.89252964150244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03723" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02449089988893, + 38.89384785188733, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03724" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01135124439529, + 38.89625492140214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03725" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01229578405268, + 38.896209513728095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H03726" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0175407045451, + 38.954430467340345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H03727" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95582762484945, + 38.89472922965072, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03728" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09072110165582, + 38.943221902714605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/04/07

Report Problem", + "NAME": "H03729" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02114474067075, + 38.92236311680298, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H03730" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02977627681746, + 38.9603388614735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03731" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97227316669225, + 38.937285833876736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03732" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07139661612302, + 38.95144319880221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03733" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07149511555085, + 38.9519844548071, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03734" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99014412893996, + 38.87637385009661, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/18/06

Report Problem", + "NAME": "H03735" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06989891802888, + 38.95079151738554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03736" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1089673506558, + 38.930876923651695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03737" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07449581337784, + 38.950685804032574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03738" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00897728353526, + 38.86883306897482, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H03739" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99140377054967, + 38.8594056386091, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03740" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99736764122783, + 38.88421520178614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03741" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09669654450336, + 38.93833754409531, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/28/08

Report Problem", + "NAME": "H03742" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09363207613583, + 38.95454338590985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03743" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03756818679783, + 38.94831320181106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, JCF&M - O'BRIEN

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H03745" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06782067092134, + 38.96980681528786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03746" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02462632034302, + 38.97575849555607, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H03747" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02975356797397, + 38.89383454975894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03748" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08629777521445, + 38.95600283812685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03749" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0332257376092, + 38.96678495718561, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03750" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02094461563445, + 38.92117828812778, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H03751" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03479925964035, + 38.983269696087696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03752" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98611537580487, + 38.86828080558696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03753" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98368081284474, + 38.868295940148016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03754" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02640885529095, + 38.9816359993884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03755" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93595291359323, + 38.892961706694685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03756" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0152190176066, + 38.96996937125363, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03757" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0120368884428, + 38.89813621335621, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03758" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98857173461492, + 38.92974780349216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03759" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01173910187487, + 38.962806523745826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03760" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03163797839147, + 38.9519323919739, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "LORTON

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H03761" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08369855437151, + 38.9598213311138, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03762" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02307129536355, + 38.95192642408664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H03763" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0006666692874, + 38.92710127701415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/26/07

Report Problem", + "NAME": "H03764" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00067257706168, + 38.92865223812971, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/21/07

Report Problem", + "NAME": "H03765" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0981991942097, + 38.938032018000676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H03766" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03657419052587, + 38.97321080522942, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03767" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99147214260988, + 38.942797066448314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03768" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93552592358458, + 38.90153821012132, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H03769" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01715890067166, + 38.92151159171768, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/11/07

Report Problem", + "NAME": "H03770" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02661216471658, + 38.97572342389356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/29/07

Report Problem", + "NAME": "H03771" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08197121143826, + 38.953935581040234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03772" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06727793389449, + 38.96301045094308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03773" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06691636964722, + 38.96218992536008, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03774" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03624027089462, + 38.96484329801526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03775" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03606891843275, + 38.96618248104796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03776" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01151398465859, + 38.95863948027614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H03777" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02108847292881, + 38.96274863950616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03778" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01628669731507, + 38.960114330397104, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H03779" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07172472634355, + 38.95326636250473, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03780" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92659979375982, + 38.89538823889925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03063" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05481944695319, + 38.90863927935803, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03064" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99045305923349, + 38.89362891870926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H03065" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02960908896921, + 38.98432816699746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03066" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96138370683586, + 38.86300740514237, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03067" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02982710973664, + 38.98233223347925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03068" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9838035827238, + 38.90661697762803, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H03069" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02408068276591, + 38.90034027371829, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H03070" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96161646154707, + 38.86464616677731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03071" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96305345025989, + 38.86467463746823, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H03072" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02300677333967, + 38.901462408978254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H03073" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92482080753835, + 38.900409802471714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03074" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92373018419002, + 38.90336745850674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H03075" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03364369264172, + 38.92648065493712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03076" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97428972209386, + 38.91341281352198, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H03077" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00334994320968, + 38.91338393879082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H03078" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02511580881117, + 38.901630403843804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03079" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05419268649665, + 38.96710665957529, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03080" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05339476720333, + 38.972366533079885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03081" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1125383286442, + 38.933493859497865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03082" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11179712299568, + 38.932421347729324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03083" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11339121339472, + 38.93430413432582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03084" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03471359883676, + 38.92632287668111, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H03085" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01884359062524, + 38.89914307904043, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/23/07

Report Problem", + "NAME": "H03086" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08079917976667, + 38.90968626762176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03144" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05011078397638, + 38.92509781496898, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 01/02/07

Report Problem", + "NAME": "H03145" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01716558161729, + 38.96617805495967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03146" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97614306030557, + 38.937146131347774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03147" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98686088996996, + 38.878449367192985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/19/06

Report Problem", + "NAME": "H03148" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01850567279425, + 38.95217319775716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H03149" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02136505073196, + 38.893516344880595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03150" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02125294674073, + 38.96787721220207, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03151" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97193514646283, + 38.9266449440927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03152" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0622395873915, + 38.96190733397728, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/06/06

Report Problem", + "NAME": "H03153" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02208557190023, + 38.893868951574575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03154" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01892885021266, + 38.9509652738986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H03155" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01269773684562, + 38.91076793287809, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03156" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02560353653519, + 38.97535640157549, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/05/07

Report Problem", + "NAME": "H03157" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07597581965106, + 38.920554251490216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03158" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01445662012209, + 38.970911630605706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03159" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97992285017801, + 38.892137896330816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H03160" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02757932395554, + 38.89503858324773, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/09/07

Report Problem", + "NAME": "H03161" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03378412864905, + 38.89674597564679, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03162" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03204687358763, + 38.959331074935484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03163" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00834632839808, + 38.91116145773266, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03164" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00668606710775, + 38.91116805053838, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, A.M Darling

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03165" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03489033834887, + 38.98542149689027, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03166" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0193985907573, + 38.95545874664475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H03167" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01796350962823, + 38.9554724613172, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H03168" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05868106619577, + 38.96082930030023, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03169" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06103442452928, + 38.96111596339867, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03170" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06206808690501, + 38.96111634711395, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03171" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06383390729334, + 38.96111396410806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03172" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06831085455843, + 38.960101518445335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03173" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00504620826737, + 38.915662148765044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H03174" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99259931929079, + 38.942241403978024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03175" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04338426468321, + 38.905765143216705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H03176" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02343349885864, + 38.964877797455635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03177" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04122348711469, + 38.90554513094255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H03178" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98876281410804, + 38.93259738370972, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03179" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06125704515705, + 38.90604031689242, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/17/07

Report Problem", + "NAME": "H03180" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01795801880182, + 38.96010097863465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H03181" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97798088532983, + 38.905736044810936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03182" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07218142447562, + 38.93341050686152, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03183" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99610510582475, + 38.882195423491474, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H03184" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03342680659567, + 38.902431263270714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03185" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9983770585032, + 38.88364220587385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H03186" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03188537061007, + 38.96547600877725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03187" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06384730087355, + 38.93345825419992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H03188" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0623914666454, + 38.93342628620925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H03189" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03354560389819, + 38.905583486006044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03190" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0295379713994, + 38.9649033944595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03191" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02992553456137, + 38.96548422881598, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03192" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0350029582957, + 38.95298587803494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H03193" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03420182627764, + 38.95525409969401, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H03194" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0836747219192, + 38.95909814692505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H03195" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0210331732302, + 38.96205700483449, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03196" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02233705863725, + 38.96123460669477, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03197" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08613009266448, + 38.94615900551879, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H03198" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02001259489441, + 38.96559534535164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03199" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04084405420814, + 38.94498942572128, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H03200" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02233651766645, + 38.96558315074984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03201" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01818410341815, + 38.96208764225485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03202" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01978833708134, + 38.962058780560724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03203" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05982166459445, + 38.92964514024582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/01/06

Report Problem", + "NAME": "H03204" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05484272262582, + 38.91710801701536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H03205" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02410285262988, + 38.965475682936756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03206" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9731781709192, + 38.91341622103919, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/22/08

Report Problem", + "NAME": "H03207" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05532668603573, + 38.917922259143026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H03208" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07708626176108, + 38.955398522853244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03209" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01814837482497, + 38.95952572697822, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H03210" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09117591710422, + 38.94170236347056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/01/07

Report Problem", + "NAME": "H03211" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01788018551073, + 38.95311603756104, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H03212" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03534395233046, + 38.900405854604756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03213" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02975547661387, + 38.905568694103394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03214" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03744482475409, + 38.898599312202094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03215" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99826787017928, + 38.89484157005496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H03217" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96614811675154, + 38.93740151748665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H03218" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96702467886138, + 38.93773785859908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H03219" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01376017119289, + 38.90650970325695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03220" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02127716386049, + 38.9666283589006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03221" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03320654797018, + 38.96547181254771, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03222" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97727047753588, + 38.87189155540718, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03223" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03359826259181, + 38.96607518113642, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03224" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04580996506851, + 38.9181264705252, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H03225" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00793015891381, + 38.91494642066939, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03226" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98739632735732, + 38.94109091557004, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H03883" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02993102017118, + 38.96689660329951, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/24/08

Report Problem", + "NAME": "H03884" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09067994690605, + 38.9510866978661, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H03885" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11038764936174, + 38.93389987912438, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03886" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94467417940768, + 38.89338113353268, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H03887" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0294107470302, + 38.88605622905826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03888" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03138760520034, + 38.886051705821195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03889" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02978226203604, + 38.88605471159471, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03890" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01238495004036, + 38.89282399770782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H03891" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0504189584601, + 38.92385555226625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 04/30/07

Report Problem", + "NAME": "H03892" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05587634447056, + 38.94552488410289, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/01/07

Report Problem", + "NAME": "H03893" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0612463631752, + 38.96825400819106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03894" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02899749615027, + 38.93613977816719, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H03895" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97208970699663, + 38.934006003443756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H03896" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07452274816076, + 38.95486545414465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H03897" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96756117691892, + 38.92938999601311, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03898" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07233903474206, + 38.94207655466052, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03899" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98080096162482, + 38.86424581581121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03900" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02003147510977, + 38.89232519721652, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H03901" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06426700595999, + 38.94045449089907, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/23/07

Report Problem", + "NAME": "H03902" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94701816806304, + 38.89410343029709, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H03903" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01225239256465, + 38.86606355011329, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H03904" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.012117532979, + 38.86539800467446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H03905" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02313279945245, + 38.89196242462637, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03907" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02376546437307, + 38.89196180216161, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Muelller

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03908" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98740892170207, + 38.879379976435274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/19/06

Report Problem", + "NAME": "H03909" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02021440176755, + 38.91642804618404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H03639" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98063121662285, + 38.89824276963699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03640" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03739949869475, + 38.91190599392193, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H03641" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98282288389858, + 38.89870385409001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H03642" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0389614784742, + 38.91464011754894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H03643" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9718437434898, + 38.89620212830783, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/08/08

Report Problem", + "NAME": "H03644" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02828119021994, + 38.91265469942714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H03645" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97696852582, + 38.896913560633564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H03646" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98301921993799, + 38.891959841567974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/15/06

Report Problem", + "NAME": "H03647" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98316287471619, + 38.90790310782094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H03648" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07008910339574, + 38.91257320447507, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03649" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0220419598844, + 38.89236167938233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03650" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02605409876183, + 38.914919678784116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H03651" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0220410988322, + 38.89304449600635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03652" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98846723544642, + 38.90071774474027, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H03653" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0450155056833, + 38.986431984549405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H03654" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07737144758829, + 38.9125746087927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, UNKNOWN

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H03655" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99016210125716, + 38.8994864211401, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H03656" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0685664874811, + 38.97414463957226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03657" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97732163172466, + 38.88545134908238, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/06/06

Report Problem", + "NAME": "H03658" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00189385896061, + 38.91265565640735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H03659" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01531647738463, + 38.91266766691569, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03660" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99146062492818, + 38.89835274907097, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/22/07

Report Problem", + "NAME": "H03661" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99632227998107, + 38.89667894325444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03662" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06969589736448, + 38.92354424519247, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H03663" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01317587490239, + 38.91403104240183, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H03664" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01321823864798, + 38.914782098541885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/05/08

Report Problem", + "NAME": "H03665" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98930899156106, + 38.89606840244226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H03666" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02991852688407, + 38.96608027027174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H03667" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99623514257868, + 38.89929725684337, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H03668" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98086774955685, + 38.89543659520728, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H03669" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05939719823994, + 38.93736314077285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/18/08

Report Problem", + "NAME": "H03670" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.992572321266, + 38.89269925581821, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H03671" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99368999608703, + 38.89421681732873, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H03672" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06204860798529, + 38.94210801739967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 12/19/06

Report Problem", + "NAME": "H03673" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97732142921282, + 38.887466415623784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/06/06

Report Problem", + "NAME": "H03674" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99851999834095, + 38.89253414296477, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H03675" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98702073677197, + 38.87756751740622, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 03/20/07

Report Problem", + "NAME": "H03676" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97619226841928, + 38.86553156673918, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06739" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97571177773297, + 38.86599735584727, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06740" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95395505577085, + 38.88967237753783, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H06741" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95601211207112, + 38.88958216769603, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H06742" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0257342955336, + 38.901365180338246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06743" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0793399357029, + 38.95482322452686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H06744" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01151128241311, + 38.96383945946481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06745" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0209775280849, + 38.90079746076288, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H06746" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02494205099968, + 38.900803527962424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H06747" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02685710766697, + 38.90094249872682, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06748" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08763583940052, + 38.95923725131862, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06750" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96779725523542, + 38.858067618875474, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H06751" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93391594052164, + 38.899137807634276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06752" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01997826848236, + 38.91423012545715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/25/08

Report Problem", + "NAME": "H06753" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00547560881265, + 38.84637883308082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H06754" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02439297733744, + 38.97948113049743, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06755" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02440662013707, + 38.980360888537334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H06756" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95477451931532, + 38.88367693562122, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H06757" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9536481212613, + 38.88764160564635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06758" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96462964466762, + 38.860166655668365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06759" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0408517845078, + 38.99374710161613, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H06760" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9755956911888, + 38.89856910900174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H06761" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95615373364924, + 38.88687019460337, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06762" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99463782613996, + 38.953091536231284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06763" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06645934937967, + 38.937416027920605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 03/08/07

Report Problem", + "NAME": "H06764" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01878735609293, + 38.91415425662246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H06765" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01998347678683, + 38.9131889140317, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06766" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0180741642603, + 38.91402962168495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H06767" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94252687115358, + 38.896887658020376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06768" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10211954219713, + 38.93777130054011, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06769" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94340512482906, + 38.90238856487108, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H06770" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0395358351307, + 38.89682850695422, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H06771" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97155970955157, + 38.90035182436649, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06772" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00000984760143, + 38.96004295725367, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06773" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93302287169982, + 38.88576873842303, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/16/08

Report Problem", + "NAME": "H06774" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00892011912906, + 38.90083947816433, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07197" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00894688005167, + 38.897743618199506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07198" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00939348519698, + 38.89769822603817, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07199" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0091771433557, + 38.90388729993978, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07200" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00899347692015, + 38.90013204620811, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07201" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00894785037569, + 38.89904613705559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H07202" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01782766257763, + 38.88744576275732, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07203" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95825889949046, + 38.91861289514262, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07204" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01892694196995, + 38.883384241899456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H07205" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01871752829672, + 38.88704923685434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H07206" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98702194377705, + 38.882780402581254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/26/06

Report Problem", + "NAME": "H07207" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0760866996656, + 38.93226364151522, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H07208" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07733033357897, + 38.93114472297318, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H07209" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07433804000576, + 38.932022037940236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H07210" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01503886054155, + 38.877600907692184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07211" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01073346648421, + 38.87723435373883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07212" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96680159991848, + 38.870595738904306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/10/08

Report Problem", + "NAME": "H07213" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04370720675433, + 38.99274652904947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07214" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03630310624884, + 38.90267650414809, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H07215" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.008040458826, + 38.95246531699045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07216" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01598044680377, + 38.87834588488748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07217" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01540541759621, + 38.878484862563035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07218" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97432436464165, + 38.84799496356251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/16/08

Report Problem", + "NAME": "H07219" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97311002954135, + 38.848328560921125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/11/07

Report Problem", + "NAME": "H07220" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0093318201568, + 38.90137860516174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07221" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91239327832523, + 38.894254690289245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07222" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91620274195222, + 38.89441105985491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07223" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91359566850382, + 38.89431823006889, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07224" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93384210812016, + 38.90368210438252, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07225" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9151337259828, + 38.89435100400987, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H07226" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01154222075427, + 38.877366835132634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07227" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99699340192487, + 38.954002266365585, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07228" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91900045070366, + 38.895873199959226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07229" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93786808494754, + 38.893322823693715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07230" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00999535557048, + 38.834449310180084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07231" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99755314306138, + 38.92094740941287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07667" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97135230860745, + 38.91753719035839, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07668" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97492738611184, + 38.90367021987711, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, eddy

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H07669" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04326853668506, + 38.91878644352333, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07670" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99014307800064, + 38.87547219959561, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/18/06

Report Problem", + "NAME": "H07671" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93765621558026, + 38.89183337460716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07672" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01677983744221, + 38.8730177022914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07673" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01887697985103, + 38.873455208423735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07674" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01640764249932, + 38.87633372868106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07675" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01159629528371, + 38.87936112579086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H07677" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01261033798694, + 38.87658511129462, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07678" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01233546547482, + 38.87936309496276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07679" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00944277407116, + 38.87633054483603, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07680" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05466802507115, + 38.902797777126835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07681" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0546644060393, + 38.90230258949338, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H07682" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05344022400106, + 38.902351296537745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H07683" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0563526613564, + 38.89719554228751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H07684" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00539260233548, + 38.836967351080574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07685" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03491034254026, + 38.96391870854372, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H07686" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97721122571765, + 38.882744758604666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 04/06/06

Report Problem", + "NAME": "H07687" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96274420677837, + 38.85721945898499, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/03/07

Report Problem", + "NAME": "H07688" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97803667181053, + 38.896984049594245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07689" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0415979436605, + 38.90487850636528, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07690" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99326421206962, + 38.917553371752454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H07691" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05396737998048, + 38.898283212361086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H07692" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0534704855882, + 38.898228309672355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H07693" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03755410254352, + 38.91743951244679, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H07694" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06017002561991, + 38.90270180948715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H07695" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98055268599259, + 38.85524640680752, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07696" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04766864729972, + 38.89608397483113, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07697" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04484972777144, + 38.89448203416388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H07698" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04444684838937, + 38.894130240194535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07699" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99164281106908, + 38.876616328836434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/10/06

Report Problem", + "NAME": "H07700" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04880336671062, + 38.896089649990614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/28/07

Report Problem", + "NAME": "H07701" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0379773301635, + 38.899475870010406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/04/08

Report Problem", + "NAME": "H08105" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97894392208693, + 38.88988682881371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H08106" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98165412357774, + 38.862557829894975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08107" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9147522190026, + 38.88963372475377, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08108" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91654995106566, + 38.88963548236685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/05/06

Report Problem", + "NAME": "H08109" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02421339881987, + 38.88333321499806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08110" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02421108343869, + 38.88462760318923, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08111" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91631701038018, + 38.88755314567799, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant,

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08112" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01386833571942, + 38.82122451049569, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H08113" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01373901775405, + 38.822126697690344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H08114" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93686756980581, + 38.891976634589106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08116" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00495907837568, + 38.880452620386954, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08117" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03451993866423, + 38.96030260517449, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08118" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91736596444753, + 38.88840732851712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08119" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05577166845528, + 38.8939583760691, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08120" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01186173359831, + 38.88752855127196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08121" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06602071262793, + 38.904456359945804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08122" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91502224180435, + 38.888557456157436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/07

Report Problem", + "NAME": "H08123" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91408993993186, + 38.88929839807364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H08124" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03037041539007, + 38.893085867578534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08125" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00055785842466, + 38.95940107255572, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H08126" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02499525397063, + 38.9148842911261, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H08127" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02408329066122, + 38.914723359574246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H08128" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00924159351723, + 38.90863474849086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/28/07

Report Problem", + "NAME": "H08129" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05453300132713, + 38.897308343842006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H08130" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98156112121428, + 38.93715530917865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08131" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03655346529241, + 38.93627169387359, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H08132" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06182094754568, + 38.92834710097888, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 01/17/07

Report Problem", + "NAME": "H08133" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04092863613873, + 38.92393933632943, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08134" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0221265819427, + 38.898539817011454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08135" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02271292907197, + 38.89836079842859, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08136" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02406975777616, + 38.898062404027264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08137" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02084117174662, + 38.87633543588754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08138" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97300181603889, + 38.859527393050946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08139" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01374574817113, + 38.88377595751544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08140" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99840104160103, + 38.95365818727558, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06702" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99721094891771, + 38.952651535941946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H06703" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99880649925983, + 38.95261883607398, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H06704" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00232570456356, + 38.954843158538196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06705" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00114517405473, + 38.95480814291553, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06706" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0005142660758, + 38.954252031074866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06707" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99167780726519, + 38.890480109195764, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/22/06

Report Problem", + "NAME": "H06708" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95310858880491, + 38.858883995619365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/27/07

Report Problem", + "NAME": "H06709" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02173224424004, + 38.919954660636435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H06710" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98307754778058, + 38.86721708826973, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06711" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0585309713972, + 38.92188727193555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/02/06

Report Problem", + "NAME": "H06712" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99959727710178, + 38.90865930069435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06713" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9974288222908, + 38.88765148607277, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H06714" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98814650876594, + 38.88606472645686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/09/06

Report Problem", + "NAME": "H06715" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95402279913114, + 38.88995550144341, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06716" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95558173450337, + 38.88995358231732, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06717" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02013062656702, + 38.90424171993253, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H06720" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02491135204471, + 38.904239492161786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06721" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04274884712204, + 38.9466990842324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H06722" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01884121146134, + 38.90432045178427, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/13/07

Report Problem", + "NAME": "H06723" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97638676191636, + 38.87314917819528, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06724" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94714033787068, + 38.899418538210234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/30/07

Report Problem", + "NAME": "H06725" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93553230448904, + 38.9109076910083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06726" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07078422439486, + 38.96085470511081, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06727" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03661697939123, + 38.98735629283935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06729" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03906193377343, + 38.986262689053405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06730" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03795766048816, + 38.98708403377112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06731" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01084131188746, + 38.96635609459757, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06732" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93787036223503, + 38.90860321777128, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06733" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9904958233762, + 38.95619927788162, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06734" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95099574866201, + 38.865689411630726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06735" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9389755508876, + 38.907339838995775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06736" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93984986018565, + 38.90535541954279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06737" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93925528624392, + 38.900397255202975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H06738" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09254635127105, + 38.9486973026342, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07232" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93382327899475, + 38.90474118788292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07233" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92157933552461, + 38.89424472400106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07234" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9851538135623, + 38.91911475703648, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07235" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98330231947256, + 38.91924845195794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07236" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97892835332335, + 38.855296644203406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07237" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96679766606418, + 38.86961438004594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H07238" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96679581303398, + 38.86777686242704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07239" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0636452801437, + 38.948887919837276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07240" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9666680627454, + 38.86867883801794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07241" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93226220888265, + 38.89755675743699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H07242" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93130172420881, + 38.89710167047263, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07243" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01967362915791, + 38.95321598453066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H07244" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97550798565447, + 38.84743397409999, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H07245" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00887822824681, + 38.87539174302792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H07246" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99623315117327, + 38.9012061819032, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H07247" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00606339758599, + 38.9071935853177, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07248" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92804164672515, + 38.88152634767735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07249" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05344021828674, + 38.900758663977086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H07250" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99724158304521, + 38.901266187703385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H07251" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99826064706298, + 38.90127459410005, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H07252" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00751400965916, + 38.946484469770624, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07253" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9737727225967, + 38.890777566180994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 02/23/07

Report Problem", + "NAME": "H07255" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0108679583866, + 38.887530602783514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07256" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99075291491035, + 38.93062772081035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H07257" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97399120404835, + 38.89240987804229, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/23/07

Report Problem", + "NAME": "H07258" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00881961020227, + 38.87758203077894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07259" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00930522065583, + 38.878462725693296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H07260" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00937235300053, + 38.87469652635012, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07261" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00944827614639, + 38.877586476799294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07262" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98342357713578, + 38.876706706480256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 10/18/06

Report Problem", + "NAME": "H07264" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98676341517982, + 38.876578961326985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 01/04/08

Report Problem", + "NAME": "H07265" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03642312919904, + 38.904976362366526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07266" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9853565847851, + 38.87652116669425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/06/07

Report Problem", + "NAME": "H07267" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0465514278772, + 38.896150438687805, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07702" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04368932293251, + 38.89529565927772, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/22/07

Report Problem", + "NAME": "H07703" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04442034926468, + 38.894170499666586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H07704" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04572986746048, + 38.89496064083354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H07705" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0448323779181, + 38.89614923733559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/22/07

Report Problem", + "NAME": "H07706" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9840155149534, + 38.86390963763843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07707" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98277500179164, + 38.863687421809345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07708" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09010290543684, + 38.90907642652341, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H07710" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93017148673826, + 38.88066259171604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07711" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03931769336532, + 38.90619250627998, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/04/07

Report Problem", + "NAME": "H07712" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98856490722186, + 38.85682458078639, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07713" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99582352528398, + 38.91202241001932, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H07714" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99046222038285, + 38.874682216628244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/18/06

Report Problem", + "NAME": "H07715" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94784720320794, + 38.90443724934308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07716" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95246022829865, + 38.90508292730649, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07718" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98912704057659, + 38.83079641789728, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/11/07

Report Problem", + "NAME": "H07719" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98999498305183, + 38.82999721053814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H07720" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01290430053886, + 38.873833184843015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07721" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93653748617665, + 38.89820879639172, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07722" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05433234478356, + 38.94348155986243, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H07723" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03436247298768, + 38.94903956155696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H07724" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09724558516685, + 38.92929154082307, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H07725" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05600337284044, + 38.900825143175915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H07727" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05597990398972, + 38.90219493827348, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07728" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.977988540688, + 38.9068194262826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07729" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9916561781167, + 38.85849224792853, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H07730" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9312637752667, + 38.89181323054132, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07731" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0554934718497, + 38.89327835858064, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H07732" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9873343554735, + 38.85198215279726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H07734" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0662298132155, + 38.91180775590383, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07736" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93084474132424, + 38.88057317864063, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H07737" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06628176841052, + 38.910815781826415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H07738" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0662008800927, + 38.909828224911614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H07739" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99270593709383, + 38.89106001988396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H07740" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03664588377005, + 38.901615708286606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08141" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92780039612224, + 38.88707814832078, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08142" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04151322791029, + 38.908898493871376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 10/12/07

Report Problem", + "NAME": "H08143" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04028346416186, + 38.908630196396956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08144" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03736201545385, + 38.907616178766666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08145" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03834930200641, + 38.90795714009193, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08146" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05735174646733, + 38.93023071146079, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H08147" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99267277976033, + 38.8607069825124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H08148" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00131375632988, + 38.88610450699817, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H08149" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0007573019991, + 38.886754268371845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H08150" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95602339297108, + 38.900677003252326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08152" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95722838637901, + 38.90062352660191, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08153" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9934376085016, + 38.91525068088991, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08154" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06049710038423, + 38.90977916810914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08155" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02284487258444, + 38.89622084505351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08156" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02246245935183, + 38.980433010542164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 09/12/06

Report Problem", + "NAME": "H08157" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01339550515529, + 38.89345469727164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08158" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00209402051352, + 38.830854568763904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08159" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01462246845327, + 38.891447097778624, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08160" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00926931424503, + 38.868295433385356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H08161" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92456958859614, + 38.89604421417688, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H08162" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02424766072127, + 38.935145217729044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 01/02/08

Report Problem", + "NAME": "H08163" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94202236269832, + 38.90861666634091, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08164" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0172963812285, + 38.890654725306696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08165" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00074023920943, + 38.886346387055426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H08166" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05812501222938, + 38.93557330871181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/10/07

Report Problem", + "NAME": "H08167" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04456499397594, + 38.911074677276005, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08168" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95381372360585, + 38.85834333883947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/26/07

Report Problem", + "NAME": "H08169" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00755524231829, + 38.90570537332664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08170" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00880649602487, + 38.90569611521218, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H08172" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00572081136154, + 38.905719260326336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/04/07

Report Problem", + "NAME": "H08173" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01340079016845, + 38.902443942775804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08174" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04240553327146, + 38.90126458670531, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08175" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95565860108124, + 38.85691093069084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/21/07

Report Problem", + "NAME": "H08176" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93171236515379, + 38.88551644748906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/07

Report Problem", + "NAME": "H06775" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07997674543732, + 38.961032367081344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06776" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93561081739895, + 38.88600962758285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06777" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05931200835049, + 38.90982979904883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H06778" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10244670460115, + 38.93988473964499, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H06779" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03091852572004, + 38.88608572947236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H06780" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03035854074379, + 38.88609295695204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H06781" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01822966368945, + 38.92886967524745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/20/07

Report Problem", + "NAME": "H06782" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95941927170149, + 38.91845287454123, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06783" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04338693484873, + 38.90467721268086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06784" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02966817634758, + 38.899743058400354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06785" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07469621511788, + 38.93910692946605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06786" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05744155687229, + 38.96314680294454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06787" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00579436256669, + 38.888774120746874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06788" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95380719997834, + 38.87396028435545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06789" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01650694641194, + 38.97397167263155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06790" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94350489538657, + 38.903783169603216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06791" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97268359089284, + 38.922408914627795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H06792" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95114901816872, + 38.89247950822375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US pipe

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06793" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99157703651174, + 38.955543577165905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06794" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04437285473905, + 38.94515082911551, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H06795" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97891349259542, + 38.843241253842216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H06796" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93930316910527, + 38.8794846133168, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06797" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0886893672408, + 38.94138019415723, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/10/07

Report Problem", + "NAME": "H06798" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0980655268222, + 38.95115875666244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H06799" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05549341051372, + 38.984084077342835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H06800" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0526978139392, + 38.97704680578762, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H06801" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0035409833462, + 38.82825590688537, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06802" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98235268411509, + 38.89207209518024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H06803" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98093008033639, + 38.89206613326344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H06804" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97833887260107, + 38.91527651301537, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H06805" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05682587062851, + 38.97885234639924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H06806" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04295758729371, + 38.926561641107796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/23/06

Report Problem", + "NAME": "H06807" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98199379578354, + 38.919101025555314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06808" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03549478026815, + 38.901479082619964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08177" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0092827879668, + 38.902604736306714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08178" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04150093609918, + 38.90126745191087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08179" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99350386421665, + 38.92752398463641, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H08180" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99355669919886, + 38.92658690672346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H08181" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03959123380503, + 38.89742481485953, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08182" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04419249618404, + 38.90140050011229, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08183" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92182074154292, + 38.899207829429145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H08184" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92120249374817, + 38.900071739400516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08185" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02363245136844, + 38.88123143409648, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08186" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02225212129427, + 38.88135470577844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08187" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0416078282054, + 38.902217507242085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08188" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9207012937859, + 38.89904467214268, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08189" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00758525140215, + 38.90569406590387, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08190" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00025186288822, + 38.92305260761414, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08191" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9972408231606, + 38.92448807802464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08192" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03995315557866, + 38.93535159953509, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H08193" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01358784632926, + 38.89290682205701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08194" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04051846792657, + 38.8964255864395, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H08195" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01494671207605, + 38.90258946535637, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08196" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93050311745522, + 38.90002479938208, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08197" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09320065072461, + 38.92114763836906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08198" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03831158173872, + 38.9014610409353, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H08199" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03748416543611, + 38.90146517393015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08200" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02119456986291, + 38.89365163659758, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08201" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02906451894086, + 38.888715003678044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08202" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92756634578595, + 38.9047109646528, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08203" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92740591776794, + 38.90597091741606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H08204" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03182204114798, + 38.91197219079815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H08205" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03209063664018, + 38.91712557874504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08206" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03210336684512, + 38.90895414811679, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08207" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99123696917337, + 38.86205485832162, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08208" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04566521114579, + 38.90863023480223, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08209" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99958465694297, + 38.89002489648742, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/22/06

Report Problem", + "NAME": "H08210" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0438685423126, + 38.991540667148115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08211" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92215662292064, + 38.901056983892204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08212" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05264919204835, + 38.89643309950491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H08213" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05557594075515, + 38.94970435584497, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/20/08

Report Problem", + "NAME": "H08214" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04313662915926, + 38.90875583518156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08215" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01744375663698, + 38.88549660543028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08216" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03081125628373, + 38.90141181307621, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08217" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03336025786113, + 38.977209204283, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08218" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01929184680138, + 38.94215128765235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08219" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02857666736612, + 38.934475904627455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/11/07

Report Problem", + "NAME": "H08220" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03931652931746, + 38.90154979970365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08221" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04534624867802, + 38.92793162400314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/09/06

Report Problem", + "NAME": "H08222" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0463193741046, + 38.929753137432066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/09/06

Report Problem", + "NAME": "H08223" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01351392151345, + 38.86472204025098, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, A.P. Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H08224" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05338534483874, + 38.89968216306236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H08226" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08392436344513, + 38.93520806434547, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08227" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0137510566863, + 38.868501266149224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H08230" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02236734369201, + 38.87872401757323, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08231" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02686660091739, + 38.9057012853849, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/24/07

Report Problem", + "NAME": "H08232" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01223179441675, + 38.90273073486977, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08233" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01223631934823, + 38.903637686407194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08234" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01631002904152, + 38.907182154548025, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08235" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99957175775653, + 38.90362408420953, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H08236" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0196865787712, + 38.887694302678234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08237" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01712937463928, + 38.88769284095378, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08238" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05325998845386, + 38.974429858512536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H08239" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05451519215418, + 38.97400137106152, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08240" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02141160033958, + 38.9025904232028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H08241" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01773654470381, + 38.90138746860893, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08242" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02423988131991, + 38.91253429240804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H08243" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01626198843816, + 38.901224676959394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08244" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97312474257745, + 38.88525611195604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08245" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99793329869803, + 38.87658623326196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/16/06

Report Problem", + "NAME": "H08246" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00578083068814, + 38.885218820420974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H08247" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0672432194845, + 38.97200398815426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H08248" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01999553121911, + 38.92114513258771, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08249" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00472236749316, + 38.885007594424685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/07/07

Report Problem", + "NAME": "H08250" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03071004240493, + 38.91339480588025, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08251" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02971018132025, + 38.91326958726182, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H08252" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02427706527385, + 38.912565219321955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08253" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03834107114176, + 38.95707617833018, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H08254" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00293472570456, + 38.925205297973406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/28/08

Report Problem", + "NAME": "H08255" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9758817182945, + 38.882693774413184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H08256" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01979363064866, + 38.897860590742205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08257" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03326918376025, + 38.91043142449036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08258" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93674142079028, + 38.890259092651476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08259" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02413260889021, + 38.913400187017174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H08260" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02584994353063, + 38.91337647010082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/08/07

Report Problem", + "NAME": "H08261" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01210857023432, + 38.869347977064805, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H08262" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00927794074641, + 38.89511931173586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08263" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00896262042976, + 38.8960392256087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08264" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01511786062102, + 38.96854741563351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H08265" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98952692870112, + 38.91281293838704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/28/07

Report Problem", + "NAME": "H08266" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98551208205598, + 38.92471905963108, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08267" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07949187356242, + 38.93323857834559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08268" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01583620541501, + 38.87752262745055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08269" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99513327070656, + 38.93132925498553, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08270" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04649363470668, + 38.89357737456082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H08271" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01230137266033, + 38.92634611310559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H08272" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01013885360227, + 38.926591229778545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H08273" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01398335499461, + 38.92621440255582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/10/06

Report Problem", + "NAME": "H08274" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01532220622806, + 38.92688260660708, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08275" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02405292872156, + 38.8944090110871, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08276" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02406840229555, + 38.89565075720782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08277" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02490264297842, + 38.89603614939658, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08278" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00510950552537, + 38.873082494450905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08279" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99606942549883, + 38.93299883544605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08280" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.984790676523, + 38.90043212834989, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H08281" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06743986700921, + 38.936163150493876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/06/08

Report Problem", + "NAME": "H08282" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05517856338699, + 38.93414474992192, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/27/06

Report Problem", + "NAME": "H08283" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01373964756537, + 38.89489005965317, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08284" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95138380039576, + 38.88833419518425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08285" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95157623961008, + 38.88941006457362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08286" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0428356429657, + 38.92247281884923, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H08287" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01532574724511, + 38.90230944559513, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08288" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94464310550777, + 38.90652417217478, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08289" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02606368145655, + 38.91274468592601, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H08290" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9403631158589, + 38.90950012644815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08291" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98558416828085, + 38.89660300893139, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08292" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98692181841473, + 38.896762317109065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08293" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07853351345675, + 38.96102858898315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H08294" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04474272033883, + 38.919258717509656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H08295" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04536119029878, + 38.91837010471332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/25/06

Report Problem", + "NAME": "H08296" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98821772840788, + 38.94636344257222, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08297" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98822205775481, + 38.94711051769654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08298" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00207792724254, + 38.82319824431888, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H08299" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00374368104323, + 38.83209246142694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08300" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0745179419083, + 38.92233686601356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08301" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00137767016994, + 38.88861960954308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/31/06

Report Problem", + "NAME": "H08302" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03954898450759, + 38.90482729379108, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08303" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03870626477836, + 38.90481002775378, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08304" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00415039685, + 38.887707932173186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08305" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03084566274906, + 38.91414191257845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08306" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02971224774062, + 38.913967498614944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H08307" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9892134418145, + 38.87402078337386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/12/06

Report Problem", + "NAME": "H08308" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92179076001224, + 38.89728089314876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08309" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03350578907524, + 38.90972104906031, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 10/25/07

Report Problem", + "NAME": "H08310" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03074528355717, + 38.89724948166159, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H08311" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96362156871533, + 38.850699911071544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H08312" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96257937013323, + 38.85150873728961, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08313" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0113459515883, + 38.9013182150612, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H08314" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0160661789324, + 38.91755385770648, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08315" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01510686781566, + 38.8923022999448, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08316" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99055525683777, + 38.87335822368137, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/10/06

Report Problem", + "NAME": "H08317" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98222824471678, + 38.83619910675699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/17/07

Report Problem", + "NAME": "H08318" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96254275137659, + 38.926826639313255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08428" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96280426767339, + 38.925778650334095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08429" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9613028254853, + 38.92613610827265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08430" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9392726023663, + 38.89175677212225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/08/07

Report Problem", + "NAME": "H08431" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02083652520874, + 38.884773856446024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/03/07

Report Problem", + "NAME": "H08432" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02679516929125, + 38.97648061376269, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08433" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98696072061638, + 38.908576156445044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08434" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96481506894972, + 38.84973311316996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H08437" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99698155188067, + 38.94559483426475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08438" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99840611729657, + 38.945426704764486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08439" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02605733788842, + 38.90977280878796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H08440" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02587864211371, + 38.9110871926042, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H08441" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97718498973083, + 38.88679479636077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/06/06

Report Problem", + "NAME": "H08442" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00381412784823, + 38.87470687551057, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08443" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02605383574824, + 38.90848666127305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08444" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02591163873204, + 38.90711401011605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08445" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97489749027639, + 38.927786358732135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H08446" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97370627688652, + 38.92776132393991, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H08447" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03900908895159, + 38.903847997163304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08448" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98381084491167, + 38.881325570503094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/17/06

Report Problem", + "NAME": "H08449" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02423415194802, + 38.920817517456605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H08450" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10248470261361, + 38.923019930141635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08452" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0150670437515, + 38.895202360187156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08453" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0197770001507, + 38.894299667958826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08454" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01968850613716, + 38.893676231752664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08455" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00790620159373, + 38.89677353762276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08456" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09146094765984, + 38.916366471316195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08457" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9949765650847, + 38.8387182415587, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H08458" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99184322048237, + 38.882666954785755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/06

Report Problem", + "NAME": "H08459" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99279589759597, + 38.88266990912566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/06

Report Problem", + "NAME": "H08460" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03808518129945, + 38.8964851216087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08461" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95899268806791, + 38.927475865897996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08462" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95952451906204, + 38.92641322328298, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08463" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95816678847049, + 38.92822525403737, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08464" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95856004768567, + 38.92774257557982, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08465" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97874310067432, + 38.83891656384935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08320" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98090804420679, + 38.83722066429693, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H08321" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04477094130978, + 38.93428994564243, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H08322" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98439807816389, + 38.85959801716119, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08323" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08455634619834, + 38.95874907307745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08324" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05050700205177, + 38.89719671153101, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H08325" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03434068464448, + 38.91109067822516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08326" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03318859323646, + 38.91118194134541, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H08327" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02799335021693, + 38.89720467227648, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08328" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02817944809317, + 38.897510533529406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08329" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02798523689899, + 38.89750416626152, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08330" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02971165071288, + 38.898224859335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08331" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0278904743096, + 38.89840758351679, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08332" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98845940621565, + 38.88277003166853, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/28/06

Report Problem", + "NAME": "H08333" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00522213820375, + 38.90991302897518, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08334" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04055172817277, + 38.90139941536408, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08335" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06645356958478, + 38.922527824070826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08336" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06502920837417, + 38.92272326820528, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08337" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06543401109026, + 38.92333855392444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08338" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98689992846845, + 38.85620339196964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H08339" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98555681399935, + 38.857141091752496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08340" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01898043308506, + 38.91272105309525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08341" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04501646204457, + 38.89529116468103, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H08342" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98816471194674, + 38.837750818319385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08343" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02619707222384, + 38.898391445191194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08344" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02381303904498, + 38.898532792202516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08345" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9883786746581, + 38.879420011156185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/27/06

Report Problem", + "NAME": "H08346" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02283404670345, + 38.897080569409574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08347" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02206304492873, + 38.89710260789232, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08348" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0169171448239, + 38.97330557233673, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H08349" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04337971467226, + 38.906529998821355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08350" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03295321706722, + 38.92350394493053, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/21/06

Report Problem", + "NAME": "H08351" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03285151529943, + 38.92267544224298, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08352" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02172945583831, + 38.911068246585344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08353" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02097298162155, + 38.91125199281655, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08354" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00716575264279, + 38.90718151478236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08355" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0145768195112, + 38.896003203035555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08356" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98768896734745, + 38.83681138550871, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08357" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98928491590188, + 38.879224579692156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/16/06

Report Problem", + "NAME": "H08358" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98837899611085, + 38.88112601104574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/05/07

Report Problem", + "NAME": "H08359" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01403141657126, + 38.90379759906298, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08360" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96326847348543, + 38.880678366073994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08362" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9825575519487, + 38.92894088897529, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08363" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94577625936975, + 38.86921353709764, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08364" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94703477273785, + 38.8683998085889, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08365" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9563895304164, + 38.92728647858071, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08366" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95998785756807, + 38.92908739259746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08367" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04025982788481, + 38.903890200379095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H08369" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92332854926619, + 38.89953523775674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08370" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03443405457999, + 38.9014902821746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H08371" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03354155308863, + 38.90123515490904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08372" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02204435392741, + 38.884068467473675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08373" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98899509108924, + 38.8612038684665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08374" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91974324070002, + 38.89917079258774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08375" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0326395003206, + 38.90123053689111, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08376" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01829311716507, + 38.89196076946774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08377" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03347096524197, + 38.90140821668236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08378" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01384898174817, + 38.8851367246785, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/04/07

Report Problem", + "NAME": "H08379" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01063685948301, + 38.9057054847332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08380" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99460350852914, + 38.909909138456875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08381" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99551978574854, + 38.909654691506766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08382" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.032102210849, + 38.90121111060677, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08383" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03217864309157, + 38.90141339025018, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08384" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96375080281416, + 38.924997377139746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08385" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9898512889259, + 38.83379076058705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H08386" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0228134302436, + 38.88491735091642, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08387" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02822365104687, + 38.89621301216608, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08388" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02825521358331, + 38.89481603216257, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08389" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01470054031982, + 38.91768706349387, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08390" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02011984858905, + 38.897421323292384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08391" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01456811375331, + 38.90863579123086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H08392" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0526693576068, + 38.913784905295614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08393" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98853372608112, + 38.86072686429535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08394" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99485835521703, + 38.93352980089793, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08395" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02089442069115, + 38.89725620816021, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08396" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99504121148979, + 38.89286552808492, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08397" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9963869020058, + 38.89239424150939, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H08398" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00009277077737, + 38.960240183984304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H08399" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03472186902212, + 38.901528500520605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08400" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04035226386559, + 38.91884498711813, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08401" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09758322381626, + 38.91781397793509, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08402" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00076633215748, + 38.87758588357054, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08403" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09665497285758, + 38.91737221497994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08404" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96086351700934, + 38.92771938951734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08405" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96185308264808, + 38.926848792888386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08406" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96094253819084, + 38.92706797972132, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08407" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9619430855142, + 38.924185378131774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08408" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00471748575956, + 38.894848162840894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08409" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00336797377814, + 38.89525374818417, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08410" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99801097628497, + 38.946349092688955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08411" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99845883958635, + 38.947335470064644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08412" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99770476850875, + 38.94720454937909, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08413" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01016547589707, + 38.903815457590504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08414" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01624662809736, + 38.89599123582937, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08415" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01129772563324, + 38.90384923399925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H08416" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01222011013053, + 38.92120324505646, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H08418" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96200971460257, + 38.92475458143464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08419" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96402536763, + 38.92594683051196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08420" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9621355275832, + 38.927497267175745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08421" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96258566163135, + 38.92368791198445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08423" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96036446401986, + 38.92427438707619, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H08424" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96369466263668, + 38.92576998507413, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/22/07

Report Problem", + "NAME": "H08425" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9625030277677, + 38.9255432928641, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08426" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96309268978209, + 38.9267188225985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08427" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95689856788752, + 38.92864146368962, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/15/07

Report Problem", + "NAME": "H08466" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95970909884488, + 38.924449050474934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/07/07

Report Problem", + "NAME": "H08467" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95726784464247, + 38.92814826806567, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/07/07

Report Problem", + "NAME": "H08468" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95984502892284, + 38.92534896520106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08469" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08638710577023, + 38.93462981066992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H08470" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02798760970032, + 38.89365008944466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/15/08

Report Problem", + "NAME": "H08471" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02836423520479, + 38.89196439736748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/15/07

Report Problem", + "NAME": "H08472" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02826522843692, + 38.89236599654917, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08473" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02826125937592, + 38.892938407398994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08474" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06318425130685, + 38.944293495447674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08475" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0573447641172, + 38.93383851487389, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/27/06

Report Problem", + "NAME": "H08476" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94637204663934, + 38.89843839358465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08477" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94616299994543, + 38.898971673545276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H08478" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02847482355152, + 38.911745638926384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H08479" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02875439842148, + 38.91095659298035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H08480" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03812996010343, + 38.89634445038992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08481" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08658881613316, + 38.95998389743036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08482" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92255226785032, + 38.898665229480834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08483" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02182938574424, + 38.8974671481761, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08484" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02204448311844, + 38.899259240202056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08485" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97922669310609, + 38.919809755946844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08486" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98449915185869, + 38.84439894866785, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08487" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97208616208393, + 38.928242145248376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08488" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05459880699436, + 38.94173242238124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/20/06

Report Problem", + "NAME": "H08489" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97510623589379, + 38.87412643178905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08490" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97512818899816, + 38.89879257990533, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H08491" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02859860157034, + 38.88768369546333, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08492" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02822972218756, + 38.88667732401562, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08493" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00432219533818, + 38.84966108808251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08494" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05497110319803, + 38.95221189678646, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08495" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00622271852494, + 38.90147398542171, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08496" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01626838110322, + 38.89159573448617, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/17/07

Report Problem", + "NAME": "H08497" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99732923533367, + 38.88520448349828, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/01/07

Report Problem", + "NAME": "H08498" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99744155044182, + 38.884990005440564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H08499" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98711293458845, + 38.881325477069744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/19/06

Report Problem", + "NAME": "H08500" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03100176511474, + 38.91107117192213, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H08501" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.029718354384, + 38.91127255354978, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/07/08

Report Problem", + "NAME": "H08502" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00579074823631, + 38.89494169348083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08503" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99708905931759, + 38.944563721900295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08504" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99780241534405, + 38.94433857542791, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08505" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0432831916959, + 38.9148896048663, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H08506" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04329924046024, + 38.91562729143581, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08507" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04336543084449, + 38.91328248714605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08508" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04336294928191, + 38.91420757221476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08509" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00467641774055, + 38.955577477958514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H08510" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01676421713123, + 38.97492892271481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08511" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00094005175632, + 38.952682427762525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08512" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00111515709453, + 38.95275324023068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08513" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0046655435606, + 38.95495466495944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08514" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97800595108619, + 38.841120966288855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08516" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92790991157297, + 38.88776816789205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 02/28/08

Report Problem", + "NAME": "H08518" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92981760872138, + 38.888724920649125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08519" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93041850895601, + 38.88594005981671, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08520" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97168509423048, + 38.85692322325186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08521" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9269147821931, + 38.8814460948615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08522" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92996967614468, + 38.88805560823569, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08523" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03181107669249, + 38.90145226288173, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/21/08

Report Problem", + "NAME": "H08525" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02006637347118, + 38.88882305079976, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08526" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02685913709283, + 38.89041123219989, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08527" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03036355406417, + 38.888691909048134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08528" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92575333584115, + 38.88681264016373, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/03/07

Report Problem", + "NAME": "H08529" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92903683068647, + 38.881683576463125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08530" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0376211413675, + 38.96128358441223, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08531" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98387172945833, + 38.8553852639279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08532" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9482544365408, + 38.88915211769327, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08533" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99043433811318, + 38.86019398022922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08534" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93534554685658, + 38.904581087974115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08535" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93597316733936, + 38.90601041048936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08536" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95496542205478, + 38.864111889116856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/03/08

Report Problem", + "NAME": "H08537" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97360608449723, + 38.858177709127055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08538" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99010971881326, + 38.83154461312445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06304" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99158447120384, + 38.84400563613905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 02/21/08

Report Problem", + "NAME": "H06305" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99650063765533, + 38.82731645106532, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06306" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9942613489853, + 38.85891046792447, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H06307" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9424613941558, + 38.87942205420123, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06308" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94318930617003, + 38.880100904643065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06309" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00094198954898, + 38.95876499697013, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06310" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99793491978788, + 38.824950095276236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06311" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99772070099907, + 38.82556903633247, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06312" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0000479654624, + 38.95502742771825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06313" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99654653064003, + 38.948286640332384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06314" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00131907759724, + 38.95697461055816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06315" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96467675990772, + 38.873105370179346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/09/06

Report Problem", + "NAME": "H06316" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9513462421715, + 38.86993561831918, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06317" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06008266147673, + 38.90404294626886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06318" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96223514638304, + 38.87188215688112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06319" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03984973394303, + 38.905599108174734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06320" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99797795290505, + 38.96087385228594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06321" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00292127032174, + 38.959335141986934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06322" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0029134179376, + 38.95860702266086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06323" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.959429989507, + 38.871193757676636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/09/06

Report Problem", + "NAME": "H06324" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08621657401493, + 38.941646176336384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/14/07

Report Problem", + "NAME": "H06325" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0060432725119, + 38.82914523706379, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06326" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97975742844228, + 38.907449627792346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06327" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05602825092163, + 38.959417683301226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06328" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09058080915013, + 38.94488207705248, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H06329" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92994923586132, + 38.87848045455763, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06330" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92997035249158, + 38.879522179931946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06331" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95678689031837, + 38.89197872047685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06332" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96668122823594, + 38.92563092149949, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H06333" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98107604350997, + 38.84970423505059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H06334" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95761052706486, + 38.885276744294536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/10/08

Report Problem", + "NAME": "H06335" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9689828986322, + 38.85529060601268, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06336" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10319215143784, + 38.937125373112885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06337" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96025208313756, + 38.87751710826846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06338" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10199165846161, + 38.94207491012106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/09/08

Report Problem", + "NAME": "H06809" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93188206066793, + 38.889632854120734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06810" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04354367039312, + 38.99020962857461, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06811" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04431139193487, + 38.98497449063176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06812" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05259754131637, + 38.89962876752536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H06813" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08112630706023, + 38.9067914243098, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06814" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97907583196913, + 38.90427153327567, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H06815" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93903046883437, + 38.89978244361404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06816" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97909581360963, + 38.90103858259027, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H06817" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97935427625308, + 38.89961572234665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H06818" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0498815307086, + 38.91266203218983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H06819" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05524152681508, + 38.966256015539265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06820" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9791653098176, + 38.90501399955406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/29/08

Report Problem", + "NAME": "H06821" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97916724142279, + 38.9037688565339, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H06822" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97915266357276, + 38.90256463524427, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, USP

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06823" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97890899180648, + 38.90175636187868, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H06824" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.950614591531, + 38.90207286702679, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06825" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93277440125377, + 38.89183110849277, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06826" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93397222830615, + 38.891781056551544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06827" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08344901069415, + 38.96247001853708, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06828" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99794042749807, + 38.84321258359658, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06829" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00211459104457, + 38.8791159604665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H06830" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9777128015119, + 38.90233239529218, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H06832" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98036613862679, + 38.90127756047794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H06833" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04581257261422, + 38.942667049608396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H06834" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93061566693929, + 38.8981998981573, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06835" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00197923389352, + 38.88001350485407, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H06836" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00218617108085, + 38.878343606629706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H06837" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00074163014447, + 38.87933638556729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 11/10/06

Report Problem", + "NAME": "H06838" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98829182615815, + 38.912835648282005, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H06839" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99682697263924, + 38.91014814825445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H06840" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9932680535277, + 38.91057318212014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06841" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06492180613985, + 38.903931743686734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H06842" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99607692273177, + 38.84348248291928, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06843" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06799562489095, + 38.90967835835896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/08/07

Report Problem", + "NAME": "H07268" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97288442106708, + 38.874268999431315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07269" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1057971046107, + 38.92774309571597, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H07270" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9718932464032, + 38.87758487310338, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07271" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97102071397458, + 38.87902117427944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07272" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93505601398128, + 38.883847091875765, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07273" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0172380791555, + 38.82272044132549, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07274" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05588598026421, + 38.93690658413924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/18/05

Report Problem", + "NAME": "H07275" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99827184749294, + 38.91957081503366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07276" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99166522071086, + 38.898960666041795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07277" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.992527170893, + 38.89896296744019, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H07278" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04337789329506, + 38.90362982387168, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07279" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0279766083476, + 38.88343885332378, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H07280" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00049927276746, + 38.83139627437486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07281" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99473614256651, + 38.89153822135641, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/04/06

Report Problem", + "NAME": "H07282" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01433752866193, + 38.87935951522073, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07283" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01998269109451, + 38.87742059309258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/21/08

Report Problem", + "NAME": "H07284" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01913810912403, + 38.87834478854834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07285" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01998414816177, + 38.878508275290706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07286" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03124438213845, + 38.97214077611694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H07287" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09438902912585, + 38.93248178929561, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H07288" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98649905520308, + 38.932808217717465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07291" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97412070698806, + 38.88402778257524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H07292" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93814038792657, + 38.876428562683174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07293" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95743452962736, + 38.885872710903186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/07/08

Report Problem", + "NAME": "H07294" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02796855055394, + 38.881700353750524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07295" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03114521856557, + 38.882812887396334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07296" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03087176449948, + 38.88312784813139, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07297" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03925445444915, + 38.982948349912874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07298" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98375852939992, + 38.91475560227307, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H07299" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93392357053568, + 38.90612145930246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07300" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01884523396411, + 38.89598159392819, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07301" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95132071266752, + 38.873913376547904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07302" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95287539677435, + 38.87454847589481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07303" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91649170986268, + 38.893011248621335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H07304" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01342033836507, + 38.878461757788635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07741" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92526210004631, + 38.88185626399039, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/22/08

Report Problem", + "NAME": "H07742" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93281190286608, + 38.90613430179411, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H07743" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05263459899241, + 38.89868417910864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07744" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05160308022576, + 38.8981174818172, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H07745" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99181324622516, + 38.913476458853495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07746" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05002308526707, + 38.90711874141516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07747" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00713398029409, + 38.902596068103726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H07748" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9730906640221, + 38.916419030126704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07749" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05654547254223, + 38.89470632929781, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H07750" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97854699647581, + 38.9290532669026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07751" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97725497061309, + 38.9291135404281, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H07752" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06110013765166, + 38.906758932084074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/17/07

Report Problem", + "NAME": "H07753" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05717522525298, + 38.90690650266282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07754" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99488126588837, + 38.902294033570534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H07755" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0582657616718, + 38.90689473049063, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07756" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99487383548785, + 38.90382141760269, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07757" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06946745852954, + 38.916522866822895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/16/08

Report Problem", + "NAME": "H07758" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99487947157466, + 38.89468810322306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07759" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93052527485881, + 38.90470013195742, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H07760" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0093999101176, + 38.88311783915731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07761" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01063283576278, + 38.88312134578459, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07762" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99487230027009, + 38.89903637692326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H07763" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00196897298102, + 38.842707697793834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H07764" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99139999991228, + 38.87320087615333, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07765" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01742140936466, + 38.87384271477187, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07766" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01765882040428, + 38.87451807484806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07767" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02081924170639, + 38.88135481684726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07768" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0174426769584, + 38.87551687743489, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07769" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01867656891648, + 38.881341846725824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07770" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03621679669857, + 38.89796392521521, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H07771" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0368967817473, + 38.89796860396744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H07772" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04346389556616, + 38.92826027783582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07773" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02406298086142, + 38.81754920450373, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/11/07

Report Problem", + "NAME": "H07774" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99745840910933, + 38.82620057874815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06339" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9956068334873, + 38.82844436207334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06340" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99682326982476, + 38.828125006322736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06341" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99339191721745, + 38.95552054258865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06342" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93476059633116, + 38.895033836867896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H06343" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94791305166814, + 38.86882538255405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06344" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95998804184612, + 38.88935925271337, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06345" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06107098506828, + 38.90850181945575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H06346" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93320064366125, + 38.88965038022436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06347" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99032197115449, + 38.88140162869176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/27/06

Report Problem", + "NAME": "H06348" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9760216362617, + 38.84839872241051, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06349" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10189551860627, + 38.93639631563402, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06350" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00192226267096, + 38.82213544512, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06352" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03855193202259, + 38.912755556166076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H06353" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98762947524733, + 38.83216761803273, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06354" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99506468853413, + 38.92624212382352, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H06355" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99598770630901, + 38.925284016651744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H06356" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98563966534705, + 38.86056768974044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06357" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08950270210565, + 38.90941356583103, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06358" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93547349084179, + 38.90275046283293, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H06359" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95493978817174, + 38.85947083173937, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06360" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91612755633857, + 38.89788590295347, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06361" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0347101888558, + 38.90360959613769, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06362" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95963016559689, + 38.88526874870483, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/10/08

Report Problem", + "NAME": "H06363" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93369194522047, + 38.90070602734576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H06364" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00857842370351, + 38.82447080877871, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06365" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94415948378074, + 38.90044744658407, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/08/07

Report Problem", + "NAME": "H06366" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10301117280481, + 38.93838187549443, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy, K81A

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06367" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99841487177481, + 38.90708070417186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H06368" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94010232235925, + 38.87872176274441, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06369" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01083734992935, + 38.82609913629217, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06370" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99191366111425, + 38.83417960066931, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06372" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98957882319804, + 38.83502705741386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H06373" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94078738017618, + 38.869412767156305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06374" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94462028341387, + 38.892721515049516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06375" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99864897478108, + 38.84317751506021, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06844" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99484419430694, + 38.843697448548774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06845" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9922569181805, + 38.84395933423378, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/07/07

Report Problem", + "NAME": "H06846" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99955191583206, + 38.84320232226955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06848" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91897316867937, + 38.891790001345214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06849" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9402533802271, + 38.87757590921841, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06850" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93928743314085, + 38.87652350957581, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06851" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08364710794544, + 38.95335321635176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06852" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09069924201972, + 38.953367298846686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/12/07

Report Problem", + "NAME": "H06853" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94248132894039, + 38.8672304526927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06854" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94265647631872, + 38.86794841010728, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06855" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94618815273662, + 38.906538136283935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06856" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93474601630156, + 38.892914303294454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06857" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.963360431868, + 38.93503937652759, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06858" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96128073431242, + 38.882799424655836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/05/07

Report Problem", + "NAME": "H06859" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00222589421041, + 38.91816450759264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H06860" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00369154111137, + 38.91805374010515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H06861" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99063765723189, + 38.92962671738468, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06862" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05725835591967, + 38.91261370752583, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06863" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05520375582552, + 38.970257873523714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06864" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06425030350772, + 38.906894673585185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06865" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97134524838968, + 38.8522550803544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06866" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05606306758123, + 38.96852105408021, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/12/08

Report Problem", + "NAME": "H06867" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05625816843887, + 38.962009617823256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06868" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05983560459721, + 38.966514994145456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06869" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98376542601555, + 38.857205735079866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06870" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08314101453924, + 38.94104236238156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06871" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97073573734988, + 38.91963415842319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06872" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9704394700389, + 38.92000406482806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06873" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96784416447316, + 38.92242569083767, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06874" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96646694615163, + 38.92384010561988, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06875" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96922992836353, + 38.92147108261294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06876" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96698599320483, + 38.92353877195621, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H06877" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96046686602362, + 38.8763736734287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06878" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95811052128136, + 38.93061837270984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/11/07

Report Problem", + "NAME": "H06879" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96727098728275, + 38.857171800876756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07305" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99635417416557, + 38.884554151004195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07306" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01494724758, + 38.881212401512734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07307" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01378666928579, + 38.8813579576819, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07308" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01279834871673, + 38.881219872480905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07309" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06878110099485, + 38.91722232852371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07310" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01602895733629, + 38.96265282003601, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H07311" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05135348582326, + 38.90381273899625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07312" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97474021922181, + 38.87126849176154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07313" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93934619799694, + 38.897468791997184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H07314" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98460593523568, + 38.932915786081175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07315" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0269938774607, + 38.882992178578796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07316" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0532342281229, + 38.90276396427433, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07317" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0493638217325, + 38.902781509455075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07318" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04772895307246, + 38.9023632372102, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07319" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05152540812392, + 38.90271795003059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07320" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04669577766252, + 38.902774507813405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H07321" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0148720424155, + 38.87301176305626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H07322" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01684278490809, + 38.874695931097925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07323" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01591764608332, + 38.87461418352595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07324" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01450467759673, + 38.873992616869565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07325" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01450659961178, + 38.874774005160646, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07326" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99382187311828, + 38.86127895747909, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07327" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02979387119423, + 38.92252251676341, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 04/05/07

Report Problem", + "NAME": "H07328" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02708016953936, + 38.88442227572075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07329" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0270826006272, + 38.883752060381994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07330" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96347613201775, + 38.85251151579887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07331" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02180399151449, + 38.895473034350346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07332" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02201541580818, + 38.89580636728702, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07333" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02180749732133, + 38.89415795624079, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07334" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02174944125531, + 38.894860484606916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07335" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02200250619778, + 38.89468900798926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H07336" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01142075801127, + 38.815766086697586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07338" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01144093096623, + 38.81439651564001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07339" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0227656159168, + 38.94630885992599, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07340" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07876359814216, + 38.94389898622888, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H07775" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99651848135503, + 38.848006392343244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H07776" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01372098245272, + 38.89595689559788, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07777" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99087963650723, + 38.91957312034873, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H07778" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04360849355336, + 38.91255213573038, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H07779" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99029430469642, + 38.91372777423202, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H07780" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98881807747505, + 38.91424336049654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H07781" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01552177152728, + 38.95446121876773, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H07782" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99293796545437, + 38.831023814076744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H07783" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05909760345287, + 38.90614583593231, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07784" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99232283930444, + 38.82834727015251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07785" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07594643658683, + 38.92489561624111, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/09/06

Report Problem", + "NAME": "H07786" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97773433433112, + 38.917372665271934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/00

Report Problem", + "NAME": "H07788" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97600817203194, + 38.917150493472356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07789" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98932201571286, + 38.9143341035538, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H07790" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98282006843007, + 38.91633001660792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - MEDALLION

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07791" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98427216517216, + 38.91582564636996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07792" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0368585383062, + 38.90752945317807, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H07793" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97512242465194, + 38.917437277631876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H07794" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98761884680764, + 38.914650587478306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07795" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97394390447603, + 38.91716589706266, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07796" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98505442179395, + 38.91550058425484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07798" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03167743781633, + 38.976578159461894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H07800" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99003768502162, + 38.935594255091814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07801" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02689659986729, + 38.89561209793297, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07802" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92280358021574, + 38.88282226502623, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/22/08

Report Problem", + "NAME": "H07803" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01348751390485, + 38.92015589692185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H07804" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99066590132217, + 38.830688431535556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H07805" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0217240860084, + 38.9453369203669, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07806" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0219117482382, + 38.94613258689647, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07807" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06614962748161, + 38.906008732419245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H07808" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06771622604425, + 38.90597631470976, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H07809" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10280732391429, + 38.93483740473735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H07810" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07902293422096, + 38.965877087039736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H07811" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03632478450702, + 38.90368134326886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H06376" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95621682912618, + 38.861642256984226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06377" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98573229222727, + 38.95115954146684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06378" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96890085144213, + 38.87151492186587, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06379" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92413955013444, + 38.89377047541237, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06380" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92518488992707, + 38.894323353731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06381" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98225091412405, + 38.90448472794493, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06382" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92548692103111, + 38.89338060451896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06383" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04018306995864, + 38.92724280083231, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06384" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94820585250427, + 38.889628558221574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06385" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95250851558777, + 38.88471370305015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06386" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05867796190613, + 38.95498451607828, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06387" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05993017911504, + 38.95455106065457, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06388" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98736806711368, + 38.919086073617436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H06389" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07262882789776, + 38.932564845168564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06390" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92729133065178, + 38.88964889623357, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06391" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98565165251033, + 38.900092189763704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H06392" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94730003285807, + 38.889951697895846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06393" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94277294832536, + 38.88989497692029, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/18/07

Report Problem", + "NAME": "H06394" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07666750097329, + 38.95081085820682, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06395" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94488773117428, + 38.86805889165294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/03/08

Report Problem", + "NAME": "H06396" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94408807622351, + 38.86866497566869, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H06397" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01915796192878, + 38.93743690998917, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06398" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9920012876199, + 38.95744291813311, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06399" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99282387370222, + 38.958034625072735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06400" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95485103689134, + 38.858286928442375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06401" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9885581649474, + 38.9323779485778, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06402" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9403906052068, + 38.889658801942446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06403" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95621010546085, + 38.859474134721815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H06404" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98872848378188, + 38.934536940069194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06405" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95993184202754, + 38.89702941929888, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06406" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07357713243127, + 38.93722579682287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06407" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07230564822046, + 38.93806898330772, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06408" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93446043709126, + 38.88957287413981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06409" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92921366782463, + 38.8896477258259, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06410" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95845546909602, + 38.93003918047837, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H06880" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96354541629603, + 38.92663907895507, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06881" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96297487993984, + 38.92719529815789, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06882" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97170466665071, + 38.901337761238985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H06883" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96158661395637, + 38.92134311795151, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06884" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9808575383346, + 38.88546202645402, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H06885" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98067951818366, + 38.891050821518625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/01/06

Report Problem", + "NAME": "H06886" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98084054752002, + 38.88422369533478, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H06887" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1022441627605, + 38.941546208943365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06888" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04577710186203, + 38.90557013625271, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06889" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94929066275576, + 38.87726620429468, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H06890" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91262698875987, + 38.89536936296406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06891" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91187691952949, + 38.89471703491633, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/11/08

Report Problem", + "NAME": "H06892" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91416352642354, + 38.89660709893166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06893" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00195263729442, + 38.965196363764406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06894" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97797636106448, + 38.92027692397566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06895" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92058618802173, + 38.898204320775314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H06896" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92479314900567, + 38.898443682540936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H06897" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05851610742279, + 38.95360645820845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06898" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92568413701112, + 38.898516679986486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H06899" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92183103294697, + 38.898221807835306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06900" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93675589040556, + 38.899096923205846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06901" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97006697274162, + 38.9199159406427, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06902" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9619108089718, + 38.928025045285246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H06903" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9600933858736, + 38.92928934997076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H06904" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97828247739685, + 38.86892409103628, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/17/07

Report Problem", + "NAME": "H06905" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95996523487764, + 38.88031413424983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06906" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97873576249505, + 38.869549475017244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H06907" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03481222745445, + 38.97513333035078, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06908" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02742612846652, + 38.974926070584175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06910" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02857030781799, + 38.97461768814917, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06911" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93860683013166, + 38.87469578200884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H06912" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97890893510812, + 38.921170595704275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H06913" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9219028564582, + 38.88646612596618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06914" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01969474537717, + 38.92930442183414, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06915" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05945717749043, + 38.97996399532121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H07341" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05416500998363, + 38.98012532686826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07342" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97073411433927, + 38.923308094717704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07343" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97004308855342, + 38.9222555675058, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07344" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01057828303236, + 38.87851643345949, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07345" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93371434777302, + 38.90841946070984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/06/06

Report Problem", + "NAME": "H07346" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01425467205539, + 38.87633756963333, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07347" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96739819608914, + 38.91745290808618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H07348" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96415166667015, + 38.91686995596387, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07349" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96305428232182, + 38.917178014373874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07350" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96523652644659, + 38.91730362050751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07351" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96621225655664, + 38.91737508153287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H07352" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0159281040351, + 38.872935493791175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H07353" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98713634192262, + 38.867198778360724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07354" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00916426489884, + 38.88745975384796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07355" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97818278157972, + 38.89352903517165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07356" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03823057312687, + 38.990129754296284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07357" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96319829252309, + 38.86558191155318, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07358" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9730110862898, + 38.8879686711808, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07359" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.938462196277, + 38.889603427344525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07360" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99121177677247, + 38.94622085267838, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07361" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02648922113475, + 38.89198671894936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07362" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02785508964458, + 38.892193891046944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07363" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02762717275141, + 38.89196901514472, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07364" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00931098896494, + 38.87921491696026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H07365" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00792679835567, + 38.96168838868454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H07366" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00882340847184, + 38.96105161203931, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07367" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02380879400752, + 38.886539102342, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H07369" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95050953117146, + 38.873211155001464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07370" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97784390927255, + 38.89838238129811, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H07371" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97778232687293, + 38.8978277788175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07372" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97763497622866, + 38.898936508822565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H07373" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02345871272976, + 38.887445911617895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07375" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00926191581291, + 38.870865559320144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H07376" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9705466305446, + 38.915511376550384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07377" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00829882753979, + 38.88512332393778, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07812" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.010037273082, + 38.88511783650101, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07813" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98299423988234, + 38.8513928821244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07814" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98139905696112, + 38.85146427392455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/02/07

Report Problem", + "NAME": "H07815" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98436377749722, + 38.851974964332385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H07816" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06036244463759, + 38.92284485292878, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/10/07

Report Problem", + "NAME": "H07817" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00925396806588, + 38.88511078456666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07818" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01082520137022, + 38.8859689320723, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07819" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06743021004122, + 38.96580750633269, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07820" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02333500914509, + 38.945262327599174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/28/08

Report Problem", + "NAME": "H07821" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05595884182088, + 38.90012345835988, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H07822" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01766589212484, + 38.87222067037575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07823" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98445260119188, + 38.93094021732408, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07824" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00665768488938, + 38.900347943841645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H07825" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06788693269378, + 38.906685082759836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/15/07

Report Problem", + "NAME": "H07826" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98940049754484, + 38.949367330114825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07827" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00428361044698, + 38.95959448378412, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07828" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99502639156024, + 38.93050889096717, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07829" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03936084651036, + 38.99134976553878, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07830" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05771518043335, + 38.95316078481239, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy, K81D

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07831" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98611011722467, + 38.90222659512454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07832" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09328228032055, + 38.938591965554785, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/26/07

Report Problem", + "NAME": "H07833" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93273344655442, + 38.88163480354615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07834" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07270935805565, + 38.970468523916345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07835" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03776997920576, + 38.92315260424226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 10/16/06

Report Problem", + "NAME": "H07836" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03867857225319, + 38.941932344447345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H07837" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01830071987415, + 38.88452667688121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07838" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04454491329965, + 38.9456414538869, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, UNKNOWN

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H07839" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02177149392207, + 38.881114029161814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07840" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02004418334263, + 38.88134952938589, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07841" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93248096639293, + 38.88276431887421, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/18/08

Report Problem", + "NAME": "H07842" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00918852714993, + 38.88235576454363, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07844" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97206170668471, + 38.91342222021708, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07845" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99625799472017, + 38.87945192364907, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/05/06

Report Problem", + "NAME": "H07846" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99841081003788, + 38.832717571741746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07847" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9963243043215, + 38.82517306037714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06447" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9995304864059, + 38.95591449763924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06448" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0160062209351, + 38.97295330748421, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06451" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00255576232554, + 38.95669546905703, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06452" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08395272345864, + 38.94402240957244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H06453" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0034081284013, + 38.95615570822822, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H06454" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99619304064757, + 38.95462273246034, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06455" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91846497136584, + 38.88986413421935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06456" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91770324035967, + 38.89207103964668, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H06457" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92050698962676, + 38.8896401070975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06458" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91850117890932, + 38.88695578580477, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06461" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92034881451684, + 38.88853236505423, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06462" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99308457652555, + 38.95458937644197, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06466" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04574062857647, + 38.91397363799839, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H06467" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99470559737202, + 38.95458836207815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06468" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09691311326478, + 38.93097133599927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06469" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97530820249524, + 38.84672567041775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06470" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97490026413797, + 38.868958455730656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H06471" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01562281186364, + 38.91508468000044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H06472" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92223478019082, + 38.88749401469716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06473" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98212791287683, + 38.87834584494729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/06

Report Problem", + "NAME": "H06474" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08433487266956, + 38.93983558472638, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06475" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08538363866316, + 38.93998172162816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06476" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0850377212599, + 38.94069364712121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/14/07

Report Problem", + "NAME": "H06477" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0583610949476, + 38.92471649247591, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H06478" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95872191496316, + 38.87003664107611, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06479" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9737771242671, + 38.84687694858346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06480" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97695557469099, + 38.84654202785491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/25/07

Report Problem", + "NAME": "H06481" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00204359595887, + 38.95911800755165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H06482" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00122056940498, + 38.9588904434059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06483" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97008413065218, + 38.926762674020075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06484" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00343822568875, + 38.89222276344097, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06485" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98372679465297, + 38.867062262925614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06486" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00648724533183, + 38.85325258725298, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06487" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00717190165935, + 38.96833554239617, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06488" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01964243886209, + 38.93029224580981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H06916" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02158505873793, + 38.929979585111354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06917" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0215817437073, + 38.92904840573736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06918" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92986964040844, + 38.883153320736085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06919" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93100726507458, + 38.88331737440409, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06920" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02064868456085, + 38.927567058325636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H06921" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03493547813184, + 38.930996926259304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H06922" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06992232888156, + 38.91855824442158, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H06923" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92181478852825, + 38.89570943557277, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06924" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03411727054059, + 38.9733074764901, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06925" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93384257741761, + 38.890621452199134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06926" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05942323667135, + 38.93421465431748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H06927" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04191154650579, + 38.994395190684806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06928" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95498377859809, + 38.86151564320145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H06929" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08950568737377, + 38.91491630083296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06930" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08879060316153, + 38.91508145576154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06931" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05232545414204, + 38.934534247823116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/10/06

Report Problem", + "NAME": "H06932" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0938246535971, + 38.928670880702796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06933" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00898722427414, + 38.886555002027116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H06934" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92552813657788, + 38.882575150284744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06935" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09929866359468, + 38.94303676509001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06937" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93998868767575, + 38.91246026526381, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06938" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93867579625896, + 38.911861609933425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 12/28/07

Report Problem", + "NAME": "H06939" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02822647912558, + 38.96011392235304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06940" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98421121856971, + 38.93194959273384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06941" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93744237833668, + 38.880254515601784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06942" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92759163468226, + 38.89842460526843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H06943" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97739999711641, + 38.92445505382356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H06944" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99838069273713, + 38.89820737574346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06945" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98377964562911, + 38.92214121834334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H06946" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03502432212396, + 38.962185216538025, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06947" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96062208914762, + 38.8692708169922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06948" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93769124525946, + 38.89596496525098, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06949" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0010194459706, + 38.8267402093052, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06950" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94896904881244, + 38.871205725811464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06951" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9720106215178, + 38.91549331435399, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07378" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02256505126924, + 38.88637850461337, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07379" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02324738863086, + 38.88637426297682, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07380" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99016298111175, + 38.89536313147431, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H07381" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99031247405496, + 38.89625968350196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H07382" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9907489650503, + 38.83235346327543, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H07383" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95923561316053, + 38.86279675180596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07384" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00869900764677, + 38.89140123292308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07385" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01047483178928, + 38.889314225282924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07386" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0086958727219, + 38.89140423294449, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H07387" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00862872610426, + 38.88823448811311, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07388" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00862540697659, + 38.8882381637762, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07389" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99965400989588, + 38.86201525233027, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 12/19/07

Report Problem", + "NAME": "H07390" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96488309635455, + 38.87387423637057, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07391" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01998219940283, + 38.88735268178771, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H07392" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98404873624094, + 38.86307440890552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H07393" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9780067069492, + 38.90256948782962, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H07394" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97800693630485, + 38.90362040241758, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07395" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95149439379644, + 38.90127230260149, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H07396" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97635823330886, + 38.90569377584452, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/10/07

Report Problem", + "NAME": "H07397" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97671468912473, + 38.90294310217873, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/27/07

Report Problem", + "NAME": "H07398" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00920357020638, + 38.90480246529546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/29/07

Report Problem", + "NAME": "H07399" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00885304021857, + 38.906541491158926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07400" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00887512558583, + 38.90844974550422, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H07401" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00923958829911, + 38.90552679686227, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H07402" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00887017082094, + 38.9077317447217, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07403" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0092808096706, + 38.90786818926415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07404" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04447671283583, + 38.91550002985804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H07405" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96768635817297, + 38.86960370214958, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/10/08

Report Problem", + "NAME": "H07406" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96767823483512, + 38.86843204837949, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H07407" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00070857753023, + 38.86199491869393, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07408" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03747415366104, + 38.918067589882845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H07409" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92602909937159, + 38.884742490282626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07411" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9238507841437, + 38.8843195069313, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07412" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98594800848531, + 38.85034603550454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H07848" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05290796512216, + 38.925624667718154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/14/06

Report Problem", + "NAME": "H07849" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07540860735465, + 38.949573363198404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07850" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0077153522999, + 38.90639261879274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07852" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04414961176225, + 38.909039525950995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07853" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99436444025051, + 38.826706962554184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H07854" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00065591240252, + 38.91990562041026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H07855" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02205062500774, + 38.887764298801066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07856" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0526197535387, + 38.898156322778675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H07857" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0662884505694, + 38.971337491236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07858" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05252470264118, + 38.897556768885565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H07859" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10290292137577, + 38.930229777114825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H07860" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99337856787909, + 38.82748258498991, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/19/07

Report Problem", + "NAME": "H07861" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98569205940727, + 38.833474785503725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07862" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99522632422931, + 38.82602436617305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/21/07

Report Problem", + "NAME": "H07863" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03017195431408, + 38.95975453853187, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07864" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06225952363265, + 38.94320213313865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/19/06

Report Problem", + "NAME": "H07865" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02566035874844, + 38.88295559883774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H07866" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02631492721297, + 38.88477947989644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H07867" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02561315135392, + 38.88475583575133, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07868" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02577593649214, + 38.883499733922086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07869" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02619484318929, + 38.883405223837116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07870" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02431815449141, + 38.88296239907488, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H07871" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05203321111429, + 38.92467207946045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/02/07

Report Problem", + "NAME": "H07872" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02580182988397, + 38.886005283847766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/28/07

Report Problem", + "NAME": "H07873" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.015200697957, + 38.872180632616704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07874" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97210640348297, + 38.92929989698902, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H07875" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96626492175632, + 38.926387951043914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07876" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.968149734719, + 38.9277700670659, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07877" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96860244533637, + 38.92859304485643, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07878" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97151990766324, + 38.93109057132295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07879" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04857480353088, + 38.911080303773396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H07880" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06790376094129, + 38.90767343303258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/15/07

Report Problem", + "NAME": "H07881" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07132303600713, + 38.957023479419924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07882" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08683836022527, + 38.94122595662857, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/26/07

Report Problem", + "NAME": "H06411" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99756873306923, + 38.95479164712626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06412" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92788669890638, + 38.88993374987981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/26/07

Report Problem", + "NAME": "H06413" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96791051099046, + 38.923390707481786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06414" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00773456528148, + 38.81968157461506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06415" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00713999550366, + 38.821944776314936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06416" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00705047874656, + 38.82048374190161, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06417" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91360021451412, + 38.889917353913354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06418" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97174732588093, + 38.92062548537049, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/11/08

Report Problem", + "NAME": "H06419" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10639501715012, + 38.92932789067318, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06420" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96153600806343, + 38.86557201607332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06422" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92483908063348, + 38.88964277679233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H06423" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92300169281533, + 38.88993334339456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06424" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0416231474056, + 38.993135776693364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06425" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08694628283081, + 38.94021591145779, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/21/07

Report Problem", + "NAME": "H06426" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99462262055135, + 38.829372967625396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06427" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92458257666763, + 38.88986487516813, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06428" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91765868460706, + 38.88950798089341, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06429" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99657988162654, + 38.83550807372832, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06430" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91082475018672, + 38.89285377339497, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06431" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91110909801176, + 38.892012932211614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06432" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99856289867849, + 38.955633891328, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06433" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94160384950266, + 38.87008790806052, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/27/07

Report Problem", + "NAME": "H06434" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9986870199681, + 38.954153690590985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/21/07

Report Problem", + "NAME": "H06435" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97644168961469, + 38.84520790112694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06436" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9925421124516, + 38.94184486450241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06437" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97415640532023, + 38.84545124908119, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06438" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99175041462823, + 38.8411274132506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H06439" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98531691857632, + 38.86128333249696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06440" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98575726491512, + 38.86243383410268, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06441" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00897148354399, + 38.954324564868124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06442" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00560326134706, + 38.82178048255727, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06443" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00541823829477, + 38.820382132395096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06444" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97400629735824, + 38.84396117409836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06445" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03286062760037, + 38.897178946827985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06446" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1017552271079, + 38.92965448406576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06952" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10259679255353, + 38.9291434722956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06953" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00338175553144, + 38.87934082513986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H06954" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00345463349966, + 38.88042332524441, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/01/08

Report Problem", + "NAME": "H06955" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97720895839207, + 38.94064721928847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06956" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98556796112138, + 38.89944858625816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06957" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99627292134048, + 38.89817018603768, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06958" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03115732724314, + 38.96182514299751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06959" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02999061288051, + 38.9616717852718, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06960" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0661075125801, + 38.90526358540482, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06961" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06010384333933, + 38.905100479983815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06962" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05908587798966, + 38.90510164783787, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06963" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06523188111883, + 38.90525056505461, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H06964" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00368841244952, + 38.95298571782302, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06965" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96909341708202, + 38.87272407181803, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06966" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99363869562072, + 38.843716631117545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06967" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93225284760618, + 38.896173688569974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06968" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02592147669041, + 38.91572090948699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H06969" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02792098507723, + 38.91227058041637, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H06970" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92972891587851, + 38.898447206222606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06971" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08734832988705, + 38.936294128063686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H06972" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99368676911035, + 38.895772526019954, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H06973" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09625834931724, + 38.945468591612475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H06974" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00915681333376, + 38.830027611670445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06975" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93711222287227, + 38.91120534991192, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 01/03/08

Report Problem", + "NAME": "H06976" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93793312400777, + 38.9130081506638, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06977" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9368172494712, + 38.91197466531144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H06978" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03222205275104, + 38.92350095987291, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06979" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05752098331406, + 38.96079725785688, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06980" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06605316759736, + 38.960942664582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/12/07

Report Problem", + "NAME": "H06981" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05632422330982, + 38.96083973787946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06982" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98417076668625, + 38.89991512838244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06983" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98806538713458, + 38.898135485163984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06984" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9911611748645, + 38.95669336123746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06985" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94449869531007, + 38.890930088276136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06986" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92632938766549, + 38.88338365683179, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07413" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96862657910718, + 38.86385943888858, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07414" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99026975297478, + 38.925416381971466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07415" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06014937442826, + 38.94654352816389, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07416" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06225246121589, + 38.94679193854353, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07417" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98772872958861, + 38.91078386915941, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H07418" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00051212805226, + 38.876662479468, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07419" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97352733206057, + 38.85535999977145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07420" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01008000518348, + 38.82968332214097, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07421" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9445063059086, + 38.889977870578285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07423" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09514643003492, + 38.94309483579863, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H07424" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92624113029149, + 38.88405893290013, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H07425" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98282968371099, + 38.88597101830189, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/06/06

Report Problem", + "NAME": "H07426" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02203506364303, + 38.88656688995685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07427" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03968085439364, + 38.90029132604644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H07428" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01511110315764, + 38.88519652800059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07429" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01534670805299, + 38.885760250818294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H07430" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92326426360978, + 38.895863890300376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07431" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04995342455808, + 38.903792734900286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H07432" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02202100457184, + 38.901363930420096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07433" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0220115950943, + 38.9081187090952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07434" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02200605938337, + 38.90489990122216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07435" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02180465098186, + 38.900195253729066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07436" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02181684851732, + 38.90626615202735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H07437" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01224432053385, + 38.88624380878003, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H07438" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03359572823398, + 38.90816929985527, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07439" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02201799698209, + 38.90316099873112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07440" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0218189139256, + 38.90397254454837, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/07/08

Report Problem", + "NAME": "H07441" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02181922453205, + 38.90189741610248, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07442" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02201064222825, + 38.901967230984845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07443" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03776977029426, + 38.90719054739083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H07444" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00927240504991, + 38.91549818139271, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07445" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00928308223466, + 38.914876218161965, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07446" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00877638181386, + 38.91806332394905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H07447" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00876146325494, + 38.916771260298475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07448" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04750411240195, + 38.90516940396755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07884" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02581383360821, + 38.8866568843909, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07885" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02615175350172, + 38.88665560209699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07886" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02616242912586, + 38.88600236599295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07887" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02124955130948, + 38.87761921174285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/28/08

Report Problem", + "NAME": "H07888" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99857922853874, + 38.841949167495265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07889" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02277696705843, + 38.894859703232484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07890" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10521583674903, + 38.92865147874046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H07891" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02095840918759, + 38.89485575568156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07892" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00024455167912, + 38.82217857526091, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/06/07

Report Problem", + "NAME": "H07893" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02415874532174, + 38.89044881030504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H07894" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02412524303273, + 38.89196544886698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07895" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0240496166839, + 38.88985017228636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H07896" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98065146999187, + 38.86845278231885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07898" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02245902647606, + 38.88744929708282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07901" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02080869508427, + 38.886765362295634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/22/07

Report Problem", + "NAME": "H07902" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0217171559744, + 38.887447978017185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H07903" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96881586516558, + 38.92333364164194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07905" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98661696338365, + 38.89605588268407, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07906" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0138799955668, + 38.813435513840034, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07907" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01258659060446, + 38.91117307700959, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07908" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00614832911347, + 38.892018729736456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07909" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02167890682476, + 38.87935053691836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07910" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96931869991654, + 38.92444437443467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07911" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99341733846948, + 38.86014789223935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07912" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93770853696317, + 38.90284266030697, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07913" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04260900694922, + 38.910659464776614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H07915" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03331918426504, + 38.95277441444272, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H07916" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03352030941684, + 38.95415965754698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H07917" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99489749411727, + 38.835303637441534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H07918" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01980959849544, + 38.88342038130411, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07920" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01981900895566, + 38.88406309191132, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07921" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9436431243427, + 38.88494669135117, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07922" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04163967723093, + 38.90736462479426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07923" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07725788174332, + 38.95474298596072, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06489" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00028739141594, + 38.848327792919605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06490" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92616184945268, + 38.890715293032855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06491" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9753159690198, + 38.9224451732559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H06492" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99031734024099, + 38.94448902978518, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06493" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99030994721933, + 38.94363182781952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06494" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05825585510728, + 38.92635757229419, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H06495" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04652667599123, + 38.94164240797303, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H06496" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94218898396095, + 38.90217811973996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darily

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06497" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05968278999548, + 38.952731264454215, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06498" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95063597597994, + 38.897159842421225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06499" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93591157539885, + 38.89030796115112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06500" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93590711364858, + 38.89197701238156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06501" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91785789979404, + 38.89088725875616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06502" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91465669938479, + 38.89079910490493, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H06503" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03522198549426, + 38.988337678909495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H06504" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96383970105636, + 38.924163333461784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H06505" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9576964210263, + 38.92000902871361, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06506" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95628174702554, + 38.91906579556323, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06507" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9881385232493, + 38.954412336166556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06508" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99034002312658, + 38.95484302582045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06509" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98932040426332, + 38.955357525285436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06510" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06756779303588, + 38.91558434835727, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H06511" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03791854932126, + 38.991171807524985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06512" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02410448849469, + 38.969971183317014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H06513" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02667759581159, + 38.978057548616206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H06514" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10797354109583, + 38.935709389750265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06515" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04088594881263, + 38.99259359003843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H06516" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96223775778958, + 38.865705803858894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06519" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95301544902972, + 38.86612948299471, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H06520" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92285090576733, + 38.890782814936465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06521" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97981826940892, + 38.870653169794814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06522" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02798289407815, + 38.901494095447674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06523" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00572903369728, + 38.83210742498885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06524" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00448355760875, + 38.94156474153692, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06525" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05606924329489, + 38.96114651049311, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06987" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0162519783485, + 38.88122228961411, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/02/07

Report Problem", + "NAME": "H06988" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97505727489293, + 38.91436977328595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H06989" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01765801769707, + 38.880402177956135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H06990" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97247311061375, + 38.91754342327378, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06991" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02950943823365, + 38.94724034870919, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H06992" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9354711764542, + 38.88140094999921, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H06993" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99382187716199, + 38.8962398601898, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06994" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01193346336534, + 38.967273522995576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H06995" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02067193214236, + 38.92791736047882, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/23/06

Report Problem", + "NAME": "H06996" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97735515863302, + 38.944106349182775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06997" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02134675927545, + 38.937825752192786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H06998" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02011530125887, + 38.93186589863517, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/05/06

Report Problem", + "NAME": "H06999" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0192850435997, + 38.93593462033714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07000" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99837624703336, + 38.83776010022164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07001" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01873346617424, + 38.931990235718, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H07002" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01952199171801, + 38.934141848137195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07003" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01912682623846, + 38.93892398642003, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H07004" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01929445556377, + 38.935253483242214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07005" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02158265043997, + 38.93871203501573, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H07006" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02051081021706, + 38.93333529157292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H07007" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01917352272751, + 38.942459138336176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H07008" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01912559332496, + 38.93359704650033, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07009" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04374823318042, + 38.920642971229206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H07010" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02134621464103, + 38.93639191968371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, DRY WELL

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07011" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02094613188794, + 38.93482078248051, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H07012" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0985620903297, + 38.94388257335056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07013" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0976519107093, + 38.944001453929395, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/24/08

Report Problem", + "NAME": "H07014" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00699942023506, + 38.892041409959404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07015" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93430973525066, + 38.885859399955486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07016" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02328546307889, + 38.93748958881003, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07017" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95969116783435, + 38.91702032883963, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07018" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96125260077652, + 38.9170967702412, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07019" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02036885504953, + 38.94181423999462, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H07020" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00921986286824, + 38.9181988291148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07449" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00877571293505, + 38.918062720441256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07450" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00875880106659, + 38.91678307042007, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07451" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0088252011388, + 38.91477439640563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07452" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03078416236093, + 38.920240010252606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H07453" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9193042667873, + 38.88993501844188, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/21/08

Report Problem", + "NAME": "H07454" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95763540449762, + 38.91720066907016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07455" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09361239005848, + 38.94320820055547, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H07456" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05398219670032, + 38.89889699028136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H07457" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98315240981138, + 38.84267407718769, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07458" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98268059050783, + 38.84164461285684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07459" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03177211577905, + 38.886710519867904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07460" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0136034782694, + 38.829498723497665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07461" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93904850503645, + 38.889953025563734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07462" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01439181712323, + 38.95755944940955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07463" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05036330371277, + 38.89224201785637, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H07464" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9611819660535, + 38.87465600281075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07465" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94450700114177, + 38.89172185623164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07466" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95707015355423, + 38.872226862563544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07467" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92936742682755, + 38.89209758363686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07468" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96127880578582, + 38.87747564523609, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07470" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04297437622263, + 38.993552232490885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07471" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93909054247733, + 38.892693764316526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07472" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9716480037056, + 38.922078585022724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H07473" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03822905659493, + 38.983151932924564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H07474" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02343360014387, + 38.97950365803748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H07475" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97716561778017, + 38.89279867636867, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/07/06

Report Problem", + "NAME": "H07476" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00398878817452, + 38.95451083472198, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07477" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92651167787781, + 38.89276973835049, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07478" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01528035227209, + 38.88419382791563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07479" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01876919457493, + 38.87633862491311, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07480" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0210759447468, + 38.894201159527846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07481" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01864675272685, + 38.8747244027887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07482" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0590056325616, + 38.94084564872903, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennnedy

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H07483" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99965052015793, + 38.861720046462345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/18/07

Report Problem", + "NAME": "H07484" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02205400529027, + 38.8829641097241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07924" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02385896355244, + 38.89600808095506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H07925" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0238678108412, + 38.89671409170843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H07926" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98045364055163, + 38.94326049884007, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07927" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04139487580589, + 38.90637474836192, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H07928" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01735675707307, + 38.881222337849344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/16/07

Report Problem", + "NAME": "H07929" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02588685858001, + 38.96857369630835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H07930" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01373275033698, + 38.89780426636046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07931" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97232428373464, + 38.86880160477246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H07932" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01355965696004, + 38.89669742001146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07933" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97367537173753, + 38.868900108816895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H07934" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0447964213905, + 38.893594279841516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H07935" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99624728954058, + 38.88030133344313, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 11/04/06

Report Problem", + "NAME": "H07936" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01612975315861, + 38.876578849809384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07937" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92748441403334, + 38.89287839268856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07938" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03251785223235, + 38.9254314327115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07939" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0321158674721, + 38.924656134904616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07940" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01531411831252, + 38.88331561411112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07941" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92336388826358, + 38.90017414297687, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H07942" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09110452368616, + 38.95651193299512, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07943" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03260578450856, + 38.92742051632777, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07944" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03223979431193, + 38.9258594948786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H07945" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9948281618923, + 38.95099733804596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07946" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02029059331193, + 38.875762202455405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07947" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00367588903994, + 38.96383095104751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H07948" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9869965980431, + 38.85964119754781, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07949" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01624787745084, + 38.902742037298076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07950" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08869792606939, + 38.91903604098807, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07951" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02396605231161, + 38.893874202124465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07952" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01103244471595, + 38.90457599010864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/01/07

Report Problem", + "NAME": "H07953" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02040001452612, + 38.93779555429568, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H07954" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02134002210782, + 38.939902903854346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07955" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01222965737209, + 38.90479049488283, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07956" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01224855341788, + 38.91593600056736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H07957" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07721748335199, + 38.93345800499922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06526" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09894925603915, + 38.92575299465459, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06527" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95876618764156, + 38.86802238568965, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06528" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03840838976555, + 38.99182145423093, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06529" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03898405280461, + 38.99262210168253, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06530" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10160852995067, + 38.9250025716698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06531" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00193451766445, + 38.84517849851957, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H06532" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09962189800203, + 38.92214123818247, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06533" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00073182254216, + 38.831021052649234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 03/07/08

Report Problem", + "NAME": "H06534" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04174287581495, + 38.99148379252362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06535" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96859949384928, + 38.865238845073264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06536" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97080932290235, + 38.91723002505121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H06537" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91657282320223, + 38.88986904992909, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06538" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96886999819282, + 38.91717397913174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06539" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06515470111678, + 38.93634517117816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H06540" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99483977402123, + 38.905329801430874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06541" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9944489519022, + 38.905757644083046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06542" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93912598595999, + 38.89669493996138, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06543" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02381686441643, + 38.919347696708975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H06544" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08593476549828, + 38.91380001075514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H06545" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01030701031365, + 38.8948463079967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06546" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99257229569044, + 38.947195138488254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06547" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.076819591807, + 38.947947756260206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H06548" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96890161469761, + 38.86957832211967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06549" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00572608536115, + 38.8311030356256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06550" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9329825764222, + 38.89055516477139, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H06551" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97268893821048, + 38.84572533916201, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06552" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97188645664649, + 38.844301120938916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H06553" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97286296573763, + 38.84744343360558, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06554" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0225048778306, + 38.89059271611999, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H06555" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0770147489041, + 38.92991599052319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06556" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01159263294112, + 38.96904227158588, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H06557" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00334481761338, + 38.830889717669116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H06558" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07998341493588, + 38.9479649932339, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06559" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99004990742897, + 38.91909028740231, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H06560" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02060330149321, + 38.94113048775644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07021" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98582953879914, + 38.911204172613175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H07022" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98625584121956, + 38.91190356797587, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H07023" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0654449147393, + 38.96199673839912, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07024" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09070276352669, + 38.95215457524894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07026" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02536723633878, + 38.920701853319024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H07027" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97296629082248, + 38.88466468406594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H07029" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10354674620037, + 38.92847582089967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H07030" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02532714536176, + 38.92386317053315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H07031" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01131150078882, + 38.95341996785075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07032" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02638132517758, + 38.930846839677955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/25/06

Report Problem", + "NAME": "H07033" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94568083769293, + 38.86474459980602, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07034" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02585749499349, + 38.92701759580693, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07035" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02634256011007, + 38.92871849115306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07036" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02593440991157, + 38.92490482237563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/06/06

Report Problem", + "NAME": "H07037" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02629431183908, + 38.92995209102587, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/25/06

Report Problem", + "NAME": "H07038" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02583105131406, + 38.92571365701877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07039" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9394556869378, + 38.88026171136533, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07040" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94038029439855, + 38.89301790233104, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07041" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93796464544897, + 38.87070997176365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H07042" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94699250718553, + 38.86365095033626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07043" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9438371694588, + 38.86622229662141, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07044" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9446985421607, + 38.865520952328055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07045" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96932535513365, + 38.874281829597855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07046" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00646140437084, + 38.91166912505933, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H07047" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00921710000658, + 38.92028658117106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07048" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00888345785944, + 38.92462091589967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H07049" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01620281476676, + 38.88331531403804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07050" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01707740404841, + 38.88331518943418, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07051" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01389189398566, + 38.88331042293399, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07052" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0145890366043, + 38.88331000462411, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07053" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9400952582351, + 38.90848298321637, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07054" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93896547417108, + 38.908471669554196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07055" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94329154399351, + 38.90566748747477, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H07056" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01454543998229, + 38.905324271557234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H07057" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99581738136735, + 38.85674578270633, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07485" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94069594656754, + 38.88989004925468, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07487" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02992657477775, + 38.92767723135113, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H07488" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98138909122179, + 38.84218735323076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H07490" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98544159228483, + 38.840577948111616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07491" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00211112049904, + 38.86075438844818, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07492" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94154922390052, + 38.889889371324585, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07493" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94244360912218, + 38.89179807752878, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07494" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03328538857521, + 38.90317920426543, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07495" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98426127593997, + 38.834594487921336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/01/07

Report Problem", + "NAME": "H07496" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02201151698797, + 38.910406116741186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07497" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96906246954298, + 38.86808655447621, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H07498" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98677236819651, + 38.83598957895159, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07499" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98655811013855, + 38.832823477688024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07500" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9974929190682, + 38.939489281422944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07501" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06024466971265, + 38.94097268222592, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 12/20/06

Report Problem", + "NAME": "H07502" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00764142412145, + 38.90862664849224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07503" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05578154231246, + 38.93060180305019, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant,Mueller

In Service


Last Inspection Date: 04/26/07

Report Problem", + "NAME": "H07504" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0512340218352, + 38.92360021725625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/02/07

Report Problem", + "NAME": "H07505" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96141025255085, + 38.9301589680097, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07506" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06939661267404, + 38.96033231024709, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07507" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98506395686054, + 38.83407229197827, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07508" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01775120651455, + 38.883171558367586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07509" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02100290703396, + 38.88331271178691, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07510" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0018864033965, + 38.914133618281895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07511" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03435582600682, + 38.9001568610635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07512" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0348872092274, + 38.91913530127127, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H07513" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98720333301587, + 38.92209673691571, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07514" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99228694092861, + 38.92260873858445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07515" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98664190965306, + 38.92449436463466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07516" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98696476401386, + 38.923988511934226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07517" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99333623171619, + 38.92227675639505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H07518" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98995621718983, + 38.92333794722294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07519" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98781983232017, + 38.92398945096424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H07520" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00282861899113, + 38.85750789108447, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07521" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98129632993214, + 38.863423707163925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07958" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03205331587833, + 38.92175468003542, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Muller

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H07959" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9286733672165, + 38.900756977111904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07960" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99330891008296, + 38.912966087654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H07961" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98244921588199, + 38.87888355057267, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/19/06

Report Problem", + "NAME": "H07962" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97718372278936, + 38.89122516062354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/28/06

Report Problem", + "NAME": "H07963" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9771489637263, + 38.89019973066068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/01/06

Report Problem", + "NAME": "H07964" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99618090254062, + 38.85580872063352, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H07965" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06281180289439, + 38.94974584155491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07966" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93554165325334, + 38.888098633072644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07967" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03889178521771, + 38.9341308732306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H07968" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04141890811663, + 38.93422023217442, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H07969" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04275001885617, + 38.934225752419614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H07970" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04122222301686, + 38.93246390762373, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H07971" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03984996827357, + 38.9342283896436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H07972" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04408508851533, + 38.93423553495599, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H07973" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9757629410183, + 38.89747700604972, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07974" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96016551203775, + 38.89669328903745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07975" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9834941857576, + 38.86565281928153, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H07976" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02157026279619, + 38.87698943913902, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07977" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02353961419217, + 38.8947452809032, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07978" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05802459227196, + 38.950872944786894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07979" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01373422884703, + 38.89728068214012, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H07980" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02642291209831, + 38.8972605746037, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07981" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02756100451121, + 38.89727015778023, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07982" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02738555592565, + 38.88457779731689, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07983" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02055137040394, + 38.874741748613815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07984" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02083446333175, + 38.875383907150834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07985" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05717764283798, + 38.95292591505484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H07986" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05948560223611, + 38.9517057641324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H07987" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0479143837426, + 38.9096993903211, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07988" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05804298470514, + 38.95089125848744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H07989" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91837844798148, + 38.89986321168602, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/29/06

Report Problem", + "NAME": "H07990" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92242589383024, + 38.90313217528559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/13/06

Report Problem", + "NAME": "H07991" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9612665794444, + 38.883694195910586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 04/03/07

Report Problem", + "NAME": "H06596" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97586111681542, + 38.88775236418858, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/06/06

Report Problem", + "NAME": "H06597" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9893342766315, + 38.95347553749706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06598" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98815288504281, + 38.95324291133274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06599" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97338060761466, + 38.88747089893495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H06600" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99357837235254, + 38.89363530305947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06601" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94218058558862, + 38.903465076305174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/30/07

Report Problem", + "NAME": "H06602" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94811367961901, + 38.89917922604904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06603" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9409561189485, + 38.90440921501846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06604" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9359593191026, + 38.90951795636217, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06605" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06358202075745, + 38.95040631739217, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06606" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0056835614632, + 38.89357375108473, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06607" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98849233603455, + 38.8874758336278, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/09/06

Report Problem", + "NAME": "H06608" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99043359955685, + 38.88753912145234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/03/06

Report Problem", + "NAME": "H06609" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00598179594421, + 38.909018184825754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/27/08

Report Problem", + "NAME": "H06610" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10249631814436, + 38.940432418633776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06611" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99632546556836, + 38.88765017738371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/23/06

Report Problem", + "NAME": "H06612" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99609997925823, + 38.88721584911839, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/06/06

Report Problem", + "NAME": "H06613" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05636385401819, + 38.97971610729608, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06614" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97522797171716, + 38.89305993864624, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/06/07

Report Problem", + "NAME": "H06615" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98689771275237, + 38.95288069903672, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06616" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93650321414749, + 38.89753484403575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H06617" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9828546656321, + 38.92456023465083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06619" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98813257996659, + 38.92455656580424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H06620" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04242749508843, + 38.99052153337876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06621" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03810444606532, + 38.9929801250602, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06622" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03943474533014, + 38.99385340717039, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06623" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9603153245525, + 38.89342086144566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06624" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94151022866663, + 38.904695508944975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H06625" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97597306191932, + 38.89674650721517, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H06626" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94047460283964, + 38.905666095238765, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06627" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97606572154815, + 38.89616169420622, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06628" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93741785376862, + 38.90798022923433, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H06629" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93883813344227, + 38.90641062797429, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06630" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9806156663805, + 38.89344552424362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06631" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01373256841333, + 38.905901688022574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07058" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00948251712136, + 38.90708367221532, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07059" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01962950723264, + 38.90355290046491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/02/07

Report Problem", + "NAME": "H07060" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02086622622208, + 38.903136680373294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07061" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01087744909373, + 38.90683976678106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H07062" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01908953226771, + 38.903975878045486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H07063" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94196476012863, + 38.90629370904827, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07064" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94328491439262, + 38.906421933602644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07065" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99310321539645, + 38.858177092598496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07066" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99322601508506, + 38.8558261980563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07067" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9453762914611, + 38.884851665558834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H07068" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04998793006257, + 38.895254271688295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H07069" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10234467986926, + 38.94303398477356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 01/14/08

Report Problem", + "NAME": "H07070" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10089793139336, + 38.94311738009003, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H07071" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93153132072348, + 38.892466810048845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07072" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03092325085856, + 38.894594534238394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07073" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00870329748531, + 38.91173151546771, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H07074" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97101290282923, + 38.85958114690573, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H07075" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93729477420432, + 38.87131411407198, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H07076" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95157349962516, + 38.886059793121355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07077" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04891940633051, + 38.89266493493581, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H07078" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99838288135655, + 38.83929133904618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07079" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98545468967123, + 38.87783297237987, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07081" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10933279625895, + 38.93692742724404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H07082" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01408142276355, + 38.87561936020418, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07083" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98399450997972, + 38.86128793317125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07084" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06906958177271, + 38.909803430877055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H07085" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01531163990133, + 38.88019853217063, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H07086" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09499629650102, + 38.944312932788314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/04/08

Report Problem", + "NAME": "H07087" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93706903318301, + 38.87947513411545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07088" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9909764186452, + 38.835915605869246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07089" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93808035237032, + 38.87947572872575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07090" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92799687155481, + 38.88221134508788, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07091" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00351691919143, + 38.91886124302476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07092" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01558136032891, + 38.91466741949089, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07093" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00064424622538, + 38.8807347765613, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H07522" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0122761433547, + 38.880346583236744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07523" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04359161413787, + 38.89340544277975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H07524" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01427581143115, + 38.81454512252718, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07525" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00689339114835, + 38.96285577058463, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H07526" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01148735152242, + 38.88022469889475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07527" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00217398221044, + 38.87659192462013, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07528" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99484397325296, + 38.8769029359662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/06

Report Problem", + "NAME": "H07529" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0073842868926, + 38.876622258870654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H07530" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9993562867439, + 38.8765900873512, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H07531" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00359297410337, + 38.876644931016926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07532" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00438971164047, + 38.876592556001036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07533" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00283423842367, + 38.876583064218515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07534" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99274567324093, + 38.87662921248858, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/06/06

Report Problem", + "NAME": "H07535" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99361662298084, + 38.8765908425349, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/06/06

Report Problem", + "NAME": "H07536" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00923626379951, + 38.886085105481726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07537" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95485780336782, + 38.87535109662965, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07538" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02469773523207, + 38.91782975466534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/02/07

Report Problem", + "NAME": "H07539" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95553235800632, + 38.872360917699716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07540" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04611918328935, + 38.91605742338394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H07541" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0448835911217, + 38.915784420524105, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H07542" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99487654096747, + 38.88332906340564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/13/06

Report Problem", + "NAME": "H07543" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06056332229282, + 38.943284729415765, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 12/19/06

Report Problem", + "NAME": "H07544" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04585122443714, + 38.897412688431686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07545" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01870812053822, + 38.87921542023988, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07546" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01767210440804, + 38.87943758439848, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07547" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01999063127565, + 38.879476640284096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07548" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01080807557877, + 38.8792085722202, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07549" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01961861923418, + 38.876582423659926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07550" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01534029043992, + 38.876335981725674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07551" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0153042530359, + 38.87912690397354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07552" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00995451579122, + 38.8762630835017, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07554" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01622942681595, + 38.87936154676377, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07555" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01384686488369, + 38.876248255409244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07556" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01126102000066, + 38.87633136558022, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07557" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08878642722624, + 38.94401500064822, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/18/05

Report Problem", + "NAME": "H07992" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91748805934091, + 38.89912437788262, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/14/06

Report Problem", + "NAME": "H07993" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92641360645341, + 38.90600093403838, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H07994" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91917924042815, + 38.900474355191186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07995" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92868048849542, + 38.90788612992194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H07996" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01318569746388, + 38.87292325991333, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07997" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05805070129023, + 38.94882143198823, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H07998" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92091372831496, + 38.901814436785116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07999" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01209855826444, + 38.87547564628886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/17/07

Report Problem", + "NAME": "H08000" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92529264376194, + 38.90520203757137, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H08002" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92732558473102, + 38.90682878678369, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/14/07

Report Problem", + "NAME": "H08003" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00123309581588, + 38.904666101559286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08004" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00374803505183, + 38.95365565184983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08006" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9678374738352, + 38.91902988378352, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H08007" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01768407170381, + 38.95204638036826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H08008" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0122856540688, + 38.9678472395543, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H08009" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99137576391018, + 38.87845629192337, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 03/10/08

Report Problem", + "NAME": "H08010" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09013119401561, + 38.919209066330524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08011" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07302869177259, + 38.92117904722717, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08012" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92363582624476, + 38.898915411420504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08013" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91864752837658, + 38.88581113845447, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08014" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01999929640256, + 38.88473430286074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08015" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02168144139392, + 38.88477146858051, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08016" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05519164557496, + 38.93557896454594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/28/06

Report Problem", + "NAME": "H08017" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05277851006446, + 38.93975067751088, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 12/20/06

Report Problem", + "NAME": "H08018" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02689915226902, + 38.89498288997653, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08019" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02717595467065, + 38.89627192306822, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08020" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0268979164257, + 38.89671917164068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08021" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02717398004032, + 38.89792741751862, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/31/07

Report Problem", + "NAME": "H08022" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00064727977103, + 38.83907849676125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08023" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93706715383539, + 38.90589805818562, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08024" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93492345314412, + 38.90600499302884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08025" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99671624772927, + 38.91148551447028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H08026" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03900244302665, + 38.93061589459772, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H08027" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01491852520418, + 38.97491360650356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06561" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00344260351017, + 38.92227122043882, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/28/07

Report Problem", + "NAME": "H06562" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95584083351743, + 38.873967638179536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06563" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02500979369948, + 38.907287662368866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H06564" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99166774099328, + 38.953675197168735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06565" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99369467023858, + 38.95336507029002, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "null

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06566" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01043193031353, + 38.9700369446018, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06567" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04612016548695, + 38.91511561067109, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H06568" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95179666950737, + 38.8913246156313, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06569" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98459677096885, + 38.85788192097813, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06570" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9864348592707, + 38.85909315133343, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H06571" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00718033428346, + 38.967393856222486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06572" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98532798835325, + 38.89352560192876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06573" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08749680169771, + 38.91920223137802, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06574" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08592632972002, + 38.91928763363257, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06575" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09216532999889, + 38.919094983644875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06576" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08703413110254, + 38.919778470457295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06577" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93285831224202, + 38.901426355074165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H06578" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03567482798069, + 38.90571386368658, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H06579" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93383976683819, + 38.901557617279686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06580" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00121670836077, + 38.95575070399314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06581" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0026173590169, + 38.95603202712855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06582" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06687123167069, + 38.95739354845349, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H06583" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06125153783827, + 38.92744542529373, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H06584" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05952402780379, + 38.92582610915013, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H06585" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98460092005485, + 38.84292248698842, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H06586" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05991700085701, + 38.92727618424961, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H06587" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92995856087197, + 38.89193418536432, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06588" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99324700956572, + 38.834238555708986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06589" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9502192445542, + 38.88997921987883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06590" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09119421828863, + 38.94041813575338, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/24/08

Report Problem", + "NAME": "H06591" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9243012568637, + 38.883110162498085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06592" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09791486051004, + 38.91590115870607, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06593" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00065244676593, + 38.88771589542851, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 01/31/08

Report Problem", + "NAME": "H06594" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0046406079933, + 38.89358002195662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06595" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02301795273003, + 38.912134857543776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07094" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01032131941619, + 38.916224624481316, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07095" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00504139007937, + 38.91796925459802, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07096" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00337813100796, + 38.918656704030155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07097" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00224194976178, + 38.91903234257876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H07098" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0018242978553, + 38.91944954348136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H07099" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00616187620341, + 38.91767737605771, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07100" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01333431209173, + 38.91518744237037, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07101" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00698698429436, + 38.91771597536882, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07102" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02738555977575, + 38.91029261969574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H07103" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0231449567532, + 38.91174207787035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H07104" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05902787350435, + 38.90085007566496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H07105" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02620148126415, + 38.91070936487943, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H07106" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04671266854976, + 38.90385056699683, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H07107" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04498156447787, + 38.90391395347246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H07108" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04181806676706, + 38.897425822597334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H07109" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04361461555273, + 38.89729744508892, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H07110" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04508950778649, + 38.897291687300175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 05/22/07

Report Problem", + "NAME": "H07111" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95946352246295, + 38.86498689414682, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07112" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96730648682933, + 38.92734499314091, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07113" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02527102941058, + 38.979343253396436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07114" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00086278833724, + 38.83527636908451, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07115" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00049058237661, + 38.840510273641996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07116" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94470346601513, + 38.88113165978272, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07117" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93894171745632, + 38.88907043708943, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07118" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02254306169178, + 38.93895171758112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07119" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00919378704138, + 38.912443722210924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07120" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00916967518945, + 38.913233791343764, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07121" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0028783514896, + 38.94652178093002, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07122" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01759336468929, + 38.87639200254709, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07123" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00470654071628, + 38.945783691167875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07124" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05528808199452, + 38.97288418536045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07125" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05434479963125, + 38.97287902438951, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07126" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99330682114955, + 38.8569601473773, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07127" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9613489145072, + 38.88446667414974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/05/07

Report Problem", + "NAME": "H07558" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96642625185427, + 38.85571694332729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07559" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02506112475884, + 38.917204057777056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H07560" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02546920080194, + 38.92012791073526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H07561" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02408996017506, + 38.91808311468866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/02/07

Report Problem", + "NAME": "H07562" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98343414891414, + 38.835238748441846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/12/07

Report Problem", + "NAME": "H07563" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97180833578197, + 38.86010562279842, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/29/07

Report Problem", + "NAME": "H07564" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97512507622825, + 38.85654261710817, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H07565" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95857104014284, + 38.87293396071503, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07566" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0073771987624, + 38.88598009187593, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H07567" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01418540078254, + 38.87292582725981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H07568" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05780509312685, + 38.94109063453305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/20/06

Report Problem", + "NAME": "H07569" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91769226838073, + 38.89702529358061, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H07570" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91769668604739, + 38.89590399812653, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H07571" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91769615567357, + 38.89801235200351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H07572" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94266104686866, + 38.86937337156766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07573" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01015689619669, + 38.870198727819705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/31/07

Report Problem", + "NAME": "H07574" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96871102885841, + 38.880701264817496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H07575" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01161961828427, + 38.878349949483336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07576" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01343896715305, + 38.877692015466565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07577" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00867559132615, + 38.87922381212902, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07578" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03508706809166, + 38.90010108918067, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07579" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03504792919787, + 38.898973560557216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07580" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0614335473731, + 38.94306875201849, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/22/06

Report Problem", + "NAME": "H07581" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.046572469912, + 38.90613345635938, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H07582" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01774156611317, + 38.88398536830302, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07583" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99826988931275, + 38.8790798071112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/06/06

Report Problem", + "NAME": "H07584" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00077573692529, + 38.87977207617051, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H07585" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0019719352658, + 38.88114426502534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/01/06

Report Problem", + "NAME": "H07586" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99944621624009, + 38.87897787965274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 04/11/07

Report Problem", + "NAME": "H07587" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10280517669854, + 38.9279407959665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H07588" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98880241043584, + 38.86788367020796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07589" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02071616384112, + 38.89410896918894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07590" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99010701528914, + 38.8747485519491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/18/06

Report Problem", + "NAME": "H07591" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96362948185926, + 38.92029800417654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/15/07

Report Problem", + "NAME": "H07592" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02497076695869, + 38.91107545410497, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H08028" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02486678288673, + 38.90970039793379, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H08029" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04827491715417, + 38.92109239790387, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H08030" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01358275659491, + 38.89953358286828, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08031" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95222153156632, + 38.888628295060684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08032" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98084305571352, + 38.8829522433112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H08033" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07724526905416, + 38.96104291448911, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08034" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00927733798935, + 38.95492659946666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08035" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06858634131976, + 38.941464775594355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/12/06

Report Problem", + "NAME": "H08036" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04866314323063, + 38.90394445765287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H08037" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03288520547382, + 38.8983308662706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08038" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03352449764643, + 38.89830554222256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08039" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03386925079425, + 38.898230970651376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08040" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98164580705942, + 38.942614707856166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08041" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96119611565318, + 38.92795932874704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08042" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02619983353765, + 38.884283549218985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08043" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00798478678746, + 38.83540010956732, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H08044" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07000926265907, + 38.96406369591698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08045" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0392754850297, + 38.898968900674156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H08046" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98083713495747, + 38.905770275462906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08047" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95536103646518, + 38.902681570863045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H08049" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9551937740285, + 38.90175366418639, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08050" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95474629179459, + 38.90633995051261, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H08052" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.954824609946, + 38.90426446576569, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H08053" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97250305723863, + 38.85494587078137, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08055" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9734551472341, + 38.85419851762248, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08056" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92649802766421, + 38.896430452092666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08057" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02525545528835, + 38.92986772309871, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08058" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03824380764105, + 38.911075782210325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08059" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03744850554799, + 38.911078859425935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08061" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94123545574868, + 38.90059929859189, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/08/07

Report Problem", + "NAME": "H08062" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9424387281317, + 38.900576457907114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/08/07

Report Problem", + "NAME": "H08063" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07359707689794, + 38.961049888945915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08064" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97058466083409, + 38.89800548161571, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H08065" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99344666688556, + 38.9499362382747, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H08066" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09820919198437, + 38.931641220192134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06632" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92585924081189, + 38.88541171461339, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06633" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97427168948785, + 38.85082620459908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06634" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9725631524919, + 38.85610922429121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06635" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94411832876546, + 38.90047573117055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/01/06

Report Problem", + "NAME": "H06636" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0332593761117, + 38.90378941050947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H06637" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96690054191585, + 38.85980920974811, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06638" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99044017445156, + 38.89206120904355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/13/06

Report Problem", + "NAME": "H06639" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98811365200389, + 38.892061662091, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 04/13/06

Report Problem", + "NAME": "H06640" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0998159947323, + 38.94224751335224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H06641" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1009400873196, + 38.9420709494172, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/09/08

Report Problem", + "NAME": "H06642" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10073907055914, + 38.94075931692487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06643" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94682562434733, + 38.900341590154255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06644" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98207306702139, + 38.887657399416554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H06645" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9788557932541, + 38.88765900531611, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H06646" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98708911737081, + 38.88753820509799, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06647" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98059526918205, + 38.88766049635629, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H06648" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98347934558751, + 38.88770010831467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H06649" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98534867500489, + 38.8879911391867, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06650" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03214896432846, + 38.9036541816669, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06651" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02893315387732, + 38.90380989392949, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06652" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02976146839815, + 38.90340540898938, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/09/07

Report Problem", + "NAME": "H06653" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93764917306679, + 38.88948522066144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06654" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0305117647332, + 38.90379603384022, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06655" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97290886150944, + 38.8631946268882, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06656" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97170238850582, + 38.86395378622063, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06657" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93492963482089, + 38.88714683758573, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06658" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95720583480187, + 38.918537114523915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06659" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95934829814477, + 38.918491864945544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H06660" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98537348571622, + 38.89206517066875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER

In Service


Last Inspection Date: 12/27/07

Report Problem", + "NAME": "H06661" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00753802672362, + 38.95575475525598, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06662" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9956397540779, + 38.89209414717504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H06663" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98691214500934, + 38.88872879563235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H06664" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00266920873362, + 38.965617241930524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06665" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04271065725995, + 38.99143433946698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06666" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94706931146355, + 38.89755654960666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H07128" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02338641580138, + 38.92913561933068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/05/06

Report Problem", + "NAME": "H07129" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03634185868984, + 38.92952303531884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H07130" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95744290126926, + 38.89548949588824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H07131" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98378858812869, + 38.86058538316426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H07133" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02799274007583, + 38.89926321820379, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07134" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06230158840661, + 38.922606177634776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 01/10/07

Report Problem", + "NAME": "H07135" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1086710335078, + 38.93741853746335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H07136" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9821590809367, + 38.89763813749226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07137" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0105660754126, + 38.877640449398264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07138" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05395292919954, + 38.968327450628394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07139" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9908981704769, + 38.91774198095922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07140" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96327169912612, + 38.87828526981169, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07141" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99597249402497, + 38.90978730178437, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07142" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02882732476392, + 38.89746160417395, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07143" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9823782253395, + 38.92624222371151, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H07144" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05638708627936, + 38.96971155368072, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H07145" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05831805738657, + 38.96971400275113, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H07146" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95073291147202, + 38.89527545031412, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H07147" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9498398849183, + 38.89515566435593, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07148" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0333905257536, + 38.93784614656226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H07149" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02344620965623, + 38.98061124328168, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H07150" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03240518879792, + 38.92874628945823, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H07151" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05467317078839, + 38.90138902988212, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H07152" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97267792893813, + 38.91942871632992, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07153" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9614169665006, + 38.86892063725262, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07154" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9402415941209, + 38.90352574477204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07155" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9757437988873, + 38.9187857659611, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H07156" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07826058967379, + 38.92695993121221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H07157" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97389587223684, + 38.88999451381324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/14/06

Report Problem", + "NAME": "H07158" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97518032980332, + 38.88931737298493, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 04/26/06

Report Problem", + "NAME": "H07159" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03510638698909, + 38.90782642144883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/04/08

Report Problem", + "NAME": "H07160" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9974140417839, + 38.88267151699444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H07161" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99187516363632, + 38.83514128692742, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H07162" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01530654822344, + 38.87671737460202, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07593" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04478054194414, + 38.94333234222084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H07594" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08091640501084, + 38.93419123810554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07595" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93891851512589, + 38.87580859089552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07597" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02800513525747, + 38.885174563874195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07598" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02285517021659, + 38.89518831317675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07599" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93839238188482, + 38.870393111297375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07600" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02304737963892, + 38.894335966770136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H07601" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92621410380156, + 38.88095949844807, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/22/08

Report Problem", + "NAME": "H07602" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92927041832074, + 38.88058494667498, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/18/08

Report Problem", + "NAME": "H07603" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92771985214326, + 38.88847710905287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07604" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9388785602111, + 38.87872847954836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07605" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93892747115012, + 38.87751675888302, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H07606" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06499242149373, + 38.923937727632065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07607" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97964319006199, + 38.84582105940526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/29/07

Report Problem", + "NAME": "H07608" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96081324553018, + 38.87200348200796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H07609" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.987837512811, + 38.86468084022014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H07610" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02042258229375, + 38.894370686948115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07611" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03165828973412, + 38.91339968756192, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H07612" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04897052266529, + 38.89962534458021, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H07613" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01072739818773, + 38.87665515053187, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07614" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0139860492789, + 38.87668408302811, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07615" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01954994639182, + 38.87633410973487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07616" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01782363110506, + 38.87633704344056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07617" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03183929255972, + 38.892347817003085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07618" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93785580982951, + 38.892712653120334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07619" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05491383122406, + 38.94055577394254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/20/06

Report Problem", + "NAME": "H07620" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93681738612061, + 38.89318208084086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H07621" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06421128315144, + 38.94957473474059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H07623" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98518276662838, + 38.86934057516383, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07624" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07443286907956, + 38.94785579430204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H07625" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00717926943237, + 38.90367416704998, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07626" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94059498805436, + 38.89745915516139, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07627" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00688885907205, + 38.91560935591307, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H07628" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98077160350076, + 38.91911350555358, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07629" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05430585808163, + 38.91472255461596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08067" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0973401834681, + 38.932657733251496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08068" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02567644903262, + 38.94073572209535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H08069" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0226263006244, + 38.87871035600972, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08070" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05422237529272, + 38.985183225136325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08071" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.976030747485, + 38.944535347896895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08072" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99807352173826, + 38.95065653649802, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/03/08

Report Problem", + "NAME": "H08073" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99830472107227, + 38.88765253803316, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H08074" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0454619136274, + 38.93206122256313, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 01/01/06

Report Problem", + "NAME": "H08075" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06204489273402, + 38.90347086306426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08076" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92525895122802, + 38.89922099786704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H08077" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09358690214279, + 38.91536564625184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08078" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05826488919057, + 38.91062544736217, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08079" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00030260667727, + 38.91025256159615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08080" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00607083603087, + 38.82783680987573, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H08081" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05710567996493, + 38.90537943213029, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08083" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01770545989216, + 38.91265707784783, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08084" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00151273583373, + 38.82120253332884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H08085" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05584047114564, + 38.9061775529845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08086" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93719410570526, + 38.9047931800685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08087" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95640859409542, + 38.862540675271426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H08088" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05309169771132, + 38.95128963360767, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08089" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98492219736976, + 38.92456337532836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08090" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01932205595843, + 38.94104091193039, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08091" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02407486879943, + 38.89892872806242, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H08092" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0241303785301, + 38.92187126057276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H08093" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08275308013201, + 38.950387968192736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08094" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02451009759346, + 38.887453749216625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08095" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97587556476205, + 38.87208924423228, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08096" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02392745914513, + 38.88768752934951, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08097" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00075636549767, + 38.94736743915042, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H08098" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00369973493692, + 38.91551630019421, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08100" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0058747438556, + 38.91560602416622, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/22/07

Report Problem", + "NAME": "H08101" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00785282832473, + 38.91551729300077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08102" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07097240657087, + 38.96680710923335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08104" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04256273614506, + 38.99248150648874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06667" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03069775897414, + 38.98654627542858, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H06668" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04126605188107, + 38.995319877069214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H06669" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99950174070769, + 38.95683618697209, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06670" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0002093400514, + 38.9568235762791, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06671" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93671217061106, + 38.909771077680766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06672" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93454780422805, + 38.91204196054723, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06673" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93470767518134, + 38.91083939127652, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H06674" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.933813118248, + 38.91190189037436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H06675" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9336261110621, + 38.89977247158318, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H06676" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9732578324894, + 38.85413185525328, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06677" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97431179441004, + 38.853123039577405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06678" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10161957426138, + 38.928536480910076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, Metropolitan

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06679" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9820851584149, + 38.856303304506994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06680" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9895455724907, + 38.94837209078545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06682" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95306309704921, + 38.860205134593336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06683" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95251682530085, + 38.86095246853403, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06684" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98822712544568, + 38.892814656261, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H06685" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94680672070382, + 38.8976325149737, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06686" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02647244234389, + 38.984322252894245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06687" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04492804856763, + 38.99188325222858, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06688" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05361088106761, + 38.897319400531686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H06689" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95879074026675, + 38.8755308719135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06690" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97247587999698, + 38.84385955934146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06691" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94984160555939, + 38.897807349541374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06692" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99488331466053, + 38.89189332890175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/13/06

Report Problem", + "NAME": "H06693" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99964764645884, + 38.893016739201016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H06694" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9982079259249, + 38.894002863118665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H06695" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99834932366409, + 38.89329666314996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H06696" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0006388926788, + 38.894233633470144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H06697" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99937165549699, + 38.894150531334496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06698" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99176743824871, + 38.88988321166382, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/22/06

Report Problem", + "NAME": "H06699" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9980643425351, + 38.8243380799068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06700" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99947874869262, + 38.9534082356228, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/09/07

Report Problem", + "NAME": "H06701" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98824195576937, + 38.84185812111377, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H07163" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03117368358609, + 38.89196042936237, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07164" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05220405256068, + 38.90235545879882, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H07165" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0294925574771, + 38.89196592861865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07166" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02887995670005, + 38.89195621751582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07167" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01326188841345, + 38.879223795774905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07168" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03055504938841, + 38.89196672752274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07169" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03009180552627, + 38.89196437948461, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07170" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97941198861014, + 38.90643729943215, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07171" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98251418665494, + 38.90176447908287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H07172" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9817361142532, + 38.90240999786607, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 02/28/08

Report Problem", + "NAME": "H07173" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98240197969302, + 38.90139178654355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 02/28/08

Report Problem", + "NAME": "H07174" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97983925922148, + 38.90534581426163, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07175" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98259188025827, + 38.90109005306457, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H07176" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98164912901785, + 38.90300065301632, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H07177" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98106407892175, + 38.904015602851935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07178" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98050995546866, + 38.90473724283739, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H07179" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93080110020489, + 38.906012443251086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/16/07

Report Problem", + "NAME": "H07180" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98856826208481, + 38.83630882114836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07181" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91769787001495, + 38.89467790579543, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 04/18/07

Report Problem", + "NAME": "H07182" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98859846682389, + 38.84089506326246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07183" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00879516794764, + 38.87656455244934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07184" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96960369738015, + 38.93236298038443, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - JUMBO

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H07185" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97615042813459, + 38.92884378257927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07186" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96643436049604, + 38.933876760413824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H07187" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98060953858959, + 38.926593403050674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H07188" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97894303555384, + 38.92757048971088, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07189" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96423259071118, + 38.9349643913268, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07190" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9818455978275, + 38.926204685610536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H07191" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97368697090285, + 38.93013727963233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H07192" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96826674125221, + 38.9327289027193, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H07193" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9776634250936, + 38.928470768105825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H07194" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06207591869202, + 38.96091468411529, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H07195" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02147380143175, + 38.931977377941415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H07196" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99545236633146, + 38.938484542889505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H07630" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95210402276778, + 38.871180226678014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07631" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95199232173123, + 38.87207599455846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07632" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01999003423212, + 38.88038972183923, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H07633" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04354145595775, + 38.901841883806725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H07634" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04337663811954, + 38.90145199136814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07635" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98884456597, + 38.91356105365554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/26/07

Report Problem", + "NAME": "H07636" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98132186798092, + 38.91284935351559, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07637" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03292540093577, + 38.931968830501816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H07638" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03255540866178, + 38.93524824479915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H07639" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95483598818235, + 38.88520158341418, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07640" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99725802551747, + 38.89099160767032, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07641" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9213090572142, + 38.88810889235209, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/07/06

Report Problem", + "NAME": "H07642" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08977166508976, + 38.9164012202743, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H07643" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02758904737483, + 38.97353620626832, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H07644" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05131506689666, + 38.89614560562933, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H07645" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9561597373276, + 38.87588020542816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H07646" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0656941045554, + 38.954835210649364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H07647" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05589223170068, + 38.934258104621634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/27/06

Report Problem", + "NAME": "H07648" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98358187957423, + 38.89793182054272, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H07649" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99505211363423, + 38.8860862576991, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H07650" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0676130006429, + 38.91744067858635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H07651" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03384151094251, + 38.902670117519804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H07652" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03329161592923, + 38.90355369776755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H07653" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0366204468569, + 38.992171131374356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H07654" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09547664180998, + 38.934339797263775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H07655" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94248106853148, + 38.90388283391777, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H07656" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99161384287906, + 38.948361564624236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H07658" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05538455131251, + 38.899825267045095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H07659" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9602227189676, + 38.89066513289886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H07660" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96156016250936, + 38.92044061922615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H07661" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98383091381878, + 38.887006124984175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H07662" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97378534478037, + 38.904140079088634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H07665" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99959286638867, + 38.91988141617034, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H07666" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08501170602099, + 38.94560412106222, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/27/07

Report Problem", + "NAME": "H04505" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95654305223472, + 38.89365977221223, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04506" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97518279915471, + 38.94067135426789, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04507" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9367036997258, + 38.87498690843462, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H04508" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97506636774665, + 38.868307444657106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04509" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01529486536687, + 38.89915188524489, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H04510" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01529637967154, + 38.89847224027998, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H04511" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01533375102812, + 38.89620930760246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04512" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93521919567424, + 38.899001646517085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04513" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96913510535339, + 38.93414917719809, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04514" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00958756264887, + 38.90795428427942, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H04515" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03780815859407, + 38.93221727942994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H04516" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91927519665964, + 38.89085197009494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04517" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01610729068243, + 38.89490146805752, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04518" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05741847698862, + 38.977393409005366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H04519" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08284602282293, + 38.9599718717732, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04520" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03661770740952, + 38.988907523757774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04521" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02007001701885, + 38.894850614774384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04522" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01971429770033, + 38.894571334891296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04523" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03228839827646, + 38.94395695096938, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H04524" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00268269482102, + 38.96278459765307, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H04525" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01688847768335, + 38.89470774990744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04526" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01602508217665, + 38.8934854720268, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04527" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01714532668765, + 38.89493451614574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H04528" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0153305961584, + 38.89316888502167, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04529" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06203172561044, + 38.97597182469591, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04530" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97509509310142, + 38.90027565512053, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 12/19/07

Report Problem", + "NAME": "H04531" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99860603254884, + 38.92455568268532, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04532" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10201453566845, + 38.93539452440193, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04533" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10368454157613, + 38.93367181967864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04534" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02951211090763, + 38.91928297852966, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/28/06

Report Problem", + "NAME": "H04535" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01528268522242, + 38.89686144779281, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04536" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01868698817158, + 38.89467790157425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04537" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94924765535072, + 38.86582359293103, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04538" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.037769935006, + 38.91690745588892, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04954" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97142885019181, + 38.86907023603545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H04955" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95763838837377, + 38.860577733899596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04956" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95882258005365, + 38.89204997336262, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H04957" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95746593202843, + 38.862081852095365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/19/07

Report Problem", + "NAME": "H04958" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02851565609653, + 38.969030451248095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04959" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97742027557022, + 38.901312638286754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H04960" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9775592473854, + 38.899270362145124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H04961" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95159432322585, + 38.893370603485906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04962" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08072525467323, + 38.921537190691474, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04963" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0798723336545, + 38.92196653705908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04964" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99158874868232, + 38.899603587189674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04965" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97687584368056, + 38.89772988919319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04966" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04321089564364, + 38.9869617983455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04967" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9765791968336, + 38.89875208095324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H04968" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95249863594898, + 38.886915518824274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04969" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95294440748845, + 38.885778967641656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H04970" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94687304428274, + 38.86573991150237, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04971" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94895799947581, + 38.86653095138741, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04972" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98523261120602, + 38.90962671104989, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H04973" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0065189663599, + 38.94476188473148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H04974" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9605324786096, + 38.86280134124152, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04975" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99870068629718, + 38.83100646300914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H04976" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99670644890912, + 38.83104835816591, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H04977" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99455718617257, + 38.83294639666921, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H04978" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99478811531402, + 38.83207610879017, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04979" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99482915720249, + 38.831038867237936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/17/07

Report Problem", + "NAME": "H04980" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99065977055142, + 38.8441879237521, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H04981" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00041010664916, + 38.829286411332376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/03/07

Report Problem", + "NAME": "H04982" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00047078157007, + 38.82997545058975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04983" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95945206901574, + 38.89346184133429, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H04984" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9600857698224, + 38.89206721243867, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04985" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95962051959977, + 38.892863239427655, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04986" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99811232082406, + 38.91092906415695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04987" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94442245963786, + 38.88039215372748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05415" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94419433211398, + 38.879583118379465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05416" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97239877531072, + 38.87283836966293, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. PIPE

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05417" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97141137090834, + 38.8740431408423, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05418" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97030914383717, + 38.87357841971728, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05419" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98384123932715, + 38.90986512187603, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05420" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98513876257802, + 38.91010779869182, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05421" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96988474780036, + 38.85963495694311, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H05423" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95747243560545, + 38.87568663192944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05424" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0888109638939, + 38.94014533488393, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/03/07

Report Problem", + "NAME": "H05425" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07896421783846, + 38.925390875417, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H05426" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08549318436802, + 38.93247978876778, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H05427" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95128025010533, + 38.890441085234784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H05428" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96591582953405, + 38.8694331020444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H05429" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98787525218218, + 38.94951067469486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05430" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98715846608076, + 38.91112853005006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H05431" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97514720745615, + 38.850887039050214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05432" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03295369554044, + 38.89736340288634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05433" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96964959960575, + 38.85706639625015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05434" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97884871222637, + 38.9056736962068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05435" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94709887099509, + 38.89194168300198, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/09/07

Report Problem", + "NAME": "H05436" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96590448522879, + 38.8564440694794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05437" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0562741295463, + 38.963957924133425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05438" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.033395806089, + 38.98770536102443, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05439" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0362772955056, + 38.98811779035975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05440" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0343469233192, + 38.98794814504181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H05441" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99161243571504, + 38.95228137975813, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05442" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99161369383835, + 38.95139350662461, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05443" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97901411267132, + 38.90722812553003, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H05444" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93057299692924, + 38.90933952346587, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05445" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97016135366849, + 38.90190040853298, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H05446" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94569905425418, + 38.866017416139044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05447" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9664628907411, + 38.86022461631165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H05448" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98149892483617, + 38.91436822324133, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H05449" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05738066633528, + 38.96204035802617, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05877" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02672198812148, + 38.87525681603104, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H05878" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00893086017508, + 38.88027864840328, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H05879" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05886760957021, + 38.980647648259456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05880" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04400764865369, + 38.91025665179926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H05881" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06622108215157, + 38.95582770549212, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05882" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05771878541042, + 38.937210291055656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/18/05

Report Problem", + "NAME": "H05883" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05663030077615, + 38.936047221472194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 12/28/06

Report Problem", + "NAME": "H05884" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05454077473271, + 38.93686234924214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/18/05

Report Problem", + "NAME": "H05885" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99864019741487, + 38.82926123447792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05886" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99745641046236, + 38.82928810495151, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05887" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98368090457289, + 38.8470321579273, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/04/07

Report Problem", + "NAME": "H05888" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94269384953485, + 38.88113131260068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05889" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94045486329308, + 38.88107126866343, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05890" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98840546659665, + 38.84447382078344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05891" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98336470998109, + 38.90033808492792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/15/07

Report Problem", + "NAME": "H05893" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05574712210667, + 38.981325253199344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05894" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98582011756288, + 38.9143420367465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H05895" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92949724953007, + 38.89490204921306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05896" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05236333188468, + 38.98061296067537, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05897" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98191136399151, + 38.9480850649206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H05898" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98309125741666, + 38.948789166333206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05899" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98499112236297, + 38.845402463460985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05900" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95878047871143, + 38.876417330625166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05901" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98716607804504, + 38.841079993145634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H05902" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96120563588212, + 38.89072530611001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05903" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00890315790349, + 38.9691662714932, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H05904" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00448081866452, + 38.94221659941282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05905" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00898844723822, + 38.969820695570306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05906" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00592802149238, + 38.942171142216594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H05907" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92343376407493, + 38.887454359169745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05908" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10866537092956, + 38.937139015092185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05909" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0318620165613, + 38.96689655251302, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05910" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04499151384205, + 38.91190145248213, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05911" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95231636309134, + 38.86204558560375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04468" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95625781226883, + 38.86059043119061, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04469" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95443400600354, + 38.86075983068309, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04470" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06302317020764, + 38.93634546611562, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/30/05

Report Problem", + "NAME": "H04471" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03364771156913, + 38.96997144820077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04472" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91519527312151, + 38.8898684452779, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H04473" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03369950263738, + 38.9064308841637, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04474" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03346881822355, + 38.906046293973915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04475" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98455836066543, + 38.91144827267494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H04476" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05762266448413, + 38.97592050825982, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 08/10/05

Report Problem", + "NAME": "H04477" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06484990255025, + 38.97386868439315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04478" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09459919171896, + 38.94439128461937, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/19/08

Report Problem", + "NAME": "H04479" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03442754185579, + 38.906317130673486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04480" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08176831929555, + 38.94975852306526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04481" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03461015845141, + 38.96679860848505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04482" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0162968995522, + 38.96138773597636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H04483" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02799037079716, + 38.90271471681653, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04484" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02851545987697, + 38.96903032518056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04485" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06992437653813, + 38.94616720989705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/23/07

Report Problem", + "NAME": "H04486" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03469240711132, + 38.966179582504225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04487" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97632962235454, + 38.90502070216662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H04491" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0061758185045, + 38.837663683795775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04492" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03972495423868, + 38.938451513701864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H04493" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05844219050198, + 38.97607782669315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04494" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02015825537079, + 38.978263448788546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H04495" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01261704659235, + 38.93355893336584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04496" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00595518369728, + 38.92639592030899, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/26/07

Report Problem", + "NAME": "H04497" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03139045830304, + 38.96832632434839, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04498" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06795762031446, + 38.962133518683494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04499" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97682805764099, + 38.92009805781247, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H04500" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97774151389005, + 38.91927053232404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04501" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97089137062612, + 38.925524117337886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04502" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09248884383969, + 38.944055928231755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H04503" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96808343928033, + 38.87488510456729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04504" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9501976712504, + 38.89185527670701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H04988" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05740504133091, + 38.96879537961942, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04989" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05690530712651, + 38.967334919084706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04990" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06706735726398, + 38.914759905473645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/28/07

Report Problem", + "NAME": "H04991" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03573820275865, + 38.898602017775055, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H04992" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05717434172206, + 38.98284093566841, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04993" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00746630807164, + 38.827846881484916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04994" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00675272397862, + 38.82691515204219, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04995" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96789522660588, + 38.86451209794541, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H04996" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04408173399972, + 38.93802545390631, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H04997" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00101105172736, + 38.8479719285518, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04998" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0080961753302, + 38.91391932397774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H04999" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03234902990685, + 38.943631068478105, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H05000" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02606052471145, + 38.94301346401148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H05001" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05611670776105, + 38.96759030558905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05002" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01774736621778, + 38.88612783101672, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H05003" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94628259926158, + 38.867838367166144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05004" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95872952250073, + 38.894223326987415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, USP

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05005" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08199239046205, + 38.92010320964475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H05006" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98665072304348, + 38.875997474552044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H05007" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0007649709477, + 38.8989641137893, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05008" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08035598957918, + 38.94329651808345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05009" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00778057749709, + 38.95663694563501, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05010" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95737387281919, + 38.89634168917012, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H05011" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94935583323286, + 38.86279905532669, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05012" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9493118132755, + 38.861995188010155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/30/07

Report Problem", + "NAME": "H05013" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94810462469599, + 38.862929749567634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05014" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92573217709304, + 38.888725268143325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H05015" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00378935518785, + 38.94444814746786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05016" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95873679521195, + 38.85544184778508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05017" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95632262760772, + 38.88539765774176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05018" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.013751640455, + 38.86740455536052, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05019" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01374002562615, + 38.86962053501322, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05020" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01373952713539, + 38.8708619383729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05021" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94572859198435, + 38.867374547179196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05450" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0080843981899, + 38.96575684595789, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05451" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92908147085333, + 38.87853815209767, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05452" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08676262875414, + 38.90773519732001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05453" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00304861681786, + 38.942972044474814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05454" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9710168513011, + 38.86208656965696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05455" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0525950951507, + 38.9783977166296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05456" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92039992813483, + 38.88443601769575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/30/07

Report Problem", + "NAME": "H05457" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00774987251386, + 38.88624695002779, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H05458" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96296106266753, + 38.880172655067256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05459" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96010702524387, + 38.85652863230421, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/03/07

Report Problem", + "NAME": "H05460" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9662578523234, + 38.87374476757092, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05461" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94943102200209, + 38.886418860120045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05462" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0581065194399, + 38.9649632765295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05463" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97100178978974, + 38.873151964906526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05464" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04250687819595, + 38.898263820177455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05465" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97872822433058, + 38.90025184338745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H05466" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96231879528543, + 38.87465626705615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05467" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96337657050077, + 38.874653991134956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05468" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01972369086437, + 38.90970046948859, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05469" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98213572489016, + 38.91204948628484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H05470" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99489040500387, + 38.8402116498363, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05471" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97087082647637, + 38.86955353433788, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/02/07

Report Problem", + "NAME": "H05472" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96469986458378, + 38.86956562380608, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05473" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9775595192457, + 38.869528823835125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H05474" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96092748084953, + 38.87334836665557, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05475" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.922639640045, + 38.8915201999504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05476" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02007291248464, + 38.912556504387986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05477" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.020000900572, + 38.90871248631782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05478" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02009328912031, + 38.911174684688625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05479" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01972444321378, + 38.90729285407107, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H05480" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02000025945296, + 38.90650833325808, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/15/08

Report Problem", + "NAME": "H05481" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95877757076808, + 38.87466835813162, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05482" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01039973341926, + 38.96915598667947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05483" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0322345569651, + 38.97218473781162, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05912" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03217924586829, + 38.97128920824938, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05913" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99951068047747, + 38.824315312506684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05914" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00172940827434, + 38.84724488502374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05915" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99843658986222, + 38.82674694162075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H05916" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99978832639101, + 38.82574446233457, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05917" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99884286278379, + 38.8254161250497, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05918" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.035035526915, + 38.97221003807122, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05919" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03360726182474, + 38.972214673101284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05920" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03608325922893, + 38.97221785392148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05921" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03786074088279, + 38.8977929927947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H05922" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05418359015695, + 38.94222665722753, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/01/07

Report Problem", + "NAME": "H05923" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00508365485885, + 38.83955913286491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05924" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04228618323036, + 38.9510751853388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H05925" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04183480223777, + 38.949728808862076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H05926" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05402398637719, + 38.98167506726326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/20/06

Report Problem", + "NAME": "H05927" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0582721154005, + 38.98195930008615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05928" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04672468460491, + 38.8997015652967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05929" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06758056741153, + 38.95661478150731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05930" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04660115537602, + 38.89724079135494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H05931" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99602759486328, + 38.85989501773551, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H05933" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98407197411996, + 38.90376975429171, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H05934" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99734390812782, + 38.83410601724103, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05935" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9248936665511, + 38.89502238752707, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05936" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05571137420573, + 38.95077943808594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05937" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02420977546612, + 38.90560348594483, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/25/07

Report Problem", + "NAME": "H05938" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01910040045848, + 38.905598874818324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05939" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02727092529912, + 38.90560644188606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H05940" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9336161211522, + 38.87855889753185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05941" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00344143825373, + 38.920826177353554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05942" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05581898379164, + 38.92016268468825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/10/07

Report Problem", + "NAME": "H05943" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01811280752959, + 38.92948476283356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H05944" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98916273353832, + 38.86258019025154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05945" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00210325452981, + 38.90192618952126, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H05946" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06133971936323, + 38.918426300346006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05947" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09667756841523, + 38.92180859230028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04539" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9781831422131, + 38.89472447271752, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04540" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0272135623196, + 38.914143364447746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04541" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95899006206633, + 38.85654342450508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H04542" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02663345176936, + 38.97944592406447, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04543" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97109502279811, + 38.937750493672844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04544" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9710962653787, + 38.936250270157906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04545" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98363959153033, + 38.92420523925874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H04546" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98236143859955, + 38.92319361722307, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H04547" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95344548516675, + 38.86904937116085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04548" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01294550710134, + 38.966053410712604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04549" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00421993728946, + 38.84020610015136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04550" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00558960508017, + 38.83842083779641, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04551" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06152500263343, + 38.95189563901555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04552" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00356182364052, + 38.84108978791524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04553" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07191214253295, + 38.916307376897855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H04554" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0289008638822, + 38.904668956389905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04555" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95759948747545, + 38.89210020789515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04556" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06172900303278, + 38.974461736861244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04557" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10182195815486, + 38.938127424066955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04558" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10050397805239, + 38.93916239323292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04559" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09413634421344, + 38.94486148554946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/27/07

Report Problem", + "NAME": "H04560" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09415609997177, + 38.945600482518, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/04/07

Report Problem", + "NAME": "H04561" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09926084706531, + 38.94025000932464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/25/08

Report Problem", + "NAME": "H04562" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09842231626308, + 38.94692327645336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H04563" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08143300808412, + 38.92465467877779, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04564" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08040314915684, + 38.92458274875631, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H04565" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08172610155317, + 38.923711464988465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04566" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00852332895758, + 38.94824079874554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04567" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97017022565078, + 38.86124873563855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04568" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97117841507207, + 38.860742274255394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04569" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97242170260776, + 38.86062560921024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04570" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9717152970167, + 38.86132835820676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04571" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9789100728303, + 38.86659355041834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04572" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95326669240247, + 38.871229676459286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H06054" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03608648730275, + 38.96546641908029, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06055" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99791451439145, + 38.910481742611296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H06056" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9255236979852, + 38.89258039620722, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H06057" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00453927684698, + 38.94292090109212, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06058" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09427323290882, + 38.9215427300685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06059" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91723851288903, + 38.88728880266766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06060" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96257705068113, + 38.87105177316388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06061" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05446446347828, + 38.980964393689995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H06063" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04814285097343, + 38.98891368947569, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06064" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99161978324591, + 38.94885800217803, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06065" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01627270761252, + 38.89848595421249, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H06066" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0645614985153, + 38.95750909848299, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06067" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02332911250363, + 38.96319848238286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06068" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.921110169987, + 38.88732829004167, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06069" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97416249509429, + 38.8539286035758, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06070" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05419077303019, + 38.97900655669684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H06071" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97126260637947, + 38.85412903898753, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06072" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0752315624423, + 38.90566486565189, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H06073" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95950074013167, + 38.921375690427816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H06074" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03079930585041, + 38.9331692262455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H06075" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98853013540462, + 38.83259545879112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06076" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95490457174867, + 38.89471281504109, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H06077" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99849754775217, + 38.95693152182779, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06078" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99733925205196, + 38.95719635311464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06079" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99586160890748, + 38.95733626250208, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06080" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99793840925834, + 38.95777908260535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06081" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96809799755391, + 38.85987505231541, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06082" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05976869507656, + 38.981008871324924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H06083" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02608698963667, + 38.90273529100587, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H06084" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08769689462318, + 38.942346703998936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06085" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03472261644147, + 38.96547009301509, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06086" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94485381033545, + 38.886486783862864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06087" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94220207343118, + 38.88646454828485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06088" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94356073568663, + 38.88646521270205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06089" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98747781304758, + 38.842167959259015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H05948" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94099601528771, + 38.883244645922076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05949" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10215977787801, + 38.92727730470362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05950" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03837335547803, + 38.98224010102738, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05951" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01802050851096, + 38.8637222724142, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05952" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01609600496734, + 38.8631720312659, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05953" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01802035566848, + 38.86311692491142, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05954" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01599134806169, + 38.86389038571573, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05955" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01820848591795, + 38.871453359366775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05956" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02456242290125, + 38.888849802552556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H05957" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06539118410345, + 38.95645391376966, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05958" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94038040174146, + 38.907151875444924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05959" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95681652686993, + 38.85847977659861, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/19/07

Report Problem", + "NAME": "H05960" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95611290911444, + 38.89284632671675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05961" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02202192001616, + 38.90074432644311, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05962" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9717285935308, + 38.91807873666925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05963" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98282966520019, + 38.94984280819875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05964" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04659681880526, + 38.89900236038672, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H05965" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04659545148175, + 38.8978973862243, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H05966" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04156943785787, + 38.9163617204276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H05967" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06351862614333, + 38.93552794684563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/02/07

Report Problem", + "NAME": "H05968" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07204188430285, + 38.96586789486272, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05969" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99865951636669, + 38.9584219405531, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05970" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97242537636323, + 38.93107214126279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05971" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97524397992515, + 38.88313590768739, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H05972" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97487754891152, + 38.886512612792615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05973" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97451783087179, + 38.881905178881524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H05974" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97360028344937, + 38.88361208229724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H05975" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97413080218112, + 38.88266427561052, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05976" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96241389265245, + 38.8827944708599, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05977" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09588426819892, + 38.923062051888984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05979" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9411022380476, + 38.88397998205178, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05980" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01552695181967, + 38.97072159974498, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05981" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06683192526043, + 38.9561772750103, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05982" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98823338104727, + 38.95168280418546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05983" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05509903031954, + 38.968148291757686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05984" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01790540310722, + 38.920408302321555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/02/06

Report Problem", + "NAME": "H05985" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98764593793524, + 38.950961649418005, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05986" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01613912936068, + 38.97072151686046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/09/07

Report Problem", + "NAME": "H05987" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08483002694584, + 38.91203847116491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H05988" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04474705822429, + 38.90862127541762, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H05989" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04481270414615, + 38.90951482401254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05990" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08686283829391, + 38.914500695811604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H05991" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00049191615116, + 38.91539354712342, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H05992" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02999478653459, + 38.91020337294831, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H05994" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.944219965088, + 38.88578784680498, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05995" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03025368005234, + 38.90923054927279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/15/07

Report Problem", + "NAME": "H05996" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93141264742363, + 38.87852562644527, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05997" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93119704708621, + 38.877684547874196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05998" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93174383663276, + 38.875606685377754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05999" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08859089824388, + 38.91637633057543, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06000" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00113383280268, + 38.960589987119796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06001" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98149197052334, + 38.94880871526207, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06002" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98273343178656, + 38.92135356986621, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06003" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08905254249221, + 38.908255436197464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H06004" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08642463903071, + 38.911785465336784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06005" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98066441841266, + 38.94719041532141, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06006" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92411977843128, + 38.902247901349874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06007" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98153274088584, + 38.920302186893004, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06008" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99781064518963, + 38.95919601642933, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06009" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09300732693742, + 38.92526199349452, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06010" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99850861227173, + 38.960232643607384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06011" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06405404571017, + 38.93764910925721, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/10/06

Report Problem", + "NAME": "H06012" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98842342578274, + 38.94519929584205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06013" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97411088595291, + 38.935172178844155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/14/08

Report Problem", + "NAME": "H06015" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92867480510196, + 38.9071245336008, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H06016" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96472925627012, + 38.91872350554345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H06017" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96592860396558, + 38.918778055495416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06018" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00914256544131, + 38.95702328350516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06019" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92728840762776, + 38.89352356757334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06020" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92721286145478, + 38.8944360054471, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06021" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92787943208923, + 38.89086238290757, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06022" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93911714344618, + 38.901571990398054, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/11/07

Report Problem", + "NAME": "H06023" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09339662574216, + 38.924525072520275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06024" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04023501742162, + 38.92222307759083, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H06025" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94808340216768, + 38.884660454119654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06026" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94078687736402, + 38.885615204732666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H06027" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93287718357305, + 38.87726696848328, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06028" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98823019091473, + 38.95227836768254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darily

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06029" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9178475664839, + 38.88642737359512, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/25/07

Report Problem", + "NAME": "H06030" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9572727160884, + 38.86470335691979, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H06031" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02547835911794, + 38.98158889462725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06032" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97488577636561, + 38.894901311216735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H06033" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09692314508263, + 38.94121920977975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H06034" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99784274890723, + 38.82406187624248, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H06035" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99940687597602, + 38.82286928083087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/11/07

Report Problem", + "NAME": "H06036" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99898173788768, + 38.823672941894145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06037" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97939728263239, + 38.947171984129106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06038" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9901443534295, + 38.91246358569445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06039" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98895811107158, + 38.911962165571076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06040" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0062725280622, + 38.94743688028898, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06041" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98839846497783, + 38.922078935114584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06042" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05625078616974, + 38.96293341782501, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06043" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98102245181586, + 38.94066209768925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06044" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05473525151494, + 38.97802773066404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H06045" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93272102105684, + 38.87855594404109, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06046" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99892992714582, + 38.9620604321043, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06047" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97468490040116, + 38.929627710810465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06048" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97387654143601, + 38.91952447869471, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06049" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9816834075737, + 38.916724318803766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06050" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93191486500743, + 38.90291925058489, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H06051" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.940176118171, + 38.90634862262025, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H06052" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02553748370023, + 38.94158888264981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H06053" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00097602102483, + 38.96431731509948, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06090" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0577599003193, + 38.93637889482694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/28/06

Report Problem", + "NAME": "H06091" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00260174349097, + 38.96441213808114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06092" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94900843706566, + 38.89549251459384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/22/07

Report Problem", + "NAME": "H06093" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96222774679589, + 38.86504851074198, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06094" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05471040593682, + 38.982734754230385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06095" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92486980613421, + 38.88597992579633, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06096" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93861073776398, + 38.874721458004274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06097" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09245548379204, + 38.95474728762475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/12/07

Report Problem", + "NAME": "H06098" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9501536570703, + 38.86125808516608, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06099" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96343393682282, + 38.9186451132847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06100" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9619882486635, + 38.918575666177475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06101" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05489042359085, + 38.96963052499907, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H06102" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05673447072746, + 38.970610453077406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06103" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00406035059625, + 38.83296137096221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06104" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04650463091485, + 38.905760159341455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H06105" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98518230763166, + 38.91356362838349, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H06106" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00242326872942, + 38.938074260395545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/28/08

Report Problem", + "NAME": "H06107" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00288284917531, + 38.94050063367342, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06108" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00165039664131, + 38.93402393565909, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06109" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0022579435767, + 38.93724085221533, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06110" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00496828811649, + 38.940720185764945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06111" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00136856635177, + 38.93258892560665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06112" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00554621031077, + 38.94095562747284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06113" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00258860043944, + 38.93898181547361, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/28/08

Report Problem", + "NAME": "H06114" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00200521433875, + 38.93590150313327, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06115" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00291715284176, + 38.939920805139906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/28/08

Report Problem", + "NAME": "H06116" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00702127244165, + 38.94214178670973, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06117" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0017748967706, + 38.93470564605151, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06118" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00348971845982, + 38.94080676388743, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06119" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95670952665942, + 38.85625743941417, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 01/30/08

Report Problem", + "NAME": "H06120" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91358531172793, + 38.892999802024995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H06121" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98608126307448, + 38.91326577017279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H06122" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96469978438265, + 38.86558102386654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06123" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9852286268318, + 38.91166283889424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H06124" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99867448733681, + 38.94999921111817, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06125" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98027490100323, + 38.90666245882123, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06126" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09420823086555, + 38.92029601175147, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06127" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98034693181015, + 38.90784886123743, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H06128" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04176581824595, + 38.905786064837585, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06129" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98640305577776, + 38.891955140684495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 04/13/06

Report Problem", + "NAME": "H06130" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99274741699661, + 38.95131693106683, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06131" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99295755905642, + 38.952318708713214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06132" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99802855821795, + 38.96214426019148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06133" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98808983547468, + 38.93826546532368, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06134" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96605687639418, + 38.8652612942667, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H06135" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03870982584631, + 38.906570744624176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06136" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03867829737317, + 38.90719478135571, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H06137" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99363677130809, + 38.838683349531685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H06139" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99684001492463, + 38.85701257235884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H06140" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99661807443468, + 38.858125620041555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H06141" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05235896186663, + 38.98151379365338, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H06142" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06644973067202, + 38.97271197567534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06143" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06646379467917, + 38.97410667667713, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, Metropolitan

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06144" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93723731837102, + 38.888360033807224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06145" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99919591303542, + 38.94715852783032, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06146" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00581997092837, + 38.83292053319816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H06147" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9407515068607, + 38.88645899298755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06148" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97916501147942, + 38.8671966822501, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06149" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09505145979456, + 38.924103499999696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06150" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96973994628644, + 38.91966094780212, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/05/08

Report Problem", + "NAME": "H06151" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94241885041961, + 38.8857699108868, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06152" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10045663680148, + 38.948500283782636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H06153" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95529213580222, + 38.8713837024314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06154" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09212590931568, + 38.92023234351756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06155" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99666803228124, + 38.83934810097682, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H06156" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0089091285063, + 38.955727796172376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06157" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9529222497127, + 38.86814368115873, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06158" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03709180498784, + 38.92866528056472, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H06159" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99621184832708, + 38.9582694220759, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06160" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98836708642243, + 38.94081620030147, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06161" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99518611881898, + 38.95896328154054, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06162" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09416615912777, + 38.94119042068433, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H06163" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09225954766166, + 38.921239684561534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06164" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92345936281907, + 38.893063604169335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H06165" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92307132049972, + 38.89379641455867, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06166" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92288369832943, + 38.89470798302518, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06167" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99381391780702, + 38.84060029433971, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H06168" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99390928457731, + 38.84244053613268, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H06170" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99522614225198, + 38.8428721920872, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H06171" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00864943260682, + 38.96462427964531, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06172" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98970179647013, + 38.833358665734416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06173" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06744837922692, + 38.94625850431112, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 01/23/07

Report Problem", + "NAME": "H06174" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91631320690418, + 38.89705537463737, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06175" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0359271720447, + 38.96679543672169, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06176" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94113667628936, + 38.86822133839423, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06177" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07329495737362, + 38.95274079191687, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H06178" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00931592319759, + 38.8730479486731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H06179" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08186968487222, + 38.921479804219885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H06180" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99728308502863, + 38.85889714578509, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H06181" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94276031089639, + 38.87804759224004, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06182" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94343806433534, + 38.87852689879248, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06183" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00161160664943, + 38.82523898608754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06184" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02138445218266, + 38.920593523172116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/29/06

Report Problem", + "NAME": "H06185" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94141218446286, + 38.8788288703742, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06186" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9408989893484, + 38.878240705966995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06187" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98724337294172, + 38.91286907656138, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H06188" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11141066065733, + 38.931218377369206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H06189" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96551518143657, + 38.85742972918487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06190" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97782969378237, + 38.844973421971964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06191" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97892558862489, + 38.8447595573216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/04/07

Report Problem", + "NAME": "H06192" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03022941080225, + 38.987334138199124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H06193" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99661944495496, + 38.959820017084816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06194" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02038668311893, + 38.95543100422687, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H06195" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07629460210578, + 38.93100359485396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/05/08

Report Problem", + "NAME": "H06196" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98264504478333, + 38.84936345547199, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06197" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97339395910024, + 38.9204393004522, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H06199" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9774492876573, + 38.84374630891142, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/04/07

Report Problem", + "NAME": "H06200" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97619209644365, + 38.84390586007711, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06201" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98239542370581, + 38.850693234384096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H06202" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98436858810177, + 38.850261389634944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06203" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03776977908477, + 38.93577314821084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H06205" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05953436352812, + 38.95364893159056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H06206" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02977432924227, + 38.90052041671877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06207" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02940476343012, + 38.90126625818928, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06208" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.094258520684, + 38.91929347910597, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06209" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09428319469734, + 38.91812243001221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06210" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02602616166911, + 38.9626041252422, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06211" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01565576904014, + 38.81413806822103, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06212" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00581539077301, + 38.83013838688788, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06213" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97233486109403, + 38.92153696207284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06214" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98696677769223, + 38.9257163885513, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H06215" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98064085409298, + 38.856315199295395, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/30/08

Report Problem", + "NAME": "H06216" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9839633760717, + 38.92590815338525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06217" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97476262795232, + 38.883891878424166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H06218" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97325298149521, + 38.88669385200874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H06219" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03259305120088, + 38.9422787396782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H06220" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99507144966911, + 38.947387471208174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06221" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99572572291981, + 38.94883266792357, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/07/07

Report Problem", + "NAME": "H06222" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99649820472746, + 38.949493432630554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06223" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99687157170628, + 38.9555856730984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06224" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99700678466596, + 38.9487844684223, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06225" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99976600062061, + 38.95802367481772, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06226" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06368184951641, + 38.95697165243259, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H06227" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0306197951636, + 38.94226810293982, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H06228" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99505617968411, + 38.949166902620284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06229" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9423743879173, + 38.880398647126576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06230" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93935168822561, + 38.89562116997079, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06231" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96427747305485, + 38.93221666532227, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06232" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94240438029138, + 38.894600184110566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06233" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94239217796873, + 38.89529333600655, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H06234" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9743369601892, + 38.88605178866275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H06235" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04901240427685, + 38.892242610504674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H06236" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96796990930274, + 38.92563082237489, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06237" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98433653142877, + 38.91245824011285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H06238" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92428916671932, + 38.882295453971835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06239" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97628602285232, + 38.921413876135965, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H06240" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97438081236051, + 38.8493411338829, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06241" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97048134432265, + 38.87494720860754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H06242" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97840582822322, + 38.84620436247066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06243" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02973124928668, + 38.918889394187204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H06244" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99402330572703, + 38.958210245509385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06245" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02891101827966, + 38.89621451062037, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H06246" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9944033682652, + 38.959210784624524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H06247" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99512996259504, + 38.95814962621087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06248" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04770241675219, + 38.89224740476481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H06249" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93783640181822, + 38.897391706500734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06250" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03622686328043, + 38.93930640229491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H06251" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01819944491953, + 38.920364269245525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/22/06

Report Problem", + "NAME": "H06252" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02564083274441, + 38.95203371777778, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H06253" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99303127674953, + 38.836687176739176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H06254" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00344501590587, + 38.88889845719042, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H06255" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01059001621702, + 38.83092087782062, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06256" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95319244257158, + 38.871902817757814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06257" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95508242451481, + 38.869305031318554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06258" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98113301212183, + 38.85069970343017, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06259" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9294998001535, + 38.90469723853815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H06260" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94765038391822, + 38.864187581226396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H06261" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97428118517571, + 38.884679610619116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/10/06

Report Problem", + "NAME": "H06262" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92864490045704, + 38.90454047864754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H06263" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92957791443911, + 38.905929376041406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H06264" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93277449939283, + 38.90458369062743, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/31/07

Report Problem", + "NAME": "H06265" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00638355957874, + 38.9483255138871, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06266" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09315298852276, + 38.91863010022487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H06267" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94243997268384, + 38.88480422256583, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06268" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97007377156672, + 38.85570729630734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H06269" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9722663752238, + 38.86739029765275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H06270" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00356677372471, + 38.88460711372881, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H06271" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97198984969701, + 38.903615619519506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H06272" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03827222194552, + 38.935256926276104, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H06273" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07035115169673, + 38.927454508024304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06274" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03752924335878, + 38.91880127357638, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H06275" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99488631992267, + 38.884702013610074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H06276" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06994602229719, + 38.93161702385608, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 03/19/07

Report Problem", + "NAME": "H06277" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93912840534068, + 38.89472418970253, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H06278" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98254085343383, + 38.84801518308433, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H06279" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98692561990302, + 38.86815780822454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H06280" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93937412872188, + 38.89841960325725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/07/07

Report Problem", + "NAME": "H06282" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93499296813131, + 38.87638436050374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H06283" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08612362235728, + 38.92073224430046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06285" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.995857574278, + 38.960452624411296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H06286" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93477383823897, + 38.874801588678174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H06287" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99712425449216, + 38.94883649416743, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06288" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00092780262983, + 38.96265213137823, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "null

In Service


Last Inspection Date: 01/10/08

Report Problem", + "NAME": "H06289" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96619350160297, + 38.87301705032258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H06290" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09550369065241, + 38.942237450514476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H06291" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98251585590089, + 38.9132035929625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H06292" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00456077768119, + 38.960220385006615, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/12/08

Report Problem", + "NAME": "H06293" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96573375267165, + 38.87062868046402, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06294" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09423838564805, + 38.942076895686746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Super Centurion

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H06295" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99539474346301, + 38.95540096383598, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H06296" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9940175433231, + 38.830156908855116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H06297" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99062657159399, + 38.94920961886874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06298" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99904156565336, + 38.947876927884714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06299" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99862706836099, + 38.944262314878884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H06300" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08258487213782, + 38.94429687555969, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H06301" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93925477538414, + 38.899156019925314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H06302" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0885594590181, + 38.94328195208756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H06303" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01053249848282, + 38.91562512813556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H03781" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03149860060336, + 38.952862722731545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H03782" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02978952208173, + 38.98523809475416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H03783" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00214318600925, + 38.892608703969614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03784" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9761558275395, + 38.93821864366102, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H03785" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02220534254324, + 38.8932120025607, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03786" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02111058852749, + 38.89195656479307, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03787" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00675234093197, + 38.90957841675109, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03788" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08362394544916, + 38.95807643903714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H03789" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94246674009094, + 38.893803478602955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H03790" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01611616484657, + 38.90387376595241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03791" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06974704261751, + 38.94702002188165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H03792" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04287549192607, + 38.94308301345826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H03793" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02988559150447, + 38.949782298964884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H03794" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02730913986697, + 38.949800585428775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H03795" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03304522449442, + 38.949794447490724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H03796" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96539942674859, + 38.929515807648194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03797" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96223814712577, + 38.863772192872155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03798" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02965254445662, + 38.888705919570135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03800" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97243633867602, + 38.926373192424016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H03801" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97207397152667, + 38.923561069928915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H03802" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01428659595271, + 38.91623474670085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03803" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00579832133425, + 38.88415803742989, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H03804" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0150172330628, + 38.910422521203124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03805" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00571479737653, + 38.89109405137284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H03806" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08614522626061, + 38.95215297766018, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H03807" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01103439773551, + 38.90863036801653, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H03808" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0779268603956, + 38.947865048048385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H03809" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03740162191232, + 38.933698483600004, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H03810" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10274984945097, + 38.931402965317936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H03811" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0299062475637, + 38.95191435380435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H03812" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01661686463513, + 38.9096776570696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H03813" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01782972779178, + 38.909592907958555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H03814" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99926917484655, + 38.90911252690702, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H03815" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04401075380775, + 38.941242810660405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H04573" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98247566907497, + 38.86455527497024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04574" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97915190076975, + 38.92825000615917, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04575" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00848617036823, + 38.947455883147875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04576" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08865688967799, + 38.926663430018685, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04577" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03840922395163, + 38.90295310786932, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H04578" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97231945655625, + 38.925513357060346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H04579" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97319377949559, + 38.92563539836224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H04580" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97514742034268, + 38.942727686927896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/31/08

Report Problem", + "NAME": "H04581" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95870943408765, + 38.88206807182069, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04582" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08618690709217, + 38.912793332138605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04583" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96519669330054, + 38.8764126446771, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04584" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02675807121229, + 38.98448400242735, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04585" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99626579690941, + 38.92570171447717, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H04586" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9751156022107, + 38.90090247904665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H04587" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99626030430434, + 38.927302167533, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/04/08

Report Problem", + "NAME": "H04588" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9962482645452, + 38.92642002798468, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/04/08

Report Problem", + "NAME": "H04589" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9962433206097, + 38.92854280077351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04590" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0220432668738, + 38.89021227240611, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04591" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93185908319334, + 38.87966959348911, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04592" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.074497746621, + 38.948771462686175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04593" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95448218729926, + 38.872255231877396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04594" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00334698427989, + 38.8473831294017, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04595" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00214347673958, + 38.846654690195734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04596" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95750475810465, + 38.85932006460698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/21/07

Report Problem", + "NAME": "H04597" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98458713840753, + 38.9236190345875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H04598" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98323534717085, + 38.922626663047446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H04599" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01623885023443, + 38.97141012872568, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04600" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01978796767985, + 38.892988155693764, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04601" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02647210699517, + 38.93182104052187, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04602" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1036934056998, + 38.93561914648893, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 07/19/05

Report Problem", + "NAME": "H04603" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07574784782663, + 38.95474720801586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H04604" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00462868518309, + 38.961212875890844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04605" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93778117916608, + 38.87734643562837, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H04606" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01375841765004, + 38.86520188988051, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05022" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0137522976389, + 38.866090948835264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05023" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98356280950657, + 38.92075862660752, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05024" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0034120908475, + 38.904445930173985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H05025" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0928556023799, + 38.93770057371047, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/09/08

Report Problem", + "NAME": "H05026" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01533724253665, + 38.88896453238649, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H05027" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05861441732024, + 38.9682167026899, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05028" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06556747156624, + 38.97497536009743, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy, K81D

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05029" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98606535106647, + 38.9279612915883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/10/08

Report Problem", + "NAME": "H05030" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03162297791978, + 38.885040892859934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H05031" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0323420800206, + 38.88373832686895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H05032" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0321542074068, + 38.887229117817036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H05033" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03354985746132, + 38.886070833104874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H05034" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03140953148022, + 38.8858773877474, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H05035" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03551169828295, + 38.92332814579259, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/28/06

Report Problem", + "NAME": "H05036" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99046609877054, + 38.94795288820776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05037" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00594353330762, + 38.943659814858094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05038" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00161618402952, + 38.943020627720564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05039" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01238923987928, + 38.82705428501907, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05040" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01182993991338, + 38.83022063892504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H05041" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00884112192549, + 38.82694375854108, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H05042" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01298400896576, + 38.83068515480144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H05043" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09808788545327, + 38.92801164701411, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05044" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98863224263212, + 38.92218740927983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H05045" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96052632262699, + 38.86557783185515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H05046" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98921066185777, + 38.92091357011748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H05048" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98215085199892, + 38.86957207251508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H05049" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98522718555996, + 38.86891050142056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/25/06

Report Problem", + "NAME": "H05050" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0499546101124, + 38.89358347676023, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H05051" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0497332798997, + 38.89744016121968, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H05052" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9864209424278, + 38.86889759315796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H05053" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08101779113183, + 38.91924394523919, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H05054" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97601310001137, + 38.87061481305235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05055" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98626301435364, + 38.93482434738986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05057" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99391835311438, + 38.92353555683909, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05484" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97895384996356, + 38.8562319667927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/04/08

Report Problem", + "NAME": "H05486" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06662986094076, + 38.93897199708627, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/26/07

Report Problem", + "NAME": "H05487" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08500477656486, + 38.94636157876048, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H05488" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09570676145275, + 38.916981727412946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05489" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93569810511126, + 38.90205788907862, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H05490" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03172492017777, + 38.92002771165384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05491" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03175860433724, + 38.91912332954183, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H05492" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03174318824335, + 38.918167559090534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H05493" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93593440790247, + 38.87345590750142, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05494" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99273157234356, + 38.950348189420104, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05495" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99161632767127, + 38.95018658740326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05496" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05781221320706, + 38.96775119564866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05497" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97100982029177, + 38.8450158706856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05498" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95646963919498, + 38.87472456184263, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05499" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99414263553922, + 38.950813852234106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05500" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9384791468379, + 38.873314528676836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/21/07

Report Problem", + "NAME": "H05501" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99404448807678, + 38.95228106051506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05502" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0457231216707, + 38.9408742818191, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H05503" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04657929348775, + 38.94069928202046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H05504" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00709849638515, + 38.94292329601782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05505" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94576109396932, + 38.89259422153347, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H05506" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94558188396927, + 38.891913870936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H05507" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92254397289948, + 38.88875466375766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05508" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02826356909192, + 38.94075401556329, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H05509" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97538502013988, + 38.90551103866676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H05510" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08693398269055, + 38.9388125000543, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05511" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05325094029833, + 38.94873202157929, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05512" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00633307475219, + 38.955560482437505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05513" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00719671740485, + 38.95525781782415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05514" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06103596832862, + 38.97783349362207, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05516" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92157449404803, + 38.88469210093975, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05517" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91953182301285, + 38.88511250215564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05518" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98966503465766, + 38.84440642080874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05519" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97972079459664, + 38.932163036297226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H03816" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07583127121498, + 38.95837914262287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03817" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99837109929354, + 38.88214955232073, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 11/13/06

Report Problem", + "NAME": "H03818" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02003675885621, + 38.97483586626943, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/14/07

Report Problem", + "NAME": "H03819" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0091949277422, + 38.91029113423856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H03820" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.019984888335, + 38.976081470009355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H03821" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03283127617412, + 38.93309383213818, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 01/10/08

Report Problem", + "NAME": "H03822" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01836975361316, + 38.93061661674601, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/02/08

Report Problem", + "NAME": "H03823" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02592774909643, + 38.880608926839926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H03824" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02482457111897, + 38.87955117612572, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03825" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02458352960875, + 38.88045888551386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H03826" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06137111328788, + 38.97298340375881, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/05/07

Report Problem", + "NAME": "H03827" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05998389447528, + 38.97390770177412, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H03828" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99104257244016, + 38.841369859504724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H03829" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02968995198691, + 38.96228283779921, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04106" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02662046021695, + 38.98075318200874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04107" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08394924988205, + 38.946342793546954, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/10/07

Report Problem", + "NAME": "H04108" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01583246259305, + 38.95321295549329, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04109" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0361461916634, + 38.981397163890676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04110" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01152132910175, + 38.955324880489755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04111" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97843316131892, + 38.93970995865392, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H04112" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05994899536816, + 38.96250647173729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04113" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0280115590136, + 38.915452420212716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04114" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01041469430427, + 38.959483864368494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04115" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98606520204657, + 38.90653434741664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/29/07

Report Problem", + "NAME": "H04116" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04370504333374, + 38.987865345200035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04117" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07970651270003, + 38.91924776570916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04118" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92068931982136, + 38.89586850335346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04119" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07970415217241, + 38.92059208929606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04120" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07927422833039, + 38.94633428348339, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04121" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97721557555866, + 38.938385229237035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04122" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97861261895501, + 38.87306796392008, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04123" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93571146523806, + 38.87753775199594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H04124" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06768601573768, + 38.94033119237723, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/07/07

Report Problem", + "NAME": "H04125" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03841979231008, + 38.98871415213123, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04607" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00897091413475, + 38.95080860113652, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04608" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95566920917643, + 38.8936459042767, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04609" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03065180386986, + 38.90534913608487, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04610" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00429123856172, + 38.836207020085304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04611" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98069374773931, + 38.935798078047505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H04612" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00369633955648, + 38.966582870900986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04613" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08691668956509, + 38.922583751131285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04614" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00268272882413, + 38.96368794505766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04615" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96319606119214, + 38.87902539358634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04616" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04282914906338, + 38.93500849084072, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H04617" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09660518402474, + 38.939429722714515, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04618" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92651601450959, + 38.88274017910485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H04619" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98902701740278, + 38.946346369571366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04620" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96752281405584, + 38.8767567778405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04621" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95022879417982, + 38.89097905448548, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H04622" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94830174370891, + 38.891979894580444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04623" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98812795640582, + 38.939028588822886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04624" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10462350669324, + 38.93353791221197, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04625" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10449779057846, + 38.93469499767204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04626" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03139073260229, + 38.968320324785346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04627" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03330130136223, + 38.96889766601351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04628" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09758800028382, + 38.91667825707182, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/20/08

Report Problem", + "NAME": "H04629" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97609021828806, + 38.942729442004406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04630" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94707593891499, + 38.86494256079356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04631" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97719521721187, + 38.94191957448436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04632" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97736728403088, + 38.94275638779594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04633" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02127003650206, + 38.9250013426471, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/22/06

Report Problem", + "NAME": "H04634" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0213887826405, + 38.92584291396384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H04635" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0291020981162, + 38.91028352972541, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H04636" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00210563764855, + 38.9076732829993, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H04637" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08760381600996, + 38.91255918756391, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04638" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99567095227769, + 38.94061964263085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04639" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10586745140442, + 38.93273603444349, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04640" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01143281127955, + 38.87430176593557, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H05058" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01133249622085, + 38.87329667250693, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H05059" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0107995114957, + 38.81858688196527, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/05/05

Report Problem", + "NAME": "H05060" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01077875586667, + 38.81794002988944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05061" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09842693223656, + 38.92688925880241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05062" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.963026527041, + 38.86144021089745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05063" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98480458702745, + 38.92004243464827, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05064" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97979974702947, + 38.89468716253029, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H05065" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00469927325149, + 38.90378396981618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H05066" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01893886607361, + 38.9626540244274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05067" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02104207062123, + 38.95432370915695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H05068" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09251123400333, + 38.941344793063415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/10/08

Report Problem", + "NAME": "H05069" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9856761222235, + 38.94225555225456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H05070" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92562213261203, + 38.887688045282744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H05071" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00750636305683, + 38.8302613460032, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05072" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00037855145172, + 38.844638493800275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H05074" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99917196697692, + 38.84466602128081, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05075" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00154609699699, + 38.84464487116169, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05076" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00787209540599, + 38.95353583511847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05077" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97995455193995, + 38.86956450942505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05078" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9576014048161, + 38.88683738905643, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05079" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95913925166877, + 38.88682973953758, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H05080" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00537921060618, + 38.84680100912937, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05081" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00799973529547, + 38.825209139206294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/14/07

Report Problem", + "NAME": "H05082" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96196872270433, + 38.93118879172168, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05083" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95767189735734, + 38.884352064981464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05084" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00826167700262, + 38.820695830109045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H05085" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94894867187764, + 38.86454140307832, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H05086" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01064260327846, + 38.819177330202, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05087" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00323280558295, + 38.84621122460502, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05088" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98667557492709, + 38.94175972814463, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05089" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98023005942686, + 38.94290812913477, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05090" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0001940108123, + 38.860781675858895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H05092" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99958320474774, + 38.860402600966225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H05093" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96306732961972, + 38.86279209913632, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05520" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93401829364757, + 38.873929042896556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05521" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00800020844989, + 38.95771740875306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05522" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0424771027105, + 38.90827484198636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05523" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04322636584824, + 38.91028066242064, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05524" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04240195724333, + 38.907292491047265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05525" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04469769490164, + 38.91266065297972, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H05526" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04451561389328, + 38.911836639587335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/25/07

Report Problem", + "NAME": "H05527" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96160296571458, + 38.855463680111455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H05528" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01024481073367, + 38.96814746468498, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05529" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00896588098301, + 38.968301061173875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05530" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96627164321573, + 38.874653836202945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05531" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0091197293331, + 38.96655373830583, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05532" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01145911397474, + 38.96827144053048, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/23/07

Report Problem", + "NAME": "H05533" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01024054727272, + 38.96738652977421, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H05534" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9614409126438, + 38.85718874049464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/17/08

Report Problem", + "NAME": "H05535" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97955204381321, + 38.85713757304962, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/15/08

Report Problem", + "NAME": "H05536" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97911540950061, + 38.85718106951473, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H05537" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97808529519855, + 38.85593256506634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H05538" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97808407054877, + 38.85718197049466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/30/08

Report Problem", + "NAME": "H05539" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00621642346994, + 38.96827299882037, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05541" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95840951134817, + 38.87186517340588, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05542" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95790517974162, + 38.87092592959299, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05543" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03464866168709, + 38.91714202713414, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05544" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0346678328603, + 38.914926052631984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05545" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03469011507521, + 38.91865831492271, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05546" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03466536158568, + 38.91423042971323, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H05547" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92607490962675, + 38.90363582020827, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05548" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93264106063309, + 38.90304841896356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H05549" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93362120518705, + 38.902963301490914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05550" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93064480504816, + 38.9032437772404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H05551" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92955130241519, + 38.903609186507865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H05552" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93925617891294, + 38.90265226387361, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H05553" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93459673696846, + 38.90278903552854, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H05554" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03444388068098, + 38.90472147679435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04126" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03444419634658, + 38.90554230861681, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H04127" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05965348159785, + 38.964043007414226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04128" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97826183480795, + 38.94191356198563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04129" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06124494758235, + 38.975321061401495, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04130" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06039680541126, + 38.975982373304525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 11/05/07

Report Problem", + "NAME": "H04131" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01462480695498, + 38.953237083802165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04132" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07784865034364, + 38.921501847940014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04133" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9738844456461, + 38.89520050273513, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/06

Report Problem", + "NAME": "H04134" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09912209734335, + 38.91800002002581, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04135" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07410363446063, + 38.91816021090756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04136" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0133816496918, + 38.95214409718589, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04137" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97911517308313, + 38.86409238340526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04138" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0965817045513, + 38.9463557131952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H04139" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01162206136723, + 38.95441416186452, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Am. Darling

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H04140" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07278076615214, + 38.951453353418316, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H04141" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01216566909041, + 38.952363608455315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04142" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01715222858077, + 38.96122928455193, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H04143" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96827071763546, + 38.93403079284673, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H04144" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9761338999655, + 38.94080510023721, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04145" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0114410067199, + 38.95222911607406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04146" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01342776104484, + 38.9531823490413, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04147" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09077952107053, + 38.9479546939858, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H04148" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0924601142271, + 38.947857483699394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H04149" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93584317933272, + 38.87483335010564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04150" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9312273930607, + 38.89011876072355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04151" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08395563715916, + 38.94485097178136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H04152" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.023881629564, + 38.897531732988455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H04153" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0863855825512, + 38.945605248842256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04154" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05069929959917, + 38.89363286410995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04155" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07870592821183, + 38.92161838194337, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04156" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93664978072373, + 38.87759329704105, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04157" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99793004310953, + 38.84460272154863, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H04158" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96825037280703, + 38.93498776623604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/09/08

Report Problem", + "NAME": "H04159" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07420000848023, + 38.95152788755235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H04641" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99468330923014, + 38.9047647096094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H04642" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99487608617089, + 38.90458818157047, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H04643" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99630852290727, + 38.905455577598765, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H04644" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96905745347226, + 38.93772639733008, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04645" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03586691548374, + 38.93666840682188, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H04646" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06282027044647, + 38.97360980561795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H04647" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97980878550244, + 38.89818613894851, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04648" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97949250667071, + 38.89930675095255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H04649" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05904905542043, + 38.90273546012486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H04650" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03325891291323, + 38.90729610909179, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H04651" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09242135373977, + 38.945588732806186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H04652" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98666491183164, + 38.904845937446964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 12/21/07

Report Problem", + "NAME": "H04653" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09813772020284, + 38.91702730210631, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04654" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9800504526319, + 38.89725149981552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04655" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01939644026498, + 38.94433388803896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H04656" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06917715330414, + 38.94225542747022, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04657" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0309787170839, + 38.90977135535689, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H04658" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0057168927409, + 38.909475245400714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04659" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01088024513119, + 38.96008872644179, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H04660" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01139043684941, + 38.9594910700732, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04661" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02949613735709, + 38.96982295120882, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04662" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9938803508378, + 38.90423548372707, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H04663" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07070448196514, + 38.927447853852385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H04664" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98596086268006, + 38.9235782648783, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H04665" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08626376844042, + 38.950439750351464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H04666" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02601997387785, + 38.96148905798413, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04667" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99354740559181, + 38.94058844807709, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04668" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01573418003876, + 38.948036139246746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04669" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97223546063009, + 38.93956825659346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H04670" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08636939461488, + 38.94714479467891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04671" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98198782552936, + 38.90562092893928, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H04672" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.962745100922, + 38.877293368879705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04673" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96596344337678, + 38.92816919467666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04674" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00793752908118, + 38.96407328653882, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05094" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05706186163043, + 38.931310580293584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H05095" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01115767264281, + 38.82048398900144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H05096" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00080082980088, + 38.931393726925926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05097" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00140140107794, + 38.86035805567028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05099" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00579112172366, + 38.8766800024697, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/31/07

Report Problem", + "NAME": "H05100" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00568714004498, + 38.878455507983176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H05101" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99118158164589, + 38.86075710134952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05103" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97124438330663, + 38.895875654275656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/07/06

Report Problem", + "NAME": "H05104" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96734037632208, + 38.85526601549889, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05105" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03660727158277, + 38.941910031317505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H05106" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95796514889975, + 38.89134906879623, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H05107" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96014188545806, + 38.891340382047275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H05108" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00550992983898, + 38.847927517413034, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05109" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0027490084969, + 38.847984305182536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05110" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00459417437982, + 38.84897402224414, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05111" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01890025915684, + 38.93272030496153, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H05112" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00122265650533, + 38.84582209829062, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/30/07

Report Problem", + "NAME": "H05113" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93426325574934, + 38.87934935379497, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05114" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93578712039782, + 38.879616480677775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05115" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93547493419248, + 38.88055920802927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05116" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99112066636087, + 38.86343684875891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H05117" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07072592528898, + 38.94117230757642, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/07/07

Report Problem", + "NAME": "H05118" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10008038390623, + 38.934232242301135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05119" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00543642575657, + 38.944333587181326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05120" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97205519821854, + 38.90557859098065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H05121" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97400418415732, + 38.90556770838965, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/10/07

Report Problem", + "NAME": "H05122" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97029875684811, + 38.89684560955335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 04/07/06

Report Problem", + "NAME": "H05123" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99494100183634, + 38.855549825340795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05124" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96458497288435, + 38.857082157904834, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05125" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96537773988202, + 38.8551334674857, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05126" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96275655477618, + 38.85631954815287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05127" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96404030432578, + 38.85573465505948, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05129" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96238711494429, + 38.855013378809616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H05130" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9319147355934, + 38.90305483527768, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H05555" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03253594381103, + 38.986995981806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05556" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03185964113344, + 38.98760103308529, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05557" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04689553390442, + 38.93270750655063, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 01/01/06

Report Problem", + "NAME": "H05558" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05241885645074, + 38.93411307681662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/27/06

Report Problem", + "NAME": "H05559" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00616467837328, + 38.824165925353434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05560" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94679255764767, + 38.869914120035084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05561" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01020743214772, + 38.823673355724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05562" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01161555115145, + 38.823558384037995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H05563" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94043824416006, + 38.87132346189441, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05564" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94936568570252, + 38.86739391851876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05565" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93756086953839, + 38.872467674792226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05566" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00770574768796, + 38.82378353218324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05567" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00873811461366, + 38.82361186604235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05568" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93807556038735, + 38.872089262565886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05569" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01054065974114, + 38.86739317842726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05570" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98650805910393, + 38.84524003724452, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05571" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98289487281518, + 38.84636191650105, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05574" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99653065523252, + 38.94998428548498, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05575" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99798412214963, + 38.94998705809843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05576" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98489755271059, + 38.8775732527253, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/19/06

Report Problem", + "NAME": "H05577" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96657403496258, + 38.872071872173485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05578" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00285028184724, + 38.96115491960757, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H05579" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96759612651366, + 38.87466361599137, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05580" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96623290382512, + 38.87469275930876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05581" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00261994094924, + 38.8316679052314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05582" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95932028643148, + 38.89482390591427, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05583" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02542357594496, + 38.98347566844439, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05584" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0254029306618, + 38.982771383640156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05585" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02640616073933, + 38.98268025052983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05586" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08500227559601, + 38.94714712095462, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/10/07

Report Problem", + "NAME": "H05587" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08362220401071, + 38.94715135026438, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H05588" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02440190090958, + 38.98258836965726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H05589" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02456104844556, + 38.98151992575786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05590" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06777648822873, + 38.905320327622675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/31/07

Report Problem", + "NAME": "H04160" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04300366269197, + 38.98494873782209, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04161" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0512314150634, + 38.939490719849296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04162" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01468092237296, + 38.95228681242221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04163" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05798077538691, + 38.93095781308936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H04164" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97928430455137, + 38.9397357051547, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H04165" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09876483038914, + 38.94134825244927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04166" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09692235319008, + 38.94119670771613, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H04167" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05863785500263, + 38.9588363347859, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04168" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0575501814373, + 38.958462374780034, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04169" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0751152219859, + 38.919940818204296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04170" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09012352660744, + 38.95590037430198, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04171" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9372235000234, + 38.87853321850827, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04172" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09449979552335, + 38.947953601576536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H04173" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0289106558102, + 38.88744086085086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04174" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03163435944765, + 38.88744510954168, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04175" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.030350692949, + 38.88745095426933, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04176" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01898416963326, + 38.914889764368034, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04177" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00537196189624, + 38.84079241280309, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04178" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01501065894607, + 38.9673886361425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H04179" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98316393234396, + 38.905425073642945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H04180" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0649515439531, + 38.976978665773245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, USP

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04181" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97588851739661, + 38.86959941394611, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H04182" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9828103479725, + 38.915086027457555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04183" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93618149557425, + 38.87850321432359, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04184" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02990746133075, + 38.962781254029906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04185" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03216845575406, + 38.96244307860228, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04186" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03110172300877, + 38.96295824288548, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04187" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98208432681712, + 38.89344620013549, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 04/02/07

Report Problem", + "NAME": "H04188" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08503009544293, + 38.95708539854154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04189" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03113282203469, + 38.88768421857263, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04190" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0297787030391, + 38.88769007576988, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04191" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00798063343545, + 38.88315079834074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/17/07

Report Problem", + "NAME": "H04192" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98069360191194, + 38.87069748600254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/09/08

Report Problem", + "NAME": "H04193" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02989833110495, + 38.92679666687976, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H04675" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99812129879997, + 38.92420748637869, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04676" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05527318635855, + 38.976562226456686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04677" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98630702966962, + 38.92009875123552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04678" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98569287661115, + 38.92090340033059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H04679" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06309926998024, + 38.97162257362873, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04680" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97730234557034, + 38.865136399541704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H04681" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08118012218975, + 38.94324616884795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04682" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02719994531716, + 38.968686136398794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04683" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03523902646883, + 38.949794716634905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - JUMBO

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H04684" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99032450482852, + 38.94720062224963, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04685" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98772160763963, + 38.92114451368463, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04686" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96687002701309, + 38.875558297545695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04687" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9808680110604, + 38.87941724764165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/17/06

Report Problem", + "NAME": "H04688" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96818994498747, + 38.87623023152657, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04689" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08065713955396, + 38.907550882824715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04690" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09930180858414, + 38.931646945111886, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04691" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07589448492523, + 38.928894856373844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04692" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07575830384523, + 38.916280434923756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H04693" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0331880811468, + 38.96315717507701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04694" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02987274199552, + 38.936270241141855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H04695" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02988145523875, + 38.93452092612295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/13/07

Report Problem", + "NAME": "H04696" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02989826064129, + 38.9323771798217, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H04697" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03333335447687, + 38.962205195674784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04698" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93299608995788, + 38.892710714341405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04699" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93301445960975, + 38.893280144078766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04700" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0199662573189, + 38.876432897439585, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04701" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98064403346592, + 38.936998047201634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04702" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93299950532439, + 38.89390997378927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04703" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93283044578831, + 38.89465833712803, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04704" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98075349844044, + 38.93821621211042, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04705" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10406574419125, + 38.93425941711597, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04706" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03452426481338, + 38.90103818916806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04707" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9333621478716, + 38.89609807080331, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04708" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96512410125285, + 38.85611041006233, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05131" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96364460045582, + 38.85413268968141, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05132" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96251722355318, + 38.85360396168428, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05133" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9815354452883, + 38.90602699974392, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05134" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00407436409346, + 38.943917171576096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05135" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0088687767568, + 38.827717439751744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05137" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01068152153015, + 38.82785752273561, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/03/07

Report Problem", + "NAME": "H05138" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01239308754744, + 38.82785739857395, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05139" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05714803537302, + 38.935408262936825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/05/07

Report Problem", + "NAME": "H05140" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03371761321357, + 38.901939287456976, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H05141" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97633159818267, + 38.904312637153666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H05142" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95224654475162, + 38.90080203386351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 12/18/07

Report Problem", + "NAME": "H05143" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94819158266684, + 38.9000889428839, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05144" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95210412245261, + 38.89944768581777, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H05145" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95150198813921, + 38.89897043567499, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05146" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95071680042268, + 38.898356214229885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/14/08

Report Problem", + "NAME": "H05147" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95291451015491, + 38.90008174437581, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/14/08

Report Problem", + "NAME": "H05148" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94990694953434, + 38.89890131708448, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05149" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01371069294511, + 38.907136924276266, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H05150" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95963606137366, + 38.88434117550581, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05151" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99825647893331, + 38.85814210538549, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H05152" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02512393129236, + 38.89058524570999, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05153" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98104509333896, + 38.906783136022824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05154" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01775104137337, + 38.82811897913732, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05155" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9680406117287, + 38.85616116054887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05156" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92752935991726, + 38.90188639872883, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H05157" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00199254427396, + 38.82632557292641, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/01/07

Report Problem", + "NAME": "H05158" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9986751048196, + 38.86153416877256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H05159" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03418298666743, + 38.91924125815276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05160" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99833992814591, + 38.85965066603583, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H05161" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99921147541397, + 38.96275150242715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05162" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99994562487444, + 38.96364876290705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05163" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96883425006706, + 38.87079106080068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05164" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01589818458916, + 38.86614307831664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05166" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05708556800568, + 38.98054136982565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05591" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93971156487623, + 38.87087736207481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05592" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05618503406097, + 38.977034759957895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05593" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97628607751274, + 38.91497274077745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H05594" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96048624294018, + 38.874721503771006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05595" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00219860309011, + 38.900310079572584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/08/07

Report Problem", + "NAME": "H05596" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94911346950808, + 38.879081426798805, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H05597" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95107549047403, + 38.87600265517927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05598" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98845195982535, + 38.90029425132657, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H05599" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9996735259519, + 38.900303938088115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H05600" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99635052167638, + 38.90030508866122, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H05601" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99720495639907, + 38.90011297295777, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H05602" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9927105245132, + 38.90031304378298, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H05603" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03474882473755, + 38.9890721963417, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H05604" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99255911239196, + 38.948058689247034, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05605" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96298741200495, + 38.86919054202265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05606" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03471160689664, + 38.91265962322301, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H05607" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0346970408595, + 38.91625531367251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/02/07

Report Problem", + "NAME": "H05608" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03471321035195, + 38.90875230859182, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H05609" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03444403905178, + 38.913334138646334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05610" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99324805600712, + 38.91756487445713, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H05611" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00664287998222, + 38.96729266235581, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05612" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0074549398061, + 38.966604005192, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05613" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00488726270738, + 38.967399307423335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05614" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10012517921214, + 38.93033792938389, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05615" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04590469946832, + 38.91466072053511, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/04/08

Report Problem", + "NAME": "H05616" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98685992576867, + 38.951714087742744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05617" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98686241843231, + 38.95039542104574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05618" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98686494046967, + 38.94954291426279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05619" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00936030198125, + 38.9710107447314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05620" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00729484274315, + 38.96936912233537, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05621" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04611798105695, + 38.91394860864541, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H05622" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00841420127617, + 38.97025479127584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05623" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9447146996884, + 38.90459361734108, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H05624" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98193228117958, + 38.91352929969213, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H05625" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02321859114396, + 38.95928284122714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H04228" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97225039976014, + 38.91265508812598, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04229" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9630260630159, + 38.86818553118676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04230" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08849188887804, + 38.953357982336556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/14/07

Report Problem", + "NAME": "H04231" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08062217065265, + 38.92248373061374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04232" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09051348448547, + 38.95042123226649, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H04233" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93181748004211, + 38.89557642372513, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04234" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0332685364397, + 38.95519343707847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H04235" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99380791140494, + 38.93933695820181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04236" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99438984117685, + 38.938164143748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04237" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0843160409656, + 38.908053406809444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04238" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08879115252536, + 38.94483593138371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/10/07

Report Problem", + "NAME": "H04239" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02822301624234, + 38.91404340270892, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04240" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03361960626368, + 38.97076466773854, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04241" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9848039514883, + 38.91474516712138, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/08/07

Report Problem", + "NAME": "H04242" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99257605546647, + 38.895473842403405, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04243" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9821151010816, + 38.870698397005036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04244" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98710591197033, + 38.92784057352039, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04245" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97733590183157, + 38.89484559105761, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04246" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97908384523127, + 38.894833116220404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04247" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02639767901154, + 38.981095067400275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04248" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0288833903384, + 38.937763678146176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/25/07

Report Problem", + "NAME": "H04249" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98083288837465, + 38.921401936560116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H04250" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98067174174777, + 38.92239272642099, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H04251" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98542161778325, + 38.906978389429945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Am. Darling

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04252" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03113644506006, + 38.93969699133028, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H04253" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98611566896587, + 38.939033663996085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04254" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03331433997035, + 38.96766163233815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04255" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99519716346217, + 38.93922768088011, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04256" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1008668349851, + 38.93514558504254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04257" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07812042015287, + 38.929999574504286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04258" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99253501156616, + 38.93970739491439, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04259" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09474792286065, + 38.925101147987306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04260" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08847356192025, + 38.94557294195461, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H04261" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02960783569715, + 38.96906362741682, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04709" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98133325793626, + 38.935765202546136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04710" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02951095390996, + 38.941928766648175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04711" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03168001493522, + 38.96986307919653, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04712" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08620570575218, + 38.94402908447132, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04713" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96334800127977, + 38.87703422596476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04714" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94666960303068, + 38.886399110692196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04715" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9479229391661, + 38.88625808248532, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04716" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94908377507225, + 38.88723079678369, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04717" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08894004824909, + 38.958221251441046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04718" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94781466845942, + 38.89458843909273, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04719" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96462987363175, + 38.87549153693379, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04720" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04345474868755, + 38.93968831360353, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H04721" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03660890013306, + 38.9896931680321, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04722" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04905193541292, + 38.90517613320066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H04723" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0145878530758, + 38.91117582605001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/10/07

Report Problem", + "NAME": "H04724" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96222175423597, + 38.877784473568504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H04725" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0417586777392, + 38.93890300322702, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H04726" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0754331077656, + 38.923581184166196, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04728" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06248503815512, + 38.97893554241053, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04729" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10591932400739, + 38.93483667092647, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04730" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98575793368119, + 38.908047388316206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H04731" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9788424771193, + 38.9245564782839, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H04732" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96485052057069, + 38.87925030228958, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04733" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95965525867965, + 38.88194380735753, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04734" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0513405725282, + 38.90514078304257, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H04735" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9332467064806, + 38.88151653860521, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H04736" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0522189469308, + 38.90534688318145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H04737" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02538520316195, + 38.94710572440684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H04738" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08849601566848, + 38.947844778236124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04739" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08753390764316, + 38.94797673524905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H04740" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02799126448157, + 38.88436796558133, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04741" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06343872983717, + 38.95972896131136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H04742" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09418338977535, + 38.948854748169815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/14/07

Report Problem", + "NAME": "H04743" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9822535555375, + 38.908835436045294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05167" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00712929976308, + 38.82611988897079, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05168" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00573025749678, + 38.82611690317241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05169" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03306643291387, + 38.95634551635734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/08/07

Report Problem", + "NAME": "H05170" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04223666641778, + 38.92745394324563, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H05171" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00916853256301, + 38.82891256091074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05172" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98861263263892, + 38.93731801588514, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05173" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00364475189643, + 38.826978376800824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05174" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00557020066834, + 38.825182696460594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05175" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00693997461075, + 38.82507662936434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05176" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00264292287537, + 38.83523089468394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05177" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00265926655396, + 38.836158963522614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05178" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9654493029774, + 38.85909494392035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05179" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99541947917167, + 38.93942175545744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05180" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00518394457792, + 38.856198399578375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05181" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00849092153655, + 38.846232382640956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/07/07

Report Problem", + "NAME": "H05182" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0138335624993, + 38.83331050135897, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/25/07

Report Problem", + "NAME": "H05183" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95878071299619, + 38.8905559469081, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05184" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00446434855682, + 38.83485467306831, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05185" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98070064473738, + 38.87090317606907, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H05186" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96434739419013, + 38.859063335397366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05187" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97911665830593, + 38.870830169684666, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05188" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99268594143285, + 38.86359398299059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05189" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99297689691656, + 38.863420255542984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05190" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96458762409094, + 38.857683290936436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05191" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00303715935394, + 38.833781108862624, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05192" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96578769586216, + 38.85377464869698, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H05193" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9681256048483, + 38.858788599077045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05194" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0645403305936, + 38.919376919038314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/13/07

Report Problem", + "NAME": "H05195" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0020455299901, + 38.823886321128626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H05196" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93195920995375, + 38.89071822830916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05197" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02916650532477, + 38.941922060850416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H05198" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98254432863565, + 38.853448476908326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05199" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02011186226316, + 38.94416618602358, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H05200" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96456620820008, + 38.925934456168676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05626" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9345339221914, + 38.90458009550121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05627" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99327537698036, + 38.92547176950791, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H05628" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9403490305565, + 38.907592818087466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05629" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96988385465852, + 38.87231929660813, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05630" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05849582904557, + 38.963620132377606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05631" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05683875629394, + 38.94889635481614, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05632" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07470631454774, + 38.95631854170552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05633" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96571956533501, + 38.86770608765082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05634" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02823882639538, + 38.98571573443198, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05635" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06990348187958, + 38.94781054026824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/31/07

Report Problem", + "NAME": "H05636" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05965423415002, + 38.96302593930838, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05637" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9500171134719, + 38.87048406531074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H05638" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07297220918346, + 38.95523451003682, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H05639" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02317546488578, + 38.98171452478699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H05640" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05647123721442, + 38.98334825067811, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/14/08

Report Problem", + "NAME": "H05641" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05475400391595, + 38.984664239522836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05642" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02761001035984, + 38.985227639521696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05643" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05221476577873, + 38.979799782857256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05644" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99389121916485, + 38.947353193040755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05645" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9288845265452, + 38.879415206737704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05646" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99650758195034, + 38.95070557727821, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05647" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03503116124297, + 38.977390636854935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05648" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95799787260297, + 38.882794506682636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05649" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00388711500801, + 38.96196109243133, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H05650" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05901852522831, + 38.978825181671596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05651" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98977080822395, + 38.860456420343795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05652" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95594061282378, + 38.88605500004995, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05653" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98900499961782, + 38.8343547305701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05656" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94108255821662, + 38.89910314008226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/08/07

Report Problem", + "NAME": "H05657" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95674945753103, + 38.884552451859854, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05658" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93686261509959, + 38.89106278639865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05659" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97477228059029, + 38.91914614560129, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05660" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00315371290615, + 38.96512307346234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05661" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98070467320836, + 38.86959953434901, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04194" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06164374887241, + 38.920185593100506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H04195" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09668519029186, + 38.95204514070214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/27/07

Report Problem", + "NAME": "H04196" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06910828643798, + 38.97119206931057, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04197" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95830060500094, + 38.86539034084077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H04198" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95781712760093, + 38.86357808847158, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H04199" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95721164437941, + 38.86541863867322, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/27/07

Report Problem", + "NAME": "H04200" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96770634890431, + 38.87085628146997, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04201" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07826486773908, + 38.946334963606006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04202" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09681384237601, + 38.94044746961238, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H04203" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06887535899614, + 38.94018639195672, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 04/19/07

Report Problem", + "NAME": "H04204" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0997265062579, + 38.92452685981922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04205" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08802840957976, + 38.92419351726891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04206" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04538189131213, + 38.98851935102793, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04207" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04576058800095, + 38.98928933297763, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04208" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04667269670925, + 38.98981420494747, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04209" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9347988590341, + 38.891965363777366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04210" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0901687791002, + 38.95708871003681, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04211" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0945298178113, + 38.95336894868246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H04212" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07044800531021, + 38.93990072956905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/19/08

Report Problem", + "NAME": "H04213" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97778103266928, + 38.90501793337816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H04214" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07264211889718, + 38.948825617158754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04215" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05602234223862, + 38.975944491008065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04216" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96767995175357, + 38.87397897382935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04217" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00866162303225, + 38.95726502079673, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04218" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09268059118425, + 38.94715814020929, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/10/07

Report Problem", + "NAME": "H04219" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09048643430907, + 38.94632451192847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H04220" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05338198606725, + 38.972773837283206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 01/24/08

Report Problem", + "NAME": "H04221" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99366632364934, + 38.93792124314612, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H04222" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93367273725826, + 38.89841423521351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H04223" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0675251092381, + 38.97119434542624, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04224" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.035255624967, + 38.94904393487972, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - JUMBO

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H04225" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0512314150634, + 38.939490719849296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04226" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01992436891082, + 38.97566503894667, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04227" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97914701395872, + 38.92350717194224, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H04744" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9499122658942, + 38.88806240322035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04745" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02728413167864, + 38.960777901397876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04746" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09399904656539, + 38.92685496105866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04747" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07658090367256, + 38.966355320287825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04748" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95357024028502, + 38.864578239839595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/11/08

Report Problem", + "NAME": "H04749" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95230956964433, + 38.86478051116998, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H04750" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9559998876629, + 38.89538628390953, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04751" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9658262175837, + 38.87584902205443, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04752" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97037939894082, + 38.86731902813283, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H04753" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07824447684018, + 38.956008018560574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04754" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94992039160039, + 38.89399085378731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H04755" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06081324158107, + 38.97879231907476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04756" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97369548375778, + 38.868201223022595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04757" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10843436087899, + 38.9336863909948, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04758" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10699318206748, + 38.934437336503365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04759" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01967668924941, + 38.88685829074186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H04760" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96762577053877, + 38.86741520062983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04761" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99750901976692, + 38.88077037995249, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/05/06

Report Problem", + "NAME": "H04764" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95502384391406, + 38.88685246889917, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04766" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95486526557892, + 38.88743972708472, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04767" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00872859395193, + 38.94969523285129, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 02/06/08

Report Problem", + "NAME": "H04768" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96469104600503, + 38.87758416985688, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/28/07

Report Problem", + "NAME": "H04769" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02855205962594, + 38.97003064527849, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04770" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99505654372098, + 38.92728226849169, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04771" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9772417886766, + 38.86941859853848, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/11/08

Report Problem", + "NAME": "H04772" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02962440022894, + 38.97088130575179, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04773" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05903720133935, + 38.96599972284117, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/05/07

Report Problem", + "NAME": "H04774" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97998940789428, + 38.93713361993313, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/16/08

Report Problem", + "NAME": "H04775" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09919507306482, + 38.939543112010114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/30/08

Report Problem", + "NAME": "H04776" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09449979472652, + 38.93943357875536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H04777" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02732498134701, + 38.93460823862935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H04778" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9535358853864, + 38.89080012318996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04779" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03780987553274, + 38.989459356416575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04780" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00579923830666, + 38.835739803389906, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H05201" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00371946252882, + 38.834567131188045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05202" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01283407284744, + 38.92336057324921, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/15/06

Report Problem", + "NAME": "H05203" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03653525833982, + 38.959240711942556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05204" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93828125126588, + 38.88836631040014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05205" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94560764270386, + 38.88071570756369, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05206" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0348088871785, + 38.92990507593924, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H05207" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96577227535872, + 38.852200943189345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H05208" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01241513610991, + 38.82444685246901, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05209" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96849001615604, + 38.9318196197282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H05210" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00199450898634, + 38.837294330382896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05211" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93505722563116, + 38.89569791888897, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05212" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9362105201997, + 38.895836679653705, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05213" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96550478615704, + 38.85052243999966, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05214" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96503674379574, + 38.85402611276057, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05215" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96423542673692, + 38.85324732539318, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05216" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01770081346389, + 38.90378448904728, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H05217" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98642395410391, + 38.93623448035742, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05218" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96052825924822, + 38.864347129993874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H05219" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92564951238235, + 38.90195138388131, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05220" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92456229178582, + 38.90175630453846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05221" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9254613149737, + 38.90274042311545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/07/07

Report Problem", + "NAME": "H05222" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92509054856161, + 38.903601817241025, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05223" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04085137133464, + 38.90584208678454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05224" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93750850862496, + 38.882491865774114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05225" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93068863045525, + 38.89556242700819, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05226" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00141409943355, + 38.83600082378851, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05228" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94640778739509, + 38.90305166260014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/15/08

Report Problem", + "NAME": "H05229" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94869554404856, + 38.905146149868784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H05230" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94537330103947, + 38.90171921693423, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05231" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94712564157969, + 38.90384841830326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05232" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.946607499322, + 38.90155703351813, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05233" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00600288044966, + 38.84130445832689, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H05234" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98114646464356, + 38.91605190556484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H05235" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94287490400488, + 38.90712267350573, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05662" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01034760222493, + 38.95877074056332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05663" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01230036121824, + 38.960061326685185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05664" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98814953415919, + 38.95022091519498, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05665" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95244149542405, + 38.87016857649753, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05666" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96218175081448, + 38.88028802801066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05667" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94305607932144, + 38.88356448428447, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05669" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94272313419559, + 38.88259671260365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05670" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97617057208338, + 38.86880775897308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H05671" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96980100108885, + 38.874002945408684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05672" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05361170579698, + 38.970433797478094, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05673" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01063281968676, + 38.82694035699557, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05674" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02836162436662, + 38.97217998495807, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05675" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99566510427299, + 38.93473681092047, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05676" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99500715481591, + 38.95026638750952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05677" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96376926850891, + 38.87507972443926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05678" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08275870237559, + 38.9280337317338, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05679" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07132502981375, + 38.94719806432574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05680" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92356977747968, + 38.888590585229444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/19/08

Report Problem", + "NAME": "H05681" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9239844800327, + 38.88958973194141, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05682" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93152743481679, + 38.9072525643163, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05683" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93156072379776, + 38.90477344051688, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H05684" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9316114662494, + 38.90617672826469, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05685" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95504665549971, + 38.888734346080106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H05686" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01583536907275, + 38.922206302223074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H05687" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9484549342919, + 38.86537084314752, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05688" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08386979272295, + 38.94883387487236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05689" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01979012898339, + 38.90165210156631, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05690" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96492961009135, + 38.870679114009285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05692" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94558037241048, + 38.868583722155954, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05693" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93695746773983, + 38.87642792110413, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H05694" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99488631513977, + 38.94812984447875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05695" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98212065187695, + 38.856913847015655, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/15/08

Report Problem", + "NAME": "H05696" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9806719167034, + 38.85716015875724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/17/08

Report Problem", + "NAME": "H05697" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97629867199124, + 38.89483945770751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04262" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0904854345653, + 38.94557323067019, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H04263" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9788463345116, + 38.925509315744556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H04264" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02233949754955, + 38.96327319189262, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04265" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0110243299574, + 38.9544901684508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04266" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93653834821622, + 38.89527011476603, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04267" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98374999306267, + 38.94417422749809, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/30/08

Report Problem", + "NAME": "H04268" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98428258754907, + 38.91389620669501, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H04269" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98375946413988, + 38.91297998731711, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H04270" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02003355633056, + 38.963280365897624, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04271" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03356650983973, + 38.93516200159843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H04272" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08886788354216, + 38.95042290013256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/27/07

Report Problem", + "NAME": "H04273" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97316242368191, + 38.92456130244601, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H04274" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01428853437034, + 38.87209712278843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H04275" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9800113302975, + 38.90258971143001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/13/08

Report Problem", + "NAME": "H04276" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09569559804243, + 38.95295278191371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/30/07

Report Problem", + "NAME": "H04277" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97891824649129, + 38.872158206939616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H04278" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03618701845232, + 38.96159082217777, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04279" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08458923913511, + 38.95599695218664, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04280" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03955123466933, + 38.899050675625894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H04281" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09806031173513, + 38.94030658579882, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/25/08

Report Problem", + "NAME": "H04282" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95884187487074, + 38.858464752401, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H04283" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08790548220217, + 38.92493654414663, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04284" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0793235956426, + 38.94784298423143, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04285" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95742892119048, + 38.89469289888812, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04286" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02277592797219, + 38.90969439226076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H04287" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99513038726887, + 38.92947343528527, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04288" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03461038972091, + 38.96865291030881, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04289" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98358587383679, + 38.8776666459264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 11/16/06

Report Problem", + "NAME": "H04290" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9771435514052, + 38.8920544725174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 04/07/06

Report Problem", + "NAME": "H04291" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06649009396924, + 38.9753302589748, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04292" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0637492159216, + 38.97594659690241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04293" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05934972355695, + 38.95076222548684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04294" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00659859114509, + 38.84027830074792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H04295" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05686011552427, + 38.96608544323306, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04781" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96585600154377, + 38.86863671429712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04782" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0125357042885, + 38.887465764552516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04783" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01538318188119, + 38.88632222485084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04784" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0161663973331, + 38.88744951777013, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/29/07

Report Problem", + "NAME": "H04785" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01494850837497, + 38.8874505988401, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H04786" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09845736050742, + 38.93294031600649, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04787" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97502968442616, + 38.8674006683606, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04788" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01608979094676, + 38.896276183107496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04789" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98177643958206, + 38.944293377338155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H04790" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93498335865014, + 38.89421668576057, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04791" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98288708280418, + 38.93498700615731, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04792" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08607993527309, + 38.943273615885936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04793" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07873995641353, + 38.950003321020475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04794" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02149414163907, + 38.958590498905714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H04795" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99236681735826, + 38.925453552930406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04796" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95490660185635, + 38.89080808329124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04797" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95397626395426, + 38.8919068681121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04798" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96483366750157, + 38.868664526134815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04799" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01356702678221, + 38.88513919904141, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04800" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09432638422177, + 38.92619960331468, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04801" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04477042354836, + 38.990204598322485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04802" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04402642731336, + 38.98881321227033, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04803" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98188930205934, + 38.921950883086794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H04804" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1075264479778, + 38.93253440034168, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04805" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10600435734776, + 38.93401833324635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04806" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10682858019072, + 38.933180269511496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04807" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01882920423077, + 38.88613034612367, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04808" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04371450679095, + 38.93889600935824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H04809" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97723976230432, + 38.86890736202704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/22/08

Report Problem", + "NAME": "H04810" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09638027028329, + 38.93233851756908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04811" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97925664619731, + 38.91614165067249, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04812" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09118233938017, + 38.91522106278821, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/06/06

Report Problem", + "NAME": "H04813" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10116194205156, + 38.93060223234202, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04814" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9303940267273, + 38.90172544067324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05236" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92951698417788, + 38.90189109201884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05237" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06288884747777, + 38.904678035720075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05238" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9364149049863, + 38.88347047825336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05239" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93947277033521, + 38.88324683923172, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05240" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93647852547285, + 38.88211158853302, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05241" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93935861335437, + 38.8819007826926, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05242" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93443518869493, + 38.883031377885494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05243" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92865174745543, + 38.9025822465212, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05244" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92747818794447, + 38.902586451492354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H05245" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9309017060856, + 38.9021063812049, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05246" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93003672678589, + 38.902546104828836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/06/07

Report Problem", + "NAME": "H05247" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92170897094678, + 38.89140887595691, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05248" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96802578021132, + 38.85061429603089, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05249" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92387292178395, + 38.891581735669874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H05250" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92635607441318, + 38.902663545716806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05251" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9578530667068, + 38.869293335316804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05252" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93359707132907, + 38.88880021537058, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H05253" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9324124946202, + 38.88867692289541, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05254" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95725594448804, + 38.87023566789262, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05255" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03838650996451, + 38.962697226149494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05256" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98644082862975, + 38.85799525046285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H05258" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98582125384355, + 38.857586788961164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05259" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98430953085037, + 38.8448852982181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05260" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98337802145222, + 38.843656030133, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05261" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99198662394896, + 38.8400376054999, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05264" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98337984701934, + 38.84452283193394, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05265" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9914789427159, + 38.839289597868145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05266" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93306402106003, + 38.88822386130041, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H05267" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93242678527895, + 38.88774198746146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H05268" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92035748611644, + 38.89724381926335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05269" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0088456648001, + 38.83144995497134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05270" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9410254124569, + 38.870184043356524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05271" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98345012991754, + 38.91272970130136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05273" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9611430508945, + 38.89188019478629, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05698" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03233738400814, + 38.98895822241572, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05699" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03097565893982, + 38.98792329589722, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05700" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03376492782296, + 38.99005990971443, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05701" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98943312180798, + 38.95014586421363, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05702" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08219976296907, + 38.948887858583475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05704" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0319358274213, + 38.98635414115788, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05705" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0335241596069, + 38.97159383131471, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05707" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03476667517141, + 38.971438229577046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05708" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99503072862606, + 38.94638695587887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05709" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99370432607566, + 38.94631697870379, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H05710" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08629893217942, + 38.93336432591368, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05712" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00012675472678, + 38.83314198908348, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05713" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9901220467203, + 38.946316343537376, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05716" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00049214456863, + 38.828184351260866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05717" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0658859245943, + 38.946340541976284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 11/10/05

Report Problem", + "NAME": "H05718" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99851523626316, + 38.88595656932109, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05719" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94043409618848, + 38.88181536008358, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05720" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94192741713624, + 38.88169605734088, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05721" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96077971341751, + 38.870469609705395, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05722" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00884101931524, + 38.82611497934236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05723" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93932168730257, + 38.894205651412484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H05724" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98572787577514, + 38.95051566560656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05725" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94550149027835, + 38.882776336084426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05726" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02000699786812, + 38.95852309279095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H05727" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02948826363551, + 38.972212099908646, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05728" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95110307371986, + 38.87083133069295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05729" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93396656142461, + 38.87653301777632, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05730" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92220923662668, + 38.89278116759077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05731" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9328585698703, + 38.87560290845916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05732" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09061089296013, + 38.93438101911093, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05733" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09212141324365, + 38.93386459924006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP. Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05734" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07126218221987, + 38.948917098772036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05735" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03289550087862, + 38.98840417027071, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05736" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01027710768506, + 38.95229484042292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04296" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98122810421337, + 38.901151152765806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H04297" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98171557244987, + 38.900737575326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H04298" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9761287016126, + 38.92070956431243, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H04300" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05954573933394, + 38.918957593692156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/16/07

Report Problem", + "NAME": "H04301" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02176840872563, + 38.89261007344565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04302" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03131990863113, + 38.96751528610002, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04303" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08611182143484, + 38.957963615336816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04304" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08608986765046, + 38.95888246537479, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04305" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0465833849777, + 38.89193533793445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H04306" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02815146221539, + 38.916273712339546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04307" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08747813340375, + 38.94473522676658, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/10/07

Report Problem", + "NAME": "H04308" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9672181997991, + 38.856638451212675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04309" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96587863380492, + 38.854824986176325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04310" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97228764298929, + 38.89912194388076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H04311" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97319135223879, + 38.898962607690265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H04312" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95705040163853, + 38.86812983209164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04313" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97633078373637, + 38.892139917208574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H04314" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97229124573204, + 38.899581380099804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H04315" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97391305318305, + 38.90025392122386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H04316" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97305286307991, + 38.9002522486052, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H04317" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97387747425165, + 38.898970852636126, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H04318" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97249705180883, + 38.90025359644827, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H04319" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97425567826107, + 38.899598558041674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H04320" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95579798736269, + 38.86762338936386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/03/07

Report Problem", + "NAME": "H04321" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95468059783182, + 38.86816171800891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04322" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95332267355158, + 38.86753025207011, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04323" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9568332769575, + 38.863627086006616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H04324" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97523601674682, + 38.89209940481035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/30/06

Report Problem", + "NAME": "H04325" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96382012456583, + 38.86814730499983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04326" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97766991656334, + 38.9043168192467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H04327" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98289673383327, + 38.90413014745225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04328" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03352424401162, + 38.960930995563075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/04/08

Report Problem", + "NAME": "H04329" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93504453813388, + 38.87850040747153, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04330" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01048054324256, + 38.962561889119925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04815" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04230630246788, + 38.93797335741091, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/15/07

Report Problem", + "NAME": "H04816" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98235356028253, + 38.90507356534147, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04817" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95399246174316, + 38.88882855960629, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04818" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97982852386657, + 38.944285868830015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H04819" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95591473597428, + 38.88883622838039, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04820" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0629606529764, + 38.968891466935894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04821" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06162612771428, + 38.9688507128994, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04822" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06290777956663, + 38.96832918281929, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04823" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96486785207344, + 38.87494706010085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04824" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95206526528843, + 38.86434070138106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H04825" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95050417296946, + 38.86435488694021, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H04826" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06127772997033, + 38.97392092168366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04827" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96557648871925, + 38.87859105014223, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04828" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09244340732056, + 38.94037395071902, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04829" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09253964154384, + 38.939485296207536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H04830" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00639208759462, + 38.945527586772194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04831" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9772997499416, + 38.850872496423754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04832" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00510200670918, + 38.94485390271116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04833" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97778767040835, + 38.85019668738738, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/20/07

Report Problem", + "NAME": "H04835" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98226160034953, + 38.943478012981686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H04836" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9775940856554, + 38.851591876752565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04837" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97685288199948, + 38.85150299907287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04838" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04679212788085, + 38.89519037494254, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H04839" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9609489954562, + 38.87581313498984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04840" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0550539948318, + 38.920829924994095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 01/08/07

Report Problem", + "NAME": "H04841" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9484752575433, + 38.890959214420675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04842" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11029411056718, + 38.934413936461496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04843" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06095431839367, + 38.97993945193936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04844" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05909324581968, + 38.90391971215852, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H04845" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10833393295695, + 38.93513332643349, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04846" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9481476171759, + 38.896103911862824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04847" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98908278252829, + 38.94739041641569, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H04848" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05725204536952, + 38.91690411086289, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/15/06

Report Problem", + "NAME": "H04849" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0086347806207, + 38.94873698448273, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER

In Service


Last Inspection Date: 02/06/08

Report Problem", + "NAME": "H05274" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9151970773889, + 38.89576895849258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H05275" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92836901623804, + 38.899910770701474, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05276" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9266768909645, + 38.89965980193343, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H05277" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92655942098412, + 38.9018863965856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05278" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92706772927086, + 38.90074253628703, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05279" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92758054670871, + 38.89967183325459, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05280" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92534275675774, + 38.89979717225478, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05281" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9285483519885, + 38.90188702639059, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05282" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92595020926296, + 38.90049781482274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05283" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93480902357527, + 38.890390921721355, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05284" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91351965296808, + 38.89191623514586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05285" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93598596323984, + 38.889517075465626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05287" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93392335669337, + 38.907273266806925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05288" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9367220178332, + 38.88830081395822, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05289" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92867621961119, + 38.903623032888554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H05290" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09552477576537, + 38.94024813160729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05291" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09426367753699, + 38.940075799739446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER

In Service


Last Inspection Date: 01/25/08

Report Problem", + "NAME": "H05292" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97287133756159, + 38.89558910897122, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H05294" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96902163373117, + 38.854331272649816, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05295" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.967088970468, + 38.934040960738464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/15/07

Report Problem", + "NAME": "H05296" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92846888637392, + 38.88496376952767, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05297" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97519429396318, + 38.90242945718334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H05298" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05440870726223, + 38.96566845570264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05299" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97487775240677, + 38.88760413114976, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/19/06

Report Problem", + "NAME": "H05300" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93415839450266, + 38.887576528550326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05301" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9336593931824, + 38.88658273883309, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05302" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93436797381392, + 38.88854282226661, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H05303" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93613901588651, + 38.88890764338561, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05304" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99592603498617, + 38.93572255352629, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05305" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93462983507179, + 38.90155689094681, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H05306" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93299997139876, + 38.890308372267484, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05307" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0088390651903, + 38.8728493324782, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H05309" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0295248923983, + 38.93628486892012, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/20/07

Report Problem", + "NAME": "H05310" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07035971154083, + 38.90509822197174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05737" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97436366308231, + 38.94280496191465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05738" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97864195455291, + 38.94531412479575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05739" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98166022114894, + 38.9462204200308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05740" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97989561748804, + 38.94611237281481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H05741" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99381000078833, + 38.924438752237336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/16/07

Report Problem", + "NAME": "H05742" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06449466562998, + 38.95418540939227, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05743" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08564797152272, + 38.91071987267789, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05744" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98796625713597, + 38.911334501654174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05745" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01724901856186, + 38.91439918725036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H05746" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97702753567869, + 38.94531302595674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H05747" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97313451138933, + 38.849455386990826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05748" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97260941626118, + 38.8501174841393, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H05749" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0179778651603, + 38.92131584384434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/11/07

Report Problem", + "NAME": "H05750" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00198003624556, + 38.848705500282136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05751" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0780977113417, + 38.90609660195239, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05752" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07951067926409, + 38.90606327289221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H05753" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03508935807288, + 38.9898523943052, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05754" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99791166927842, + 38.95173467076874, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05755" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9965218224642, + 38.95132050040647, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05756" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97826170270852, + 38.946091928872214, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/16/07

Report Problem", + "NAME": "H05757" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94164428733507, + 38.88262713136998, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05758" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97608265535031, + 38.88931999349269, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 04/14/06

Report Problem", + "NAME": "H05759" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97914778326177, + 38.94063437507967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H05760" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00924258351668, + 38.91912185663241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05761" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05901463357367, + 38.967103298526446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05762" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98275298093917, + 38.86173944750236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05763" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06130203909844, + 38.967488332270186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05764" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06262930649754, + 38.97774780274344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, Metropolitan M94

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H05765" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94176091398215, + 38.88391056942392, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05767" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0025980426277, + 38.96196307396218, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05768" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00614357416043, + 38.964232903626396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05769" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98190085126755, + 38.94700821364279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/27/07

Report Problem", + "NAME": "H05770" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.040165588548, + 38.991800892890765, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05771" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02386224128482, + 38.90101687322729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04365" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0238571062221, + 38.90158808516398, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04366" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02123570865538, + 38.96439680742797, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04367" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07221776230718, + 38.918431902807164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04368" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95351893723814, + 38.86244512545276, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04369" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95463284581349, + 38.86292382948282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04370" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95372497712366, + 38.86162581952653, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04371" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00735747981291, + 38.959767784758185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04372" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02441928182391, + 38.97511031579954, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04373" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97613620327186, + 38.94167751755087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04374" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97322822777984, + 38.93825700669867, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04375" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96285676230137, + 38.86735187524944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04376" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00217722399313, + 38.88765774589491, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/31/08

Report Problem", + "NAME": "H04377" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00339064057852, + 38.88781671484649, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H04378" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97149250447177, + 38.918687011754336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04379" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0825464276259, + 38.94542507355292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04380" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09236264564747, + 38.9267015749324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04381" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09030910561266, + 38.92658108107922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04382" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98365764013333, + 38.90714281958733, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H04383" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02004747216087, + 38.95651376614207, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H04384" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98020881351526, + 38.904424836640914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H04385" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08459157191788, + 38.9133799320576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04386" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09076131242598, + 38.94711726209218, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/10/07

Report Problem", + "NAME": "H04387" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05986733497306, + 38.97765295124391, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04388" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97231363763498, + 38.93836192945532, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04389" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02691046330943, + 38.90476890201847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H04390" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02714731890651, + 38.90787070991565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04391" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02691275462516, + 38.909161218613555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04392" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99464600354275, + 38.937453680503125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04393" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96296153660478, + 38.870422838808324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04394" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01524085879905, + 38.972382918269226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04395" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01440727061679, + 38.97225233246718, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04396" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9624059419235, + 38.92319363081205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H04397" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97229847213681, + 38.91413216952943, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04398" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05931863197713, + 38.91826539202323, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H04850" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95448704807538, + 38.887707516551636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H04851" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04861636578171, + 38.90728637703005, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H04852" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08363180478528, + 38.94785202562629, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04853" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9525854579913, + 38.88936693210724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04854" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98084271778794, + 38.87184791076097, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04855" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0642135618758, + 38.9729661401513, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04856" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98683426395263, + 38.919508298035446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04857" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94251619274606, + 38.89763623886089, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04858" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10153543582629, + 38.922603258865564, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04860" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97620680310852, + 38.84941120959343, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04861" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97969958896098, + 38.84910341132716, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/15/07

Report Problem", + "NAME": "H04862" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97975239460152, + 38.84963817932627, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04863" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97826355906706, + 38.85117125540655, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04864" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97879500907135, + 38.84955865403297, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04865" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97866550086144, + 38.84805480688819, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04866" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0436009035287, + 38.9422341734002, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04867" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97911079445437, + 38.85074704975445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H04868" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94471477686481, + 38.8666374447389, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04869" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02827668839237, + 38.932767075462706, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H04870" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98043312064672, + 38.94518942137881, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/31/08

Report Problem", + "NAME": "H04871" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9816084484277, + 38.94514979558932, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04872" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97710609557588, + 38.90575544280286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/24/07

Report Problem", + "NAME": "H04873" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0118262027984, + 38.83095155904082, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04874" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97746325873652, + 38.92552507400033, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H04875" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99016027324167, + 38.94533323694629, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04876" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98514814923617, + 38.87997940840418, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 03/05/07

Report Problem", + "NAME": "H04877" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93139114543416, + 38.876532632192315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H04878" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0153283638076, + 38.90037609882181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H04879" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01509757805228, + 38.901239850171095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H04880" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95217036320625, + 38.89255269150732, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04881" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01106464885362, + 38.97238290152446, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04882" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95298829788665, + 38.89291631315321, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04883" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10579397560643, + 38.93571591403128, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H04884" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97423145903142, + 38.90135000271714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H05311" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96991943770166, + 38.85821775178569, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H05312" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0063048064685, + 38.908188490305065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H05313" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97432974842071, + 38.93316629444106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/12/07

Report Problem", + "NAME": "H05314" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94177214756726, + 38.90970416449285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H05315" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9490782045424, + 38.89497117674824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05316" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93009665441133, + 38.893556261630565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05317" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92839610634294, + 38.89589219188854, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05318" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92755893154089, + 38.89602770208981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05319" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9288997421302, + 38.893731427693766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05320" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93010694342054, + 38.89291397086683, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05321" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92900280425049, + 38.89294622159397, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05322" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9279548618616, + 38.89685607711352, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05323" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00476611472676, + 38.83369324561206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05324" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99191676134575, + 38.832941027768875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H05325" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97747003444422, + 38.88969819771228, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/01/06

Report Problem", + "NAME": "H05326" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0205995511198, + 38.87397770175878, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05327" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0161056881362, + 38.89883203353696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H05328" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94696630937725, + 38.883633419712204, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05329" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94679439594358, + 38.88483676268073, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/29/07

Report Problem", + "NAME": "H05330" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9452629422241, + 38.88370139485717, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05331" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9803102195726, + 38.847088184039535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05332" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99851284750505, + 38.889966153157346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05333" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05816191390761, + 38.90294589892776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H05334" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0874610737096, + 38.948873311928736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05335" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05614455808113, + 38.90168653569009, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H05336" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97601597100676, + 38.903046214579554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05337" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97305968877532, + 38.90318007400636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H05338" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97407695757303, + 38.90296151826522, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/05/07

Report Problem", + "NAME": "H05339" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06405084205406, + 38.9028839671798, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H05340" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9800871536211, + 38.940791427270284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/15/08

Report Problem", + "NAME": "H05341" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00670052175994, + 38.94352657740833, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05342" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9962431356938, + 38.87667208617181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 11/16/06

Report Problem", + "NAME": "H05343" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09535810201993, + 38.91645696159477, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05344" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98322197200405, + 38.9470769637264, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05772" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9444277021068, + 38.86966536842158, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05773" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98308202550764, + 38.94627435983034, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05774" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05273431036878, + 38.94075003242173, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/18/05

Report Problem", + "NAME": "H05775" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08209134976842, + 38.949611813063065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05776" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03501679279307, + 38.99094057082654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05777" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00452760675826, + 38.94333874189808, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05778" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97408502324092, + 38.85023320107571, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05779" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99698976744763, + 38.94636125004855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05780" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99713676371535, + 38.947298340058076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05781" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94630245638086, + 38.90553917184205, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 09/07/07

Report Problem", + "NAME": "H05782" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09898332968342, + 38.93083426915807, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05783" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97106736384829, + 38.92112225421891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05784" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99619621948037, + 38.95191316246679, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/17/08

Report Problem", + "NAME": "H05785" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0699158929287, + 38.95838294662499, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05786" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97123180688277, + 38.852939441074504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05787" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97021993443934, + 38.852956762797184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, ASECOND

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05788" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97221823730892, + 38.85308055383485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05789" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93751544091515, + 38.90156901873582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05790" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02643630313452, + 38.940985794020946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H05791" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9486886236881, + 38.893194213513155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H05792" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01196468484497, + 38.81611175080019, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05793" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01229113167126, + 38.81695207326778, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05794" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01609466839653, + 38.81595966846284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05796" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01258370061352, + 38.81774323007814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05797" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97737109913541, + 38.90024694909009, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H05798" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0182686576767, + 38.922573045286946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H05799" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9630785749578, + 38.873773470346734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05800" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94177209820324, + 38.9071659817418, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05801" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9396499317961, + 38.86937125964632, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05802" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91998507261452, + 38.901034419180235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05803" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93676555665591, + 38.87566850844981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05804" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99699130726087, + 38.9383029133492, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05805" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98947972607715, + 38.86706854419742, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05806" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0309611201911, + 38.885037349718445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04331" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03047903121914, + 38.88503654865234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04332" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9574374066653, + 38.893647282596596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, USP

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04333" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98357835851769, + 38.878723887905146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04334" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98434653911396, + 38.942615794350445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04335" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98831041513479, + 38.92302299842862, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H04336" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98498477435501, + 38.921753751284506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H04337" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98661194285748, + 38.922992106824246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H04338" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9846218213071, + 38.92359055484959, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04339" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98576120888207, + 38.922308671042686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04340" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9860849098168, + 38.922291621248704, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04341" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0051566762043, + 38.96530814879601, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04342" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94080412483069, + 38.89683436005604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H04343" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98592404782501, + 38.940661475493464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04344" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05624142405397, + 38.95292641422097, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04345" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09416858043568, + 38.947031880036064, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/31/07

Report Problem", + "NAME": "H04346" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07376141114568, + 38.94223943650632, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04347" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07891053737639, + 38.92465313021852, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04348" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08037814241008, + 38.92355520464714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04349" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07890915879342, + 38.92356363764547, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04350" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08749212856794, + 38.95041450615786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H04351" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97990377268994, + 38.86414929282362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04352" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97408323423807, + 38.91414852377485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04353" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97426356969697, + 38.89817544599551, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04354" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03405383232327, + 38.941957330896415, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H04355" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97616749101634, + 38.926721625727005, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H04356" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04497583457153, + 38.93137702251578, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 12/21/07

Report Problem", + "NAME": "H04357" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05915305751323, + 38.976822630001095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04358" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9740456833249, + 38.92456220459464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H04359" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9587956842141, + 38.86054217742242, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04360" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95884183504249, + 38.85933304729061, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H04361" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00058788315079, + 38.846502889142755, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04362" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91214730248898, + 38.89293112152528, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04363" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92862122237243, + 38.89961864877854, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H04364" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03840727415464, + 38.91671801912763, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H04885" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9473117957653, + 38.89095836211015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04886" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97885248960094, + 38.87072844428013, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04887" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93613071799646, + 38.893786277214275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H04888" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98448314505494, + 38.921488444689565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H04889" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98801214318598, + 38.92013571958857, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04890" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07056514361017, + 38.94227044340879, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04891" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00299066434559, + 38.837933116584274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04892" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03559190455715, + 38.939989849360686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H04893" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00075038632602, + 38.91634001521385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H04894" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03145707447457, + 38.96903239044914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H04895" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97639695820709, + 38.90179577036829, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/20/07

Report Problem", + "NAME": "H04896" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.976398620421, + 38.900918293715435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H04897" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99254332655114, + 38.946338512270465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/16/08

Report Problem", + "NAME": "H04898" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03811370522907, + 38.93988385545386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H04899" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03297633060127, + 38.943087450299835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H04900" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92434839294593, + 38.890841907425056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04901" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93156657096162, + 38.89988049165386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H04902" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96949114713723, + 38.86121884139694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H04903" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01234482122938, + 38.82518999581628, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H04904" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97698528805732, + 38.89691055514364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H04905" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06114871389445, + 38.926249688224246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/20/06

Report Problem", + "NAME": "H04906" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98150025790616, + 38.938211873579334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H04907" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01237917558967, + 38.8304484060221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04908" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06231079797175, + 38.95512007551095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04909" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98696883526245, + 38.90145697512101, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/12/07

Report Problem", + "NAME": "H04910" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97441014735803, + 38.897081610737494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H04911" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97453502596304, + 38.89621305154919, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H04912" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09454369663428, + 38.93818203834453, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/09/08

Report Problem", + "NAME": "H04913" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94796489846615, + 38.866243694209345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04914" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94738967034276, + 38.8668550986476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04915" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95598577737442, + 38.88770828910662, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H04916" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01016811902291, + 38.83153291428178, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H04917" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98278215240266, + 38.92551126808792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 08/06/07

Report Problem", + "NAME": "H04918" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0577719928952, + 38.924541798572356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/09/07

Report Problem", + "NAME": "H05345" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96954064114924, + 38.86103968586152, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05346" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05740648369145, + 38.92609225625718, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/14/06

Report Problem", + "NAME": "H05347" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97914189542227, + 38.92669498932551, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H05348" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08634685875595, + 38.955396662533744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05349" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08757434872217, + 38.955391848961035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05350" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96712309472149, + 38.93502505523588, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/09/08

Report Problem", + "NAME": "H05351" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92186662069173, + 38.88554860682302, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/22/08

Report Problem", + "NAME": "H05352" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92386005341119, + 38.88513788880113, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05353" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9225453130617, + 38.884281912300864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H05354" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92066654003027, + 38.88545204773908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H05355" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91974921498726, + 38.885938972864516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05356" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92357400635332, + 38.886407469780586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H05357" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9210566474298, + 38.88621966425954, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05358" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00098222088296, + 38.96206913484772, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05359" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9919239798893, + 38.91870514578134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H05360" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99993764162818, + 38.96206290524546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05361" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98739055205115, + 38.85863509008467, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05362" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98323137150355, + 38.84517784164617, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05363" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02552618625118, + 38.949887314626295, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H05364" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93675533019515, + 38.896725146781314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05365" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0850027940398, + 38.94784311851121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05366" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94564186751613, + 38.88541170555154, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05367" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92092086297211, + 38.88406431617301, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05368" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98960940359626, + 38.84317286248802, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05369" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98864008467258, + 38.84392943653786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05370" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98861860163672, + 38.84313363739907, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H05371" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97068665118475, + 38.846013015585534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05372" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97167229974202, + 38.84561624787174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05373" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96913184562084, + 38.84758237166778, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05374" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97075567496486, + 38.84798369233439, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/06/07

Report Problem", + "NAME": "H05375" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9767221824855, + 38.940356182585624, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05376" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9691593493674, + 38.848208087115324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05377" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96973286725274, + 38.8466519121057, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05378" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99659571186065, + 38.93734830243366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05807" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05351941905525, + 38.96411241174244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H05808" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9959949192952, + 38.92395748803602, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H05809" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0871016481261, + 38.91057372766045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05810" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08675180379811, + 38.90985009527403, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H05811" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00847076962663, + 38.95133610883429, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05812" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97228215091027, + 38.85225696410726, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05813" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03425324628465, + 38.940871260223894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H05814" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98318373089532, + 38.88140054879152, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/17/06

Report Problem", + "NAME": "H05815" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03334164924286, + 38.961437951302145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05816" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0004982191329, + 38.89001893261946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/31/08

Report Problem", + "NAME": "H05817" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99273663493335, + 38.88277421355622, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/07/06

Report Problem", + "NAME": "H05818" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00894081891772, + 38.96573501067958, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05819" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05596680396104, + 38.98036025073512, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05820" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07892673383769, + 38.94968483351879, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05821" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06711790133738, + 38.90598078578831, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05822" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98517476886573, + 38.91033622779275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05823" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98129246261607, + 38.908597474827275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05824" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9875644529908, + 38.909119560540795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/23/07

Report Problem", + "NAME": "H05825" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93712208021883, + 38.873932007474636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05826" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97906720321647, + 38.91658547541989, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05827" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98026894614443, + 38.91547739838723, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H05828" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0186679307301, + 38.892596908355785, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05829" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10064765578079, + 38.92938469821102, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05830" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0236986182379, + 38.96205190077656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05831" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.1007062161376, + 38.92835298836681, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05832" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95786983807483, + 38.89670973468568, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H05833" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0335914887838, + 38.98666253285324, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05834" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03471781215059, + 38.9869926971265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05835" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0217395748448, + 38.90969228354792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H05836" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97135059646807, + 38.923492755895694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05837" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03067991802416, + 38.94712500264623, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H05838" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0120939886857, + 38.900055447565144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H05839" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0055739769854, + 38.82266215248173, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05840" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02407027214022, + 38.91185201786605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H04399" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08374470896311, + 38.94331697552041, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H04400" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09453904984362, + 38.946333763235046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H04401" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03533219868035, + 38.967611017276596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04402" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06620260835496, + 38.92438530238908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H04403" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91859154435178, + 38.89277355859029, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04404" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06095871131957, + 38.95453232319597, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04405" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07389642351586, + 38.91948788178545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 11/08/07

Report Problem", + "NAME": "H04406" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08859736665035, + 38.91367495927595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04407" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0871231148422, + 38.91333775057115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04408" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01905079226289, + 38.89196386434339, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/28/07

Report Problem", + "NAME": "H04409" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03168970613166, + 38.90267357666231, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H04410" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03479404406004, + 38.902677332668766, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/21/07

Report Problem", + "NAME": "H04411" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99564140493116, + 38.90563778451744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H04412" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9949250983879, + 38.9055222595509, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H04413" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08884018472197, + 38.95108008402275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04414" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95502807202708, + 38.87048948077753, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/26/07

Report Problem", + "NAME": "H04415" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02377866844559, + 38.91117320907044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H04416" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9903194852121, + 38.86574497494948, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H04417" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99363369104861, + 38.936910222274584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H04418" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06290405827463, + 38.97689870189981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04419" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03484495968459, + 38.98042754470442, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04420" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98079828008791, + 38.8608934140115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04421" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07185859100335, + 38.91741512859899, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04422" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02224439440603, + 38.956275109245084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/11/07

Report Problem", + "NAME": "H04423" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98350147003177, + 38.904373540988374, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04424" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0647939005297, + 38.94649504084284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H04425" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09009388374997, + 38.933534511848876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H04426" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09275545468826, + 38.94632167961499, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 12/10/07

Report Problem", + "NAME": "H04427" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06467210033686, + 38.957932434728, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H04428" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06340072761463, + 38.955270954553875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04429" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0924177019822, + 38.94483625543618, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/27/07

Report Problem", + "NAME": "H04430" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95852894111589, + 38.876824916550774, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04431" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95747343705025, + 38.89287971951555, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H04432" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95701109105642, + 38.8888371955463, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04919" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04675340907951, + 38.89287132091371, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H04920" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01997645054664, + 38.88616846818783, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H04921" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96487808535504, + 38.92734886480327, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H04922" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95054040186743, + 38.86322085076671, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04923" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9691513800051, + 38.87542052644, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H04924" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95208064969906, + 38.86311931957265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/26/07

Report Problem", + "NAME": "H04925" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08016157894583, + 38.94403834902647, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04926" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05771436921889, + 38.96656424545901, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04927" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06487812403492, + 38.90327332026708, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/01/07

Report Problem", + "NAME": "H04928" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06342198075382, + 38.90275895898322, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H04929" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0198025472746, + 38.895596724314856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/06/08

Report Problem", + "NAME": "H04930" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0061156075087, + 38.94692006560282, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04931" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0200057987405, + 38.90130658536127, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04932" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0199969625686, + 38.90272661898074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/07/08

Report Problem", + "NAME": "H04933" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02001930809196, + 38.89850635272143, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04934" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0200059632849, + 38.90098895967974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04935" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02001053326973, + 38.89997850940823, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04936" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02002984357406, + 38.896737117527046, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04938" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0197983043954, + 38.900329168894444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H04939" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01979705027189, + 38.904907358966696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/29/08

Report Problem", + "NAME": "H04940" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97699565626603, + 38.91587780576576, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H04941" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95001122417332, + 38.8651386792982, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04942" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08868236238992, + 38.912835209308696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04943" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06699749599495, + 38.94776848859413, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04944" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.072321281086, + 38.94723763818863, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H04945" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03674744010685, + 38.90875873103022, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H04946" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03619945891404, + 38.90696027763341, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04947" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03633731965108, + 38.908757318872496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04948" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03620206502912, + 38.90752913594826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/05/07

Report Problem", + "NAME": "H04949" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08773012893722, + 38.908452908738305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/29/07

Report Problem", + "NAME": "H04950" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97632078092181, + 38.89345193026794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04951" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05300149389484, + 38.97462508524917, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04952" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98262115476261, + 38.90310847850502, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/09/07

Report Problem", + "NAME": "H04953" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97156925417775, + 38.84643727924792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H05379" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97292328554563, + 38.938976212740535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H05380" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96978849698085, + 38.84594020557552, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05381" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94888721729193, + 38.892720910674086, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H05382" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99047698797429, + 38.95227606798671, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05383" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99048863527987, + 38.950149855436, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05384" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98947129501609, + 38.95225754181235, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05385" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9894406355584, + 38.95128962731958, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05386" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9906397665663, + 38.95133632026012, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05387" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94708987675162, + 38.892723218281056, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H05388" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97080226062072, + 38.852096793767714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05389" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97006697045208, + 38.85513917804312, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05390" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99559621592604, + 38.83926269236657, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05392" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97312552141948, + 38.90549578509796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "KENNEDY

In Service


Last Inspection Date: 08/27/07

Report Problem", + "NAME": "H05393" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97407912173732, + 38.904747037286725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H05394" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94944326633335, + 38.884900862851964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05395" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95032242214741, + 38.88406482960428, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05396" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95167151454748, + 38.88345882499014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H05397" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95098258789362, + 38.88454948036674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H05398" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94806133795164, + 38.88292427614895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05399" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95116367549177, + 38.88541437006546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05400" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94952149876084, + 38.88303357551387, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H05401" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01903284951779, + 38.89859195289846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H05402" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.044987779945, + 38.901448472355526, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/22/07

Report Problem", + "NAME": "H05403" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04478620615964, + 38.90712354169392, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05404" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04479326656674, + 38.904835751434106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H05405" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04480854421615, + 38.90581124188021, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05406" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04499584077479, + 38.90094063209819, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H05407" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9721139091053, + 38.87395319068186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H05408" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97187262494673, + 38.87335563264001, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05409" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97011235209557, + 38.87310510416403, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05410" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94640947391078, + 38.88277614366396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/24/07

Report Problem", + "NAME": "H05411" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05896514412423, + 38.93661831916949, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H05413" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05896200911285, + 38.9369278999598, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/17/07

Report Problem", + "NAME": "H05414" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9593402986791, + 38.87233184822074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05841" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0715093733097, + 38.906558120097145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "null

In Service


Last Inspection Date: 10/30/07

Report Problem", + "NAME": "H05842" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94046086131658, + 38.88036091505042, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H05843" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96636314112835, + 38.8583540967899, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H05844" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03993575949565, + 38.98880269949869, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H05845" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02789790037157, + 38.90065316761824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05846" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02878617012215, + 38.90034583016884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H05847" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05735394944952, + 38.964456195335785, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H05848" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96701714797383, + 38.84825124649828, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/04/07

Report Problem", + "NAME": "H05849" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00502834788763, + 38.87920177538388, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H05850" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93070057931699, + 38.885421614853634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H05851" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94101338676967, + 38.884928457104344, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05852" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00235142256035, + 38.82724917757216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05853" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00196949291082, + 38.8298207235464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05854" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00212175253381, + 38.828108247496445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05855" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00196756870618, + 38.828952550728346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05856" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00309651012144, + 38.82238616177905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H05857" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00415673828145, + 38.823049143578494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H05858" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95460465958541, + 38.86702253898066, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H05859" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95343992910297, + 38.86654419313684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/08/07

Report Problem", + "NAME": "H05860" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95748144390447, + 38.87447430291672, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05861" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0539154226598, + 38.98323917815843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H05862" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02841592057085, + 38.971140952802195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H05863" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07868874133604, + 38.92623339312654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/09/07

Report Problem", + "NAME": "H05864" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08208331363964, + 38.92706412044146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05865" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05791124199031, + 38.934153201906014, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H05866" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06393519471922, + 38.944682848661124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/26/07

Report Problem", + "NAME": "H05867" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0662173522871, + 38.94896883593362, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H05868" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09226496121309, + 38.93857944972431, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H05869" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08217763775764, + 38.93527920992108, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H05870" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00951568229651, + 38.83929344870545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H05871" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04524595509936, + 38.93966471688504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H05872" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00101695228176, + 38.961352942351006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H05873" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99735478276324, + 38.961513344850474, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05874" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99895309516779, + 38.961325710133806, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H05875" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9622451010904, + 38.86297672492007, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04433" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10522851420588, + 38.927012286670944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Super Centurion

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H04434" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93472844454767, + 38.87373084274489, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H04435" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0774261063245, + 38.92367876508404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H04436" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05477358203676, + 38.94103864816232, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H04437" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97733272743392, + 38.89351700929176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H04438" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08875912058254, + 38.95199010758078, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H04439" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0620741852276, + 38.935210603716584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/02/07

Report Problem", + "NAME": "H04440" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95899519231484, + 38.85735990502317, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/22/07

Report Problem", + "NAME": "H04441" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05836513551615, + 38.97760067913016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04442" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97744795798937, + 38.86830315444358, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - JUMBO

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H04443" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98089608157682, + 38.86892898901475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H04444" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05627995660726, + 38.96563840133289, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H04445" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09050464417739, + 38.94874662697343, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04446" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00188149899884, + 38.9170436161969, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H04447" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95357294660701, + 38.87019551653525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04448" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93458187159659, + 38.8774767504435, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H04449" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95821390067368, + 38.868494257030754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04450" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95612736666627, + 38.86954284516876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H04452" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97513531630638, + 38.94191150643074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H04453" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03945203741759, + 38.939658474334315, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/14/07

Report Problem", + "NAME": "H04454" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04079710909922, + 38.939655211034236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 10/04/07

Report Problem", + "NAME": "H04455" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98531342176409, + 38.85123187388481, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H04456" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02961562668881, + 38.98608963101715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H04457" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06703735187567, + 38.94700715787207, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H04458" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06832477460605, + 38.94713234829342, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04459" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00130771202248, + 38.96382498400293, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H04460" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08114619500478, + 38.96301606225877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H04461" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0416333193583, + 38.93959158788519, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H04462" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00188651893774, + 38.91632212085611, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H04463" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97611415105615, + 38.86754483160119, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04464" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97645379624538, + 38.866548065917556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H04465" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05970039225984, + 38.96107537631399, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H04466" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96693509495171, + 38.87722023900156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H04467" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00357748301012, + 38.884185358911424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/07/07

Report Problem", + "NAME": "H09004" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98996182489935, + 38.84163770984148, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H09005" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9190838851327, + 38.89825298901213, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H09006" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00562726118709, + 38.883615344703756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H09007" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00480563902512, + 38.883948781701825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/24/06

Report Problem", + "NAME": "H09008" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08849333449118, + 38.94622392877475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09009" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03360299392004, + 38.88732290161533, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H09010" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00924643451117, + 38.92232010879566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/25/07

Report Problem", + "NAME": "H09011" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92989443682231, + 38.87703660095473, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H09012" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07867231526322, + 38.95771398704769, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H09013" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08011657973411, + 38.95772090656625, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H09014" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07440646518339, + 38.95772714812114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H09015" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07724774939429, + 38.9577211616338, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H09016" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07325571214197, + 38.9577276675949, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H09017" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04620715619693, + 38.99074082937913, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H09019" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08022957173232, + 38.959047539045855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H09020" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08041293006447, + 38.95694125399052, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H09021" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08018625770872, + 38.9583797592369, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling, B84B

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H09022" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02716711359766, + 38.90314485287352, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H09023" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11008689052852, + 38.936017141943914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H09024" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07161428737155, + 38.95773617937794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H09025" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11185197135288, + 38.9366973137694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H09026" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11090362040375, + 38.9373850915702, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H09027" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02425178916825, + 38.898385721520825, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H09028" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02474664235955, + 38.898234457436175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H09029" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08383015424543, + 38.93018513542305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09030" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0827398142461, + 38.930212522959145, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09031" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07472136855726, + 38.928978569847466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H09032" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07823662247331, + 38.92925954495621, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H09033" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07698472173966, + 38.92890569196667, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H09034" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98649847197449, + 38.834048756474225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H09035" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95743914350457, + 38.887702413760245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H09036" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07902849186996, + 38.929609300438386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09037" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9368312059512, + 38.887520350988865, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H09038" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05605405669904, + 38.923102195678936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 01/08/07

Report Problem", + "NAME": "H08970" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05158834990114, + 38.923354926939524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 01/08/07

Report Problem", + "NAME": "H08971" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05248187934549, + 38.92357129631647, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 01/08/07

Report Problem", + "NAME": "H08972" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06838706302851, + 38.97276431368139, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H08973" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05172957515671, + 38.895318715983656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08974" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05112613962501, + 38.8946953143176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08975" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01659394493691, + 38.88886964654522, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08976" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01039286728023, + 38.89604137722768, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08977" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00916793081885, + 38.89625498703594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08978" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00976508856019, + 38.896211995770386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08979" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00890521939598, + 38.92333068874144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08980" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00887923597604, + 38.92526032659052, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08981" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00883074380967, + 38.92126451866896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H08982" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00889758063224, + 38.92144530164201, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H08983" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93054727831746, + 38.8764421124646, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08984" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93249502606915, + 38.874956895698226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, UNKNOWN

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08985" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04685069061479, + 38.90151463618884, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 05/24/07

Report Problem", + "NAME": "H08986" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98360661757303, + 38.94077524544294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08987" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03094247456977, + 38.930996105813065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - JUMBO

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H08988" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02578610924981, + 38.934131616701535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08989" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02733403213745, + 38.932283229446604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/13/07

Report Problem", + "NAME": "H08990" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02863194469406, + 38.9316224567308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/13/07

Report Problem", + "NAME": "H08991" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02962749395054, + 38.931442132553876, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H08992" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02525756382916, + 38.93484355909263, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H08993" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02617054106372, + 38.93347626731597, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08994" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03122477460342, + 38.930736798657925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/17/07

Report Problem", + "NAME": "H08995" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02010410346386, + 38.957557904088844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H08996" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97721721870975, + 38.84011618368776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08997" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97614963212195, + 38.840954891331414, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08998" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99388153161837, + 38.949339346515366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08999" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97295582131991, + 38.92937535205477, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H09000" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0335954158444, + 38.886626042554695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H09001" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99033427481527, + 38.84255851269548, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H09002" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9190791514341, + 38.89723296849213, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H09003" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93958261646672, + 38.88752469827424, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H09039" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.938523327564, + 38.88750947990186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H09040" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03127870290466, + 38.90659966212444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H09041" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10971776704318, + 38.93652675550647, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H09042" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92861676514879, + 38.87799075308454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H09043" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02301952543257, + 38.89907398439239, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H09044" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03251424432464, + 38.930417724084485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/13/07

Report Problem", + "NAME": "H09045" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98868584439664, + 38.84454760042522, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H09046" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98725939623742, + 38.845051791157864, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H09047" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98732571223994, + 38.84362839214157, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H09048" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98580910873986, + 38.84293345025701, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H09049" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02940215543835, + 38.89916231165648, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H09050" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99160683377616, + 38.940776481011675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H09051" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08871662276252, + 38.91792731727288, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, SUP CENT 250

In Service


Last Inspection Date: 02/19/08

Report Problem", + "NAME": "H09052" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06746405218475, + 38.959528589351265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H09053" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06796380033117, + 38.95895866257383, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/07/07

Report Problem", + "NAME": "H09054" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06931031679339, + 38.95733877204453, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H09055" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02513373945062, + 38.88770298662333, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H09056" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06881553284747, + 38.953933470949494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H09057" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02817215483672, + 38.898833818600494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H09058" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00891120123002, + 38.95228154820823, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H09059" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0092064164634, + 38.95338395734715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H09060" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.009980735443, + 38.96353114862895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H09061" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05276349967937, + 38.915618842913894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H09062" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0143577754417, + 38.88387244475433, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H09063" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00457511249418, + 38.88264351200035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/05/07

Report Problem", + "NAME": "H09064" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00050737183291, + 38.90469006917829, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/06/07

Report Problem", + "NAME": "H09065" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05458488194304, + 38.89968110427733, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 05/11/07

Report Problem", + "NAME": "H09066" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04265684650899, + 38.917043862824684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H09067" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0773012092924, + 38.94401442173012, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H09068" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00336697371237, + 38.91265474042744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H09069" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99957394083697, + 38.899070441190595, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H09070" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0718922072102, + 38.96773723434008, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H09071" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08747186075786, + 38.95216442402454, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 07/29/05

Report Problem", + "NAME": "H09073" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98847895501503, + 38.85906155318294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08539" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92810667045268, + 38.88571439599207, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08540" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02720715557734, + 38.92071337546067, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H08541" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93789165580496, + 38.90010448716796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08542" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93789396160324, + 38.90010430822659, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08543" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98208247464486, + 38.88278337063967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H08544" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06387838038624, + 38.903921815110316, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08545" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02549690318271, + 38.97877464139044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H08546" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93395193642357, + 38.875662023478846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08547" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9565272301833, + 38.91951101565036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08548" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95524269388355, + 38.91835629358651, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08549" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95734343310873, + 38.92004651015837, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08550" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99247925413083, + 38.91105061211053, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08551" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99133037406304, + 38.912175448917964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H08552" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92845323810772, + 38.884431328320815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08553" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98233697261593, + 38.8553387565206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/16/07

Report Problem", + "NAME": "H08554" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04863070654336, + 38.905355998875166, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/29/07

Report Problem", + "NAME": "H08555" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98106392750358, + 38.89985231024399, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H08556" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98862596823128, + 38.864714629169406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 12/03/07

Report Problem", + "NAME": "H08557" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06905955237025, + 38.90512515798623, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08558" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04874893378806, + 38.900796514971326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/29/07

Report Problem", + "NAME": "H08559" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05023201934696, + 38.90081481325534, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/11/08

Report Problem", + "NAME": "H08560" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.051486002836, + 38.90057705923955, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08561" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05003038640514, + 38.900531794088835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/23/07

Report Problem", + "NAME": "H08562" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00066339192198, + 38.87852852246565, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/16/07

Report Problem", + "NAME": "H08563" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99520649659708, + 38.94263358063965, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/28/07

Report Problem", + "NAME": "H08564" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0124059474504, + 38.89345901346585, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08565" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98558821633338, + 38.881415436809974, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/17/06

Report Problem", + "NAME": "H08566" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06514298878535, + 38.943168915701406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H08567" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00973556235982, + 38.898969701189074, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08568" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99960440153339, + 38.931680148096184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/18/08

Report Problem", + "NAME": "H08569" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02882084751378, + 38.89538203379702, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08570" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95577398551826, + 38.921453657739285, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-62-B

In Service


Last Inspection Date: 09/27/07

Report Problem", + "NAME": "H08571" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99433799153933, + 38.93442153569604, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08572" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07024814783125, + 38.96035520520068, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/06/06

Report Problem", + "NAME": "H09075" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02157434211952, + 38.93081015312525, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H09076" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06044338306467, + 38.95086729619458, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller, Centurion

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H09077" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04138955855865, + 38.92204724629831, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H09078" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96813349799348, + 38.84830912049457, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H09079" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05149556832315, + 38.90622612199416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H09080" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01886129175715, + 38.90487578637114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/24/07

Report Problem", + "NAME": "H09081" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0575355775474, + 38.93343887577325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 01/19/07

Report Problem", + "NAME": "H09082" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02412985795266, + 38.915629660431776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H09083" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04786743972032, + 38.903814381451866, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H09084" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9726642394464, + 38.94079268360396, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H09085" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99687070831642, + 38.84043856150093, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H09086" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99670148941775, + 38.8414251711826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/04/07

Report Problem", + "NAME": "H09087" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99616376450973, + 38.841347438865114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H09088" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99626546942768, + 38.84012938271303, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H09089" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99558086774195, + 38.84047124749271, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H09090" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96462619801888, + 38.867748767698956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H09091" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05147823614823, + 38.90459143820292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/13/06

Report Problem", + "NAME": "H09092" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02645801336642, + 38.91481973063547, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 12/04/07

Report Problem", + "NAME": "H09093" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10470015106651, + 38.92956594364366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H09094" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07824829363948, + 38.94508677770197, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H09095" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97340828201314, + 38.933240226765925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/02/07

Report Problem", + "NAME": "H09096" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94317102933596, + 38.86839174932191, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H09097" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08272133244417, + 38.90687530869195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/15/07

Report Problem", + "NAME": "H09098" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99685468394523, + 38.87996472586356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H09099" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99811487378193, + 38.88064576924839, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/22/07

Report Problem", + "NAME": "H09100" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02726999628489, + 38.90368911361274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H09101" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0019692494539, + 38.92414068820509, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/19/07

Report Problem", + "NAME": "H09102" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01801354766188, + 38.91786057760934, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 04/25/07

Report Problem", + "NAME": "H09103" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99122699292546, + 38.86560177687061, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09104" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00582934571723, + 38.836443164116645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09105" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00705729089124, + 38.94511711313671, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09106" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.017932382195, + 38.95840675440536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H09107" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99387661280471, + 38.82838777400342, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09108" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00277619794527, + 38.840649169966404, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08573" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97893477015928, + 38.922249347046964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H08574" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98281480852543, + 38.900163450372936, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H08575" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92387367558487, + 38.88513912282087, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08576" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92372227500937, + 38.885729956071486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08577" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94976052046304, + 38.897346563918575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 11/01/07

Report Problem", + "NAME": "H08578" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9780028653113, + 38.92134510906843, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H08579" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97710272923885, + 38.92134207151667, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H08580" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95547082433256, + 38.916845215248195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08581" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0163829945223, + 38.885129586393255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/04/08

Report Problem", + "NAME": "H08582" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.066732816111, + 38.943233905541746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 05/19/07

Report Problem", + "NAME": "H08583" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0188403268678, + 38.89752307892184, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/23/07

Report Problem", + "NAME": "H08584" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01078834197283, + 38.82034062677432, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08585" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95616480637626, + 38.9173618352077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08586" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08778468943332, + 38.912005453128366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08588" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0190235699886, + 38.89491934354903, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H08589" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04871429874123, + 38.9027658192885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H08590" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01785694742098, + 38.8949398055434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H08591" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08531548338183, + 38.96025498219793, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H08592" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93091026436544, + 38.88471216661913, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/18/08

Report Problem", + "NAME": "H08593" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0292329918798, + 38.895165640505745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08594" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02817718438348, + 38.89528165745904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08595" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02636842694048, + 38.894377792826916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08596" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02763771690492, + 38.89472860054361, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08597" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03624882205068, + 38.91255320036532, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08598" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95315223039381, + 38.89604881395341, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08599" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9542234507704, + 38.89574466577712, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08600" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05146632364985, + 38.90712772648776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08601" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01505682147155, + 38.89810909931428, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08602" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0328013762658, + 38.89542667433872, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08603" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03339296921185, + 38.89543517277314, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08604" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03228069099289, + 38.895422963803064, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08606" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03021130752691, + 38.89540046491191, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08607" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03350770572573, + 38.89625304547842, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08608" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02960799630996, + 38.961090066635336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09109" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05019193509814, + 38.90756477139692, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09110" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96648470400932, + 38.92013823949831, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09111" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9297498272209, + 38.87967084813571, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09112" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94619741559671, + 38.87003159623627, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09113" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10102767277525, + 38.947858528055356, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09114" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05554828483594, + 38.94853023909844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09115" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94185638025759, + 38.910048226097835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09116" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94165583304925, + 38.91062310166634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/23/07

Report Problem", + "NAME": "H09117" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92841214462342, + 38.88896179884377, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09119" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0080803275818, + 38.922323032865336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09120" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08707243694516, + 38.9197300581798, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09121" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09876766725233, + 38.924753710956594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09122" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06290905606541, + 38.95142208519586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09123" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04212265248194, + 38.927215723489915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09124" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07375563903265, + 38.917683295757456, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09125" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05579576042543, + 38.966428494542434, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09127" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08904881612418, + 38.91084858186611, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09128" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09570717923661, + 38.94523554935284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09129" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06305312075824, + 38.921629911800125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09130" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06395864164293, + 38.92326983546393, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09131" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06339716970705, + 38.92246111292508, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09132" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05880662632796, + 38.91826584899397, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09133" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10355354396799, + 38.93630939668897, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09134" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98861879462714, + 38.86280517775928, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09135" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03408750048177, + 38.937826883828016, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09136" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06367368575731, + 38.91837362332335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09137" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0741708440765, + 38.93495234787948, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09138" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92506018847027, + 38.88393071247643, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09139" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92493181329877, + 38.884481339738386, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09140" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92204363869698, + 38.89948032821506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09141" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91640749423819, + 38.89241017670246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09142" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91496586742983, + 38.89214454216605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09143" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00089124142046, + 38.947265932911634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09144" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02974063992806, + 38.895949150130065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H08609" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03350426658844, + 38.895802898442945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08610" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04157587307783, + 38.903605552933925, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08611" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01158647754188, + 38.89739787047814, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08612" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03210752067322, + 38.88534626194587, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08613" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97312984969142, + 38.866308436257476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H08614" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03906963220658, + 38.93623050470729, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H08615" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03918911488095, + 38.935645546810676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H08616" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04289804909273, + 38.917865163142665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/13/07

Report Problem", + "NAME": "H08617" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03763703123715, + 38.903822692349024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08618" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03642533723821, + 38.9520148834351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H08620" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03830565562527, + 38.90558203132135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08621" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99725103922168, + 38.8332830923234, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H08622" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99630317677882, + 38.83843283127437, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08623" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.066625503076, + 38.941529310018225, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/09/07

Report Problem", + "NAME": "H08624" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99993013762492, + 38.83681705245397, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08625" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07331721140595, + 38.924396693909536, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08626" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07331252436354, + 38.92413384303951, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08627" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96411210838446, + 38.87183401332887, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H08628" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99312976410624, + 38.93558784763175, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08629" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97231364336412, + 38.90457533844903, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 05/10/07

Report Problem", + "NAME": "H08630" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04356876428044, + 38.89942150787223, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08631" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04480016525211, + 38.90660488068256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08632" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99136845088773, + 38.856691028575334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08633" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98984033585377, + 38.856454659628795, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08634" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00610322556301, + 38.96182890973894, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/01/07

Report Problem", + "NAME": "H08635" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04327724804261, + 38.907184871679476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08636" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04277072775197, + 38.908086676633566, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08637" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93632382533126, + 38.886498083628815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H08638" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.937772868302, + 38.88658598467158, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08639" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92000330174575, + 38.887215707149984, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08640" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01129797638228, + 38.86416133074623, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/05/07

Report Problem", + "NAME": "H08641" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03631511351088, + 38.95069560213885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H08642" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03640989294186, + 38.96209450356922, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08643" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09378367864437, + 38.91851770325485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09145" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0844194101977, + 38.927045394571586, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09146" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06441627664769, + 38.9243047933927, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09147" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97771945972165, + 38.85521600151856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09148" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03831307100914, + 38.95946090830021, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09149" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94115878588856, + 38.899671056590996, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09150" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9407366966845, + 38.899668419982824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H09151" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0991376094575, + 38.93646688920711, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09152" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07280482125975, + 38.95335239949877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09153" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10110220180124, + 38.9212167303206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09154" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07190949779098, + 38.92613818312947, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H09155" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02128453702582, + 38.931120965843505, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H09156" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10296233056515, + 38.94532665579319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H09157" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10192090967148, + 38.9448149877885, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H09158" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10206518499017, + 38.94401836694838, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H09159" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10292406615106, + 38.94463878952908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H09160" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.11001111691373, + 38.935728803382325, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H09161" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08012954794336, + 38.96494590779582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H09162" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06212037615211, + 38.97220825480305, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H09163" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00911958466912, + 38.82529102514977, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/13/07

Report Problem", + "NAME": "H09164" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00603900133896, + 38.87314829248499, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H09165" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0184886036488, + 38.947477979507475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H09166" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0225139425842, + 38.907191005939524, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H09167" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02408928454868, + 38.90676327269332, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H09168" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02440045866837, + 38.90311953742286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, U.S. Pipe

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H09169" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02407891719905, + 38.90433096633858, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/31/07

Report Problem", + "NAME": "H09170" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02408624206616, + 38.90499157424918, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H09171" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03463471331794, + 38.91679430967951, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H09172" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02488832410485, + 38.92748731052724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 09/04/07

Report Problem", + "NAME": "H09173" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09506403013819, + 38.931655693652665, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/20/07

Report Problem", + "NAME": "H09200" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01419335897909, + 38.90569583721601, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/23/35

Report Problem", + "NAME": "H09209" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97435898380105, + 38.921337844320796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H09210" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00600777493914, + 38.875924529424545, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H09211" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96048194541679, + 38.922145111982026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 09/19/07

Report Problem", + "NAME": "H09212" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0365171720218, + 38.95722354284319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08644" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03629389177893, + 38.95627977159117, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08645" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03630917532455, + 38.95471040089543, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08646" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0364698500718, + 38.960254197407686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08647" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09957558862641, + 38.94633227510696, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08648" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05324307807622, + 38.90539970535039, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08649" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00894028788855, + 38.90318464877102, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 12/04/07

Report Problem", + "NAME": "H08650" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99534466044936, + 38.92166486427478, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08651" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05645273887436, + 38.90530147588465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08653" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03620649184059, + 38.96337918858392, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08654" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93865236050358, + 38.90497913058511, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08655" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00815716269088, + 38.876340424827504, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H08656" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98657553738025, + 38.89817850053494, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08657" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.931773242978, + 38.8841441907157, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08658" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9930423485349, + 38.9573333541786, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H08659" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92994989815949, + 38.890836788946245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant,

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08661" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92997594811217, + 38.883802573958064, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 08/08/07

Report Problem", + "NAME": "H08662" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02697048070101, + 38.917172418815746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H08663" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08223133785353, + 38.95203849934632, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08664" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02606367036198, + 38.91716313882413, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H08665" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0703015182813, + 38.92283706239084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08666" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07106839101364, + 38.92249210221713, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08667" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98817930239974, + 38.88904215198616, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-MET 250 M94

In Service


Last Inspection Date: 04/12/06

Report Problem", + "NAME": "H08668" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05670833521232, + 38.95181880180764, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08669" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02801847312037, + 38.91717313612248, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08670" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0985296394079, + 38.944991079714455, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H08671" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0258221077461, + 38.91690732883077, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H08672" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05787320457475, + 38.946203884831085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08673" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03250940463836, + 38.897188053460745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08674" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92615708432245, + 38.88056312919905, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08675" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92634950900363, + 38.87977925928223, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08676" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9228931109311, + 38.882415838617035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/09/07

Report Problem", + "NAME": "H08677" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92802269818132, + 38.878476877868756, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08678" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92470871810644, + 38.881252049100986, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08679" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9878245599078, + 38.9237225709901, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/08/08

Report Problem", + "NAME": "H09213" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03731597080925, + 38.90863732553582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant,

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H09214" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08577616013496, + 38.91399775225103, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H09215" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08117232595204, + 38.906624008174255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H09216" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03475152340339, + 38.96119169648588, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H09217" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0059644714094, + 38.90576332599382, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H09219" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00568250168304, + 38.907186244644734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H09220" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00432703588632, + 38.90728189928287, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H09221" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00343405921083, + 38.9081582067841, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 09/28/07

Report Problem", + "NAME": "H09222" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00034088857399, + 38.83846501346144, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant,

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H09223" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99960080784255, + 38.83813712361215, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant,

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H09224" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99985962331871, + 38.83740941232444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant,

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H09225" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95688877125403, + 38.92222182671161, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/01/07

Report Problem", + "NAME": "H09226" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01760034198207, + 38.90729710297956, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H09227" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06624073525964, + 38.953201423673065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H09228" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92913156939407, + 38.882355344568744, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H09229" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93027475983557, + 38.882423091085336, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H09230" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93130519026096, + 38.882261289449474, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H09231" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93109090951636, + 38.88194094199932, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H09232" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92995346739029, + 38.88168354426477, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H09233" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92926175286132, + 38.88168796486839, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/06/07

Report Problem", + "NAME": "H09234" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00313297767796, + 38.84516448239475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/09/07

Report Problem", + "NAME": "H09235" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99692024402691, + 38.841638380100676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/10/07

Report Problem", + "NAME": "H09236" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95021359767463, + 38.92198895680593, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/21/07

Report Problem", + "NAME": "H09237" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9579299449329, + 38.9229395208611, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/22/07

Report Problem", + "NAME": "H09238" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95938626070784, + 38.92353032431596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H09239" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95847938418572, + 38.92279785431506, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H09240" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95760369554229, + 38.92229999224416, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H09241" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95615038327321, + 38.92200928886095, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H09242" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9543213685154, + 38.92251046894431, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H09243" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95254171269899, + 38.922466952213284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 10/24/07

Report Problem", + "NAME": "H09244" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02475624239386, + 38.81511391306391, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Blue Plains # C6FH1

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09246" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06198194751812, + 38.93573992641686, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09252" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05678210789156, + 38.95360997067364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09253" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0123858362094, + 38.828744102767445, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 12/04/07

Report Problem", + "NAME": "H08716" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98754090090777, + 38.833196410884035, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08717" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9742776640474, + 38.92162172376561, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 08/02/07

Report Problem", + "NAME": "H08718" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93916313099159, + 38.88659397782849, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 02/06/08

Report Problem", + "NAME": "H08719" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02411427793977, + 38.89621935576537, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08720" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00894501157781, + 38.89966655200319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08721" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95543539481729, + 38.91702175603697, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08722" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93673635039156, + 38.902866577574734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08723" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09740785062755, + 38.94627545753691, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08724" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05951181249839, + 38.92439979219147, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/16/07

Report Problem", + "NAME": "H08725" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00719253295067, + 38.89904011461296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08726" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00703195557956, + 38.89959103062003, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08727" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05022256405657, + 38.90669025481118, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H08728" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99921924360699, + 38.920356747571944, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08729" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99480636483248, + 38.9406118332587, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08730" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04527402585663, + 38.98588461797464, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08731" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01814302217667, + 38.95880404920544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08732" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01701177841085, + 38.95882519049787, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08733" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95850855229487, + 38.88765021662725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08734" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94987427777586, + 38.90156101218892, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08735" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95099383531999, + 38.90076210352137, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H08736" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95160739815256, + 38.90006137382878, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H08737" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9506869221206, + 38.89935376957078, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08738" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94943419635878, + 38.89937397130198, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08739" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94990358588407, + 38.89991547689804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08740" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94888915521787, + 38.90071557434845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08741" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94976507820202, + 38.90063092438199, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08742" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94880481857784, + 38.899890110458124, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H08743" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08502300070731, + 38.96120636834058, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08744" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08245619336594, + 38.96305487221091, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08745" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98921235707812, + 38.920913047791174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08747" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99271458108961, + 38.91827389700935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/31/07

Report Problem", + "NAME": "H08748" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.000642778057, + 38.89686912089262, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08750" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99426785972668, + 38.957170380157024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H08751" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9977977081463, + 38.956312525984444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H08752" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9910333859845, + 38.85783473998021, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09254" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03484254061438, + 38.924854356532954, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09255" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92492428778557, + 38.90493126258286, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09256" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05359944418875, + 38.93963261059847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09257" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05497419264395, + 38.93358499815553, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09258" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01963994825064, + 38.91685340945908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/13/07

Report Problem", + "NAME": "H09259" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9393199621042, + 38.9095423789871, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09260" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0569848218339, + 38.915468141927384, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09261" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05026678134584, + 38.8969760471546, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/07

Report Problem", + "NAME": "H09262" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99579511363885, + 38.910090264103694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H09263" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02964645346998, + 38.923367300566554, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H09264" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99652434753408, + 38.923666977676156, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H09265" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04244517980435, + 38.921569777825226, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/07

Report Problem", + "NAME": "H09266" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02863271827209, + 38.90959566054185, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09267" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97879161578743, + 38.906967690069855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09268" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08660677716558, + 38.953353367458945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09269" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97998503074454, + 38.86167664955933, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09270" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01582900249406, + 38.81408747120256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09271" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04353400002903, + 38.90876056131167, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09272" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9834197310972, + 38.881702759897244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Am. Darling

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09273" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00472157906025, + 38.873093230776824, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H09274" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98465617367789, + 38.95082372991569, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H09275" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98358834951473, + 38.95033262497695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09276" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98419270966416, + 38.95004420025911, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09277" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91906978186881, + 38.89471075395269, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/07/07

Report Problem", + "NAME": "H09278" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99739549998577, + 38.87881243983216, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Am Darling

In Service


Last Inspection Date: 01/18/08

Report Problem", + "NAME": "H09279" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97697794278825, + 38.918670907205694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09280" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00765329097595, + 38.87469895781118, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09281" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00814307381587, + 38.874570203679475, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09282" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02698543669445, + 38.88109182517637, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09283" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95334734690051, + 38.922382256060715, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H09284" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01735475465979, + 38.904358562165754, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 10/29/07

Report Problem", + "NAME": "H09285" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94875785077852, + 38.919135021316265, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/02/08

Report Problem", + "NAME": "H09287" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01647577934592, + 38.887834483621496, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Am Darling

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09289" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92176550434398, + 38.88329910897763, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08680" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92708947381672, + 38.87919746603908, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08681" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92408481032187, + 38.88149445740319, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08682" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92724450655383, + 38.88085838608868, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/22/08

Report Problem", + "NAME": "H08683" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07249169154235, + 38.94104680332024, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 09/26/07

Report Problem", + "NAME": "H08684" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06213333298192, + 38.910528947731486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 08/14/07

Report Problem", + "NAME": "H08685" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99943835888241, + 38.83179842987002, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08686" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91907201002455, + 38.893640804205596, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08687" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02385434134246, + 38.901869704953135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/13/07

Report Problem", + "NAME": "H08688" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01076323869623, + 38.82859341691804, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H08689" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0447586788924, + 38.923942625522734, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/19/06

Report Problem", + "NAME": "H08690" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92417114762259, + 38.883791733801765, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08691" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98462632190741, + 38.89806074620181, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08692" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98464381741263, + 38.89738229270767, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08693" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07718089395061, + 38.93598943465808, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08694" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07757129766513, + 38.9367000302747, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08695" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07584002977998, + 38.937236214401075, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08696" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07706932574608, + 38.93905212281427, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08697" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07544023444585, + 38.93934356801358, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08698" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07768494898157, + 38.93774250334308, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08699" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07474534176015, + 38.93553232380206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08700" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02982851136642, + 38.908624000642575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08701" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02096405326786, + 38.90174500717568, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08703" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99859094633403, + 38.89606670313516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08704" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92814733406689, + 38.886446604404135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08705" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93251427921629, + 38.8869028262654, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/10/07

Report Problem", + "NAME": "H08706" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0034341312402, + 38.89624412593952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08707" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00041705038856, + 38.89617952263983, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08708" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93046233533161, + 38.886739300636116, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08709" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.002188089492, + 38.89618109737246, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08710" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01868116301925, + 38.89351866065366, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08711" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02970206975802, + 38.91248058503723, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/18/07

Report Problem", + "NAME": "H08712" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02981000497276, + 38.911903447315964, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08713" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93246260635284, + 38.88485872213008, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08714" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99889835956795, + 38.94631824204952, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08715" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00704136408936, + 38.885008072195916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09290" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95490844331678, + 38.92177986069538, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09291" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9513086707524, + 38.922063673823594, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09292" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00297870587309, + 38.8204773226711, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09293" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05157131009331, + 38.93632515399027, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 11/16/07

Report Problem", + "NAME": "H09294" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9495104797852, + 38.92002390334836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 11/16/07

Report Problem", + "NAME": "H09295" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00887852285749, + 38.87368417400741, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/16/07

Report Problem", + "NAME": "H09296" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94949797892636, + 38.921783647311045, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 11/16/07

Report Problem", + "NAME": "H09297" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02415624676367, + 38.93621100856753, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 08/29/40

Report Problem", + "NAME": "H09298" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02442615867146, + 38.93595231520718, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/29/40

Report Problem", + "NAME": "H09299" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02609666353408, + 38.937559737122406, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 12/17/07

Report Problem", + "NAME": "H09300" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94939449191173, + 38.9211680997582, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09301" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05972008660773, + 38.937843839182165, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/07/08

Report Problem", + "NAME": "H09303" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9884488395658, + 38.87414238669879, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 11/19/07

Report Problem", + "NAME": "H09304" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01075912714681, + 38.88484834953486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H09307" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98616535584016, + 38.93174177554106, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09308" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0229307459235, + 38.97470163447889, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/07/08

Report Problem", + "NAME": "H09309" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00602604304966, + 38.87431165593684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09310" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00270167910509, + 38.836865495703044, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09311" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09789717388706, + 38.92599935744832, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09312" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96160666683869, + 38.92290792427751, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09313" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95758538479275, + 38.93051777670375, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/23/08

Report Problem", + "NAME": "H09314" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01623186735475, + 38.913344618983736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 01/24/08

Report Problem", + "NAME": "H09315" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06442779964327, + 38.938998788117466, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 04/02/30

Report Problem", + "NAME": "H09316" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04492253938406, + 38.91340050265108, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/17/08

Report Problem", + "NAME": "H09317" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9631310490341, + 38.924952655145624, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 01/24/08

Report Problem", + "NAME": "H09318" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96655507916714, + 38.91706741053211, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 01/25/08

Report Problem", + "NAME": "H09319" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99833925795618, + 38.87756015531194, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Am Darling

In Service


Last Inspection Date: 01/22/08

Report Problem", + "NAME": "H09320" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91878616593085, + 38.88958460278862, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 01/24/08

Report Problem", + "NAME": "H09321" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00933868020185, + 38.87197153292126, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H09322" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00890359683652, + 38.871819937468985, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H09323" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00756097818527, + 38.87117409356284, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H09324" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0066963196627, + 38.87152652806933, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H09325" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00849222136488, + 38.87081333305187, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H09326" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99431464556976, + 38.95642802955262, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H08753" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9914366175631, + 38.954583078672904, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H08754" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96700810746621, + 38.86464720208796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08755" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9659872441215, + 38.864224378497006, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08756" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96460894537778, + 38.863711128787294, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08757" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96763373361483, + 38.86553339070093, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/17/07

Report Problem", + "NAME": "H08758" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96613072149334, + 38.862597031785256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H08759" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96730990863365, + 38.86332970713221, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 08/20/07

Report Problem", + "NAME": "H08760" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01778644994052, + 38.91354216170856, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08761" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07548153425437, + 38.91275512895882, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08762" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07523671171474, + 38.91252506068831, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08763" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07398417995368, + 38.91262140294875, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08764" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07620466046885, + 38.91256654740798, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08765" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08259014522528, + 38.912883571964244, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08766" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.08164952241454, + 38.91259664174641, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08767" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00500905428665, + 38.90988776990425, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08768" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00476109283106, + 38.897079614148794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08769" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02387038061198, + 38.894678795089796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08770" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03086190785439, + 38.91709656058297, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08771" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0297118888888, + 38.916759568717914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/13/07

Report Problem", + "NAME": "H08772" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02816493910211, + 38.896791975907256, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08773" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01653222067856, + 38.9004082026011, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08774" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01316311014868, + 38.900283765943584, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08775" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0092874073791, + 38.90027519304724, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08776" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00928195840858, + 38.90030505618723, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08777" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00668024480795, + 38.96545990568684, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/24/07

Report Problem", + "NAME": "H08778" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94550679698732, + 38.87166270732186, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 08/07/07

Report Problem", + "NAME": "H08779" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94864753687541, + 38.87267007211219, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H08780" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0098480825433, + 38.90027040873241, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08781" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01057145694017, + 38.90027449836676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08782" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01372806366703, + 38.90034702967891, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08783" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92622347641245, + 38.90457663859126, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/28/07

Report Problem", + "NAME": "H08784" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01270689411403, + 38.89880922911742, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/27/07

Report Problem", + "NAME": "H08785" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02816231811993, + 38.89695654133128, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08786" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03184846819468, + 38.900326910649255, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08787" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00603296870757, + 38.87526238391792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H09327" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00579855860819, + 38.87530645586449, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H09328" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03228881386602, + 38.90980407028345, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H09329" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0424313981925, + 38.90970658186085, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/05/08

Report Problem", + "NAME": "H09331" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01980048400594, + 38.89896138429871, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/04/08

Report Problem", + "NAME": "H09332" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0197897148647, + 38.89966073211877, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H09333" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07260007877383, + 38.922600638857574, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H09334" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91955468659461, + 38.888397145538676, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H09335" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91882591439352, + 38.88866839715733, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H09336" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91817019879976, + 38.888008309955815, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H09337" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9192318088207, + 38.887564386148846, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/11/08

Report Problem", + "NAME": "H09338" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00441930506632, + 38.878433014833476, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/20/08

Report Problem", + "NAME": "H09339" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00222548091834, + 38.823995059116136, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/14/08

Report Problem", + "NAME": "H09340" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00339713525518, + 38.8259588777402, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/15/08

Report Problem", + "NAME": "H09341" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00366669730415, + 38.83047224678334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 02/15/08

Report Problem", + "NAME": "H09342" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95001355327334, + 38.91932828938052, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 03/03/08

Report Problem", + "NAME": "H09344" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95436733392737, + 38.91894300981501, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 03/03/08

Report Problem", + "NAME": "H09345" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01120709117866, + 38.82221083722736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 03/03/08

Report Problem", + "NAME": "H09346" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98648607661214, + 38.85718614604409, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Kennedy

In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H09347" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.041676246334, + 38.94714072415591, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 03/03/08

Report Problem", + "NAME": "H09348" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04102689629917, + 38.94680192721034, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 03/03/08

Report Problem", + "NAME": "H09349" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99351976995797, + 38.82914942057292, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H08788" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02306623927376, + 38.90200428589626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08789" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02273902097328, + 38.90094169730195, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08790" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01354351443048, + 38.905663898680736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08791" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01611015837176, + 38.90520113832982, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/13/07

Report Problem", + "NAME": "H08792" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99126877216338, + 38.82926070859868, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 10/09/07

Report Problem", + "NAME": "H08793" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9962210632459, + 38.82929124246931, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/15/07

Report Problem", + "NAME": "H08794" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98596243998557, + 38.95270681195157, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/26/07

Report Problem", + "NAME": "H08795" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05914725121823, + 38.901338907915296, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/30/07

Report Problem", + "NAME": "H08796" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02816488572094, + 38.90205840720238, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08797" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00438123513435, + 38.8768691951298, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 01/08/08

Report Problem", + "NAME": "H08798" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00729788668431, + 38.87638065012211, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/30/07

Report Problem", + "NAME": "H08799" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02953115953406, + 38.88513969491125, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08800" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02174856904672, + 38.90848554213636, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08801" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94764937578191, + 38.90081239671709, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 01/15/08

Report Problem", + "NAME": "H08804" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03456215344579, + 38.895293410353915, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08805" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0187164660632, + 38.91731535508084, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/22/06

Report Problem", + "NAME": "H08806" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00064074063144, + 38.89720034941164, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08807" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01764854205611, + 38.91739140742575, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08808" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00186229085949, + 38.897264989345544, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08809" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99579591702195, + 38.86301105765919, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/05/07

Report Problem", + "NAME": "H08810" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04134678878712, + 38.94826382225088, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H08812" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9947575163789, + 38.860123304058206, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08813" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93580729222725, + 38.88550585180411, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08814" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.93350421003265, + 38.88206520635128, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/17/07

Report Problem", + "NAME": "H08815" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07033226944189, + 38.95585197812847, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, OTHER, SEE FLD NOTES

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08816" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00053821190153, + 38.86497991214398, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08817" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99867121250075, + 38.86451523383149, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08818" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0532404472594, + 38.90606095552444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08819" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02167392330027, + 38.91226876229872, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08820" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0220094395951, + 38.91607889222257, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H08821" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02174173458414, + 38.91265460385914, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/11/07

Report Problem", + "NAME": "H08822" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02200785880494, + 38.91166616810135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08823" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02174802471912, + 38.915624200529365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 10/31/07

Report Problem", + "NAME": "H08825" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05409560402761, + 38.910519496075764, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08861" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05216748407929, + 38.91064744453669, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08862" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05607816992051, + 38.9106080051977, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08863" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05721275393297, + 38.91064462356736, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 02/07/08

Report Problem", + "NAME": "H08864" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02699217347983, + 38.88744503140304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08865" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02567433151633, + 38.88745080560488, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08866" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0639111800448, + 38.910509981111844, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/25/07

Report Problem", + "NAME": "H08867" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0019330980894, + 38.84337726915251, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08868" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00914338527055, + 38.83390007124215, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/02/07

Report Problem", + "NAME": "H08869" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10089936078661, + 38.93233392892799, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08870" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09919728642942, + 38.932396137964176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US Pipe, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08871" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10328700024372, + 38.93218317915868, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08872" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10229653912195, + 38.93413978118592, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08873" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10061113416536, + 38.933735347816096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08874" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.10308342998931, + 38.932346778645694, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy, Eddy

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08875" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05507834449074, + 38.91062579482191, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08876" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07589667021534, + 38.96494866877805, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08877" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97197844433609, + 38.891855965227826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 03/09/07

Report Problem", + "NAME": "H08878" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07909584259765, + 38.95073413849933, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08879" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03735816088506, + 38.90245803421959, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 08/03/07

Report Problem", + "NAME": "H08880" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03980873715406, + 38.90268759556199, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 10/01/07

Report Problem", + "NAME": "H08881" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09359919803424, + 38.92759885559243, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08882" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04175348077844, + 38.902731030627535, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/15/07

Report Problem", + "NAME": "H08883" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.09197855260298, + 38.92766514632522, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/25/07

Report Problem", + "NAME": "H08884" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03811752505584, + 38.902671782404745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/28/07

Report Problem", + "NAME": "H08885" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04366221031981, + 38.902358485978134, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 06/18/07

Report Problem", + "NAME": "H08886" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03869502663345, + 38.90243456471562, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08888" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04272069933567, + 38.90236633801674, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/14/07

Report Problem", + "NAME": "H08889" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04479492523886, + 38.90272215686607, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/06/08

Report Problem", + "NAME": "H08890" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03926909323233, + 38.90274976468699, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08891" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01589502215094, + 38.97502547718258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08892" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00731297615674, + 38.83143909777326, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08893" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00830265070712, + 38.83358891883111, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08894" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00782139634741, + 38.83130444234121, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08895" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0230045609527, + 38.91690870121258, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/04/06

Report Problem", + "NAME": "H08826" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02181590769047, + 38.91340550702836, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 11/20/07

Report Problem", + "NAME": "H08827" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02492865820847, + 38.91691082890837, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H08828" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02406675489375, + 38.91718084514725, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 05/21/06

Report Problem", + "NAME": "H08829" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98709616556368, + 38.8936885107829, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08830" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03810995635037, + 38.939883631468845, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, LORTON - O'BRIEN

In Service


Last Inspection Date: 09/10/07

Report Problem", + "NAME": "H08831" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07159875383506, + 38.954780396611895, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08832" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03668217965783, + 38.942963644253346, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 09/12/07

Report Problem", + "NAME": "H08833" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03656952824868, + 38.94620334692981, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, US PIPE-A P SMITH

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H08834" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03663183523125, + 38.94510889314444, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/19/07

Report Problem", + "NAME": "H08835" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03096571153398, + 38.90026399937653, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08836" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03222516801468, + 38.900282161921794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08837" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03210463724255, + 38.90068526508826, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 01/22/08

Report Problem", + "NAME": "H08838" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94937575343454, + 38.90599532150236, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H08839" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95131294599805, + 38.90749146767299, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/16/08

Report Problem", + "NAME": "H08840" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94842237740023, + 38.90146015322745, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H08841" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95238859240804, + 38.907112947779304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 01/17/08

Report Problem", + "NAME": "H08842" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95154392848963, + 38.9043143366131, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08843" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.94898009499613, + 38.90193432779135, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H08844" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95062673621489, + 38.90351450627775, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 10/17/07

Report Problem", + "NAME": "H08845" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95286968234223, + 38.905953777320335, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08846" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9497264341279, + 38.90257922625323, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/21/07

Report Problem", + "NAME": "H08847" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.95007755170082, + 38.907171996772334, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 11/30/07

Report Problem", + "NAME": "H08848" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00336463139561, + 38.842961199618784, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/24/07

Report Problem", + "NAME": "H08849" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02286540829637, + 38.89670426590485, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08850" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07275352764715, + 38.91269357580465, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 11/02/07

Report Problem", + "NAME": "H08852" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96716302397698, + 38.85190698308656, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08853" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03214122554058, + 38.88655624045092, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08854" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96692717290887, + 38.85139537259351, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08855" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07264693992603, + 38.91544224830243, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H08856" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03212633583716, + 38.884691860814364, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08857" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.96803996442917, + 38.85199745492108, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08858" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07280393808152, + 38.91366517493101, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08859" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07260695412066, + 38.91453874598076, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08860" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00826482290368, + 38.83245611662837, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08896" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01525667252106, + 38.908744515140945, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/12/07

Report Problem", + "NAME": "H08897" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99827272276606, + 38.908666333146115, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08898" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00019506106203, + 38.90780101313025, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP SMITH - O'BRIEN

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08899" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99805374292248, + 38.906912918249304, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08900" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99899097407206, + 38.90758652922681, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08901" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.06054096499086, + 38.910546133805695, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/02/07

Report Problem", + "NAME": "H08902" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00196182580596, + 38.901195632331486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08903" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02256671912761, + 38.925323381009946, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 09/22/06

Report Problem", + "NAME": "H08904" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0224827886553, + 38.924742946249395, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 09/22/06

Report Problem", + "NAME": "H08905" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02325215783448, + 38.92817018034462, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 08/05/06

Report Problem", + "NAME": "H08906" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0230417930079, + 38.92704055251279, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/11/07

Report Problem", + "NAME": "H08907" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02292954828596, + 38.92783495469365, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08908" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02275504535227, + 38.9250467260951, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08909" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02294983457368, + 38.92618751922533, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/29/07

Report Problem", + "NAME": "H08910" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0227418074932, + 38.92653292969026, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08911" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99387490699182, + 38.90009920716982, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/02/07

Report Problem", + "NAME": "H08912" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00771007729371, + 38.95123949370792, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08913" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00676463176144, + 38.949939937648274, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 07/26/07

Report Problem", + "NAME": "H08914" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03357163121086, + 38.900060519441354, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08915" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.031794129773, + 38.90013284937174, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 05/31/07

Report Problem", + "NAME": "H08916" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03275012726523, + 38.90010165057746, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08917" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03347979444293, + 38.900274980769176, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Clow Eddy

In Service


Last Inspection Date: 06/01/07

Report Problem", + "NAME": "H08918" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04018872076269, + 38.98957042717275, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: Unavailable

Report Problem", + "NAME": "H08919" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04189650696442, + 38.98827397062993, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 02/05/08

Report Problem", + "NAME": "H08920" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00527344245755, + 38.89614490231935, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08921" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07473909704427, + 38.943185775947015, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08922" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01699162514261, + 38.920507341162114, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 09/22/06

Report Problem", + "NAME": "H08923" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07070706888001, + 38.94318747360675, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08924" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0591929189357, + 38.91040148390385, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/06/07

Report Problem", + "NAME": "H08925" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.01695629125419, + 38.92273260929036, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 03/12/08

Report Problem", + "NAME": "H08926" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0312164383039, + 38.98469328431794, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08927" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0333204642323, + 38.98500518072252, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08928" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.03514235142791, + 38.97593048694613, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/22/07

Report Problem", + "NAME": "H08929" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07252171845182, + 38.94319165876171, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Eddy

In Service


Last Inspection Date: 06/06/07

Report Problem", + "NAME": "H08930" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92587240636306, + 38.88540878623634, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08931" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.92915987721392, + 38.88576672061623, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/08/07

Report Problem", + "NAME": "H08932" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0035278298557, + 38.82962376179835, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08933" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.04500846616315, + 38.94183439252916, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/21/07

Report Problem", + "NAME": "H08934" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98596193046112, + 38.95271650478861, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08935" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98720381084333, + 38.95368736935155, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08936" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.91083700707229, + 38.89289697790556, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 09/18/07

Report Problem", + "NAME": "H08937" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.90997247965049, + 38.893215598609096, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/07/07

Report Problem", + "NAME": "H08938" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97121428165056, + 38.928365897136516, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 07/27/07

Report Problem", + "NAME": "H08941" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97825039142175, + 38.91839795539441, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 08/30/07

Report Problem", + "NAME": "H08943" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02951468714578, + 38.88424317575938, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08944" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02877188262288, + 38.88421561528062, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08945" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97900183502773, + 38.93824158419969, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08946" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97965106878492, + 38.93913660999967, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08947" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98032172098291, + 38.939761567047796, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08948" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97540266795704, + 38.93514176655271, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/20/07

Report Problem", + "NAME": "H08949" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.97786740676564, + 38.9371988177896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Lorton

In Service


Last Inspection Date: 04/02/07

Report Problem", + "NAME": "H08950" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02992539231113, + 38.882869724926245, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08951" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.02862535635137, + 38.882834728904605, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 06/26/07

Report Problem", + "NAME": "H08952" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98373163938666, + 38.943167431929645, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 07/09/07

Report Problem", + "NAME": "H08953" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98470344318412, + 38.94375860578053, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08954" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98584257252891, + 38.944289166113776, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant

In Service


Last Inspection Date: 06/21/07

Report Problem", + "NAME": "H08955" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98955808483929, + 38.85972219720714, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, Mueller

In Service


Last Inspection Date: 10/18/06

Report Problem", + "NAME": "H08956" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98234257804742, + 38.941520236084486, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08957" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98324549005675, + 38.94237975070426, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/18/07

Report Problem", + "NAME": "H08958" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99647808241964, + 38.862930274733635, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 01/31/08

Report Problem", + "NAME": "H08960" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.9950528034839, + 38.86234025281626, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 06/04/07

Report Problem", + "NAME": "H08961" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.99695304153806, + 38.90794910679896, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, KENNEDY-K81-A/D GUAR

In Service


Last Inspection Date: 07/10/07

Report Problem", + "NAME": "H08963" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.07707916040054, + 38.96499498141065, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AM DARLING - B-84-B

In Service


Last Inspection Date: 09/14/07

Report Problem", + "NAME": "H08964" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0093148713099, + 38.87540698725855, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, CLOW - EDDY

In Service


Last Inspection Date: 07/03/07

Report Problem", + "NAME": "H08965" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.00690648325929, + 38.8324328369647, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, AP Smith

In Service


Last Inspection Date: 06/19/07

Report Problem", + "NAME": "H08966" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -76.98819752280579, + 38.9257094658146, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, MUELLER-SUP CENT 250

In Service


Last Inspection Date: 07/17/07

Report Problem", + "NAME": "H08967" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.05389484528261, + 38.9234737236897, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 09/11/07

Report Problem", + "NAME": "H08968" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + -77.0533673443786, + 38.92334425495122, + 0.0 + ], + "type": "Point" + }, + "properties": { + "DESCRIPTIO": "Hydrant, American Darling

In Service


Last Inspection Date: 01/08/07

Report Problem", + "NAME": "H08969" + }, + "type": "Feature" + } + ], + "type": "FeatureCollection" +} diff --git a/ios/app/polyline.geojson b/ios/app/polyline.geojson new file mode 100644 index 000000000..c10496954 --- /dev/null +++ b/ios/app/polyline.geojson @@ -0,0 +1,14187 @@ +{ + "features": [ + { + "geometry": { + "coordinates": [ + [ + -122.854957, + 48.65588, + 109.7 + ], + [ + -122.854644, + 48.656217, + 112 + ], + [ + -122.855082, + 48.656155, + 111.1 + ], + [ + -122.855053, + 48.656188, + 111.4 + ], + [ + -122.854857, + 48.656198, + 111.6 + ], + [ + -122.854893, + 48.65629, + 111.8 + ], + [ + -122.855026, + 48.656349, + 111.9 + ], + [ + -122.855035, + 48.656411, + 112.1 + ], + [ + -122.855044, + 48.656437, + 112.1 + ], + [ + -122.855006, + 48.656472, + 112.6 + ], + [ + -122.85496, + 48.656508, + 112.8 + ], + [ + -122.854941, + 48.656534, + 112.9 + ], + [ + -122.854921, + 48.656575, + 113.5 + ], + [ + -122.854914, + 48.656603, + 114 + ], + [ + -122.854894, + 48.656628, + 114.5 + ], + [ + -122.854864, + 48.656659, + 114.8 + ], + [ + -122.854851, + 48.656687, + 115.2 + ], + [ + -122.854818, + 48.656718, + 115.5 + ], + [ + -122.8548, + 48.656757, + 115.3 + ], + [ + -122.85479, + 48.656783, + 115.3 + ], + [ + -122.854761, + 48.65682, + 115.5 + ], + [ + -122.854771, + 48.656851, + 115.8 + ], + [ + -122.854781, + 48.656886, + 116 + ], + [ + -122.854793, + 48.656921, + 115.9 + ], + [ + -122.854785, + 48.656954, + 115.8 + ], + [ + -122.854756, + 48.656977, + 116 + ], + [ + -122.854729, + 48.657002, + 116.1 + ], + [ + -122.85476, + 48.657038, + 118.3 + ], + [ + -122.854757, + 48.657067, + 118.5 + ], + [ + -122.854744, + 48.657097, + 118.3 + ], + [ + -122.854728, + 48.657127, + 118.6 + ], + [ + -122.854678, + 48.657135, + 117.1 + ], + [ + -122.85466, + 48.657169, + 117.5 + ], + [ + -122.854659, + 48.657203, + 117.8 + ], + [ + -122.854645, + 48.65724, + 118.2 + ], + [ + -122.854624, + 48.657282, + 118.6 + ], + [ + -122.854608, + 48.657312, + 118.8 + ], + [ + -122.854615, + 48.65735, + 119.8 + ], + [ + -122.854626, + 48.657377, + 120.8 + ], + [ + -122.854614, + 48.65741, + 120.9 + ], + [ + -122.854655, + 48.657389, + 122 + ], + [ + -122.854702, + 48.657391, + 123 + ], + [ + -122.854656, + 48.65738, + 121.9 + ], + [ + -122.854625, + 48.657402, + 121.2 + ], + [ + -122.854599, + 48.657438, + 121 + ], + [ + -122.854575, + 48.657468, + 120.9 + ], + [ + -122.854586, + 48.6575, + 121.7 + ], + [ + -122.854573, + 48.657532, + 121.9 + ], + [ + -122.854553, + 48.657569, + 122.1 + ], + [ + -122.854549, + 48.657605, + 122.4 + ], + [ + -122.854553, + 48.657636, + 123.5 + ], + [ + -122.854566, + 48.657665, + 124.7 + ], + [ + -122.854564, + 48.657693, + 125.2 + ], + [ + -122.854574, + 48.65772, + 125.9 + ], + [ + -122.854596, + 48.657747, + 126.8 + ], + [ + -122.854619, + 48.657778, + 127.4 + ], + [ + -122.854629, + 48.657807, + 127.1 + ], + [ + -122.854644, + 48.657844, + 126.7 + ], + [ + -122.854705, + 48.657861, + 128.4 + ], + [ + -122.854746, + 48.657866, + 130.3 + ], + [ + -122.854782, + 48.657897, + 131.8 + ], + [ + -122.854748, + 48.657939, + 130.5 + ], + [ + -122.854719, + 48.657958, + 129.3 + ], + [ + -122.854663, + 48.657967, + 127.8 + ], + [ + -122.854614, + 48.657967, + 128.7 + ], + [ + -122.854561, + 48.657965, + 129.5 + ], + [ + -122.8545, + 48.657953, + 131 + ], + [ + -122.854442, + 48.657947, + 133.6 + ], + [ + -122.854399, + 48.657927, + 133.8 + ], + [ + -122.854351, + 48.657929, + 135.8 + ], + [ + -122.854319, + 48.657894, + 134.8 + ], + [ + -122.854311, + 48.657866, + 133.6 + ], + [ + -122.85436, + 48.657873, + 131.5 + ], + [ + -122.854398, + 48.657886, + 130.6 + ], + [ + -122.85445, + 48.657883, + 128.6 + ], + [ + -122.854501, + 48.657883, + 127.2 + ], + [ + -122.854549, + 48.657885, + 126.7 + ], + [ + -122.854596, + 48.657899, + 127 + ], + [ + -122.854612, + 48.657924, + 127.7 + ], + [ + -122.854566, + 48.657937, + 128.4 + ], + [ + -122.854518, + 48.657934, + 129.2 + ], + [ + -122.854459, + 48.657926, + 131.1 + ], + [ + -122.854414, + 48.657951, + 135.1 + ], + [ + -122.854391, + 48.657973, + 137.1 + ], + [ + -122.854357, + 48.657953, + 137.2 + ], + [ + -122.854336, + 48.657927, + 136.3 + ], + [ + -122.854322, + 48.657902, + 135.1 + ], + [ + -122.854295, + 48.657878, + 135.1 + ], + [ + -122.854265, + 48.657854, + 135.4 + ], + [ + -122.854233, + 48.657833, + 136 + ], + [ + -122.854211, + 48.657799, + 135.6 + ], + [ + -122.854204, + 48.657753, + 133.7 + ], + [ + -122.854204, + 48.657721, + 132.3 + ], + [ + -122.854213, + 48.657685, + 130.6 + ], + [ + -122.854213, + 48.657653, + 128.7 + ], + [ + -122.854215, + 48.657618, + 126.6 + ], + [ + -122.854211, + 48.657579, + 125.5 + ], + [ + -122.85424, + 48.657534, + 124.2 + ], + [ + -122.854264, + 48.657511, + 123.6 + ], + [ + -122.854329, + 48.657491, + 122.6 + ], + [ + -122.854387, + 48.657489, + 121.6 + ], + [ + -122.854441, + 48.657494, + 121.3 + ], + [ + -122.854483, + 48.65749, + 120.8 + ], + [ + -122.854521, + 48.657469, + 120.1 + ], + [ + -122.854565, + 48.657463, + 120.5 + ], + [ + -122.854604, + 48.657453, + 121.5 + ], + [ + -122.85465, + 48.657446, + 122.7 + ], + [ + -122.854692, + 48.657445, + 123.5 + ], + [ + -122.854738, + 48.657442, + 124.3 + ], + [ + -122.854789, + 48.657438, + 125.2 + ], + [ + -122.854844, + 48.657429, + 126.4 + ], + [ + -122.854892, + 48.657419, + 127.5 + ], + [ + -122.854897, + 48.657457, + 128.4 + ], + [ + -122.854882, + 48.657491, + 128.6 + ], + [ + -122.854876, + 48.657518, + 129 + ], + [ + -122.854868, + 48.657545, + 129.7 + ], + [ + -122.854823, + 48.657551, + 129.1 + ], + [ + -122.854782, + 48.657556, + 128.5 + ], + [ + -122.854742, + 48.657548, + 127.5 + ], + [ + -122.854698, + 48.657553, + 126 + ], + [ + -122.854671, + 48.657574, + 125.6 + ], + [ + -122.854626, + 48.657578, + 124.2 + ], + [ + -122.854576, + 48.657564, + 122.5 + ], + [ + -122.854541, + 48.657584, + 122.1 + ], + [ + -122.854527, + 48.657612, + 121.9 + ], + [ + -122.85453, + 48.65764, + 122.8 + ], + [ + -122.854536, + 48.657667, + 123.9 + ], + [ + -122.85453, + 48.657695, + 124.4 + ], + [ + -122.854524, + 48.657731, + 124.8 + ], + [ + -122.854507, + 48.657758, + 124.6 + ], + [ + -122.854521, + 48.657784, + 124.9 + ], + [ + -122.854567, + 48.657808, + 125.6 + ], + [ + -122.854579, + 48.657834, + 125.7 + ], + [ + -122.854606, + 48.657856, + 126.2 + ], + [ + -122.854639, + 48.657877, + 126.7 + ], + [ + -122.854635, + 48.657909, + 127.3 + ], + [ + -122.854656, + 48.657935, + 127.6 + ], + [ + -122.854642, + 48.657961, + 127.8 + ], + [ + -122.854606, + 48.657986, + 129.2 + ], + [ + -122.854564, + 48.657977, + 129.8 + ], + [ + -122.854521, + 48.657963, + 130.7 + ], + [ + -122.854471, + 48.657959, + 132.8 + ], + [ + -122.854437, + 48.657939, + 133.2 + ], + [ + -122.854391, + 48.657924, + 133.9 + ], + [ + -122.854343, + 48.657935, + 136.6 + ], + [ + -122.854301, + 48.657928, + 137.7 + ], + [ + -122.854273, + 48.657903, + 137.6 + ], + [ + -122.854247, + 48.657882, + 137.7 + ], + [ + -122.854212, + 48.657865, + 138.2 + ], + [ + -122.854175, + 48.657851, + 138.7 + ], + [ + -122.854124, + 48.657832, + 139 + ], + [ + -122.854073, + 48.657828, + 139.9 + ], + [ + -122.854029, + 48.657824, + 140.6 + ], + [ + -122.853978, + 48.65783, + 141.8 + ], + [ + -122.853925, + 48.65783, + 142.6 + ], + [ + -122.853915, + 48.657795, + 141.2 + ], + [ + -122.853873, + 48.657801, + 141.7 + ], + [ + -122.853813, + 48.657794, + 142.4 + ], + [ + -122.853778, + 48.657774, + 142.3 + ], + [ + -122.853747, + 48.657755, + 142.3 + ], + [ + -122.853733, + 48.65773, + 142 + ], + [ + -122.853731, + 48.657693, + 141.9 + ], + [ + -122.853729, + 48.657662, + 142.4 + ], + [ + -122.85373, + 48.657632, + 143.2 + ], + [ + -122.853716, + 48.6576, + 144.6 + ], + [ + -122.853683, + 48.657583, + 146.2 + ], + [ + -122.8537, + 48.657547, + 146.3 + ], + [ + -122.853714, + 48.657518, + 146.1 + ], + [ + -122.853708, + 48.657476, + 147 + ], + [ + -122.853695, + 48.657446, + 147.9 + ], + [ + -122.853696, + 48.657405, + 148.1 + ], + [ + -122.853685, + 48.657376, + 148.5 + ], + [ + -122.853683, + 48.657345, + 148.7 + ], + [ + -122.853689, + 48.657317, + 148.8 + ], + [ + -122.853712, + 48.657348, + 147.8 + ], + [ + -122.853722, + 48.657383, + 147.3 + ], + [ + -122.853741, + 48.657413, + 146.5 + ], + [ + -122.853718, + 48.657437, + 147.2 + ], + [ + -122.853711, + 48.657465, + 147.1 + ], + [ + -122.853694, + 48.65749, + 147.2 + ], + [ + -122.853679, + 48.657525, + 147.3 + ], + [ + -122.853662, + 48.65755, + 147.6 + ], + [ + -122.853641, + 48.657575, + 147.7 + ], + [ + -122.853627, + 48.657609, + 147.2 + ], + [ + -122.853616, + 48.657638, + 147.1 + ], + [ + -122.853609, + 48.657665, + 147.1 + ], + [ + -122.853596, + 48.657699, + 147.3 + ], + [ + -122.853583, + 48.657727, + 147.6 + ], + [ + -122.853581, + 48.657755, + 147.6 + ], + [ + -122.853564, + 48.657788, + 148.3 + ], + [ + -122.853534, + 48.657817, + 149.5 + ], + [ + -122.853507, + 48.657852, + 150.8 + ], + [ + -122.853487, + 48.657878, + 151.7 + ], + [ + -122.853509, + 48.657905, + 152.2 + ], + [ + -122.853491, + 48.657943, + 153.5 + ], + [ + -122.853466, + 48.657965, + 154.5 + ], + [ + -122.853431, + 48.657998, + 156.1 + ], + [ + -122.853394, + 48.658018, + 157.2 + ], + [ + -122.853352, + 48.658037, + 158.2 + ], + [ + -122.853329, + 48.658071, + 159.3 + ], + [ + -122.853281, + 48.65809, + 160.5 + ], + [ + -122.853233, + 48.658104, + 161.6 + ], + [ + -122.853197, + 48.65812, + 162.3 + ], + [ + -122.853156, + 48.658147, + 163.4 + ], + [ + -122.853105, + 48.658157, + 164.1 + ], + [ + -122.853048, + 48.658166, + 164.6 + ], + [ + -122.852982, + 48.658164, + 164.7 + ], + [ + -122.852922, + 48.658163, + 164.7 + ], + [ + -122.852872, + 48.658166, + 164.8 + ], + [ + -122.852826, + 48.658174, + 164.9 + ], + [ + -122.85278, + 48.658167, + 165 + ], + [ + -122.852731, + 48.658151, + 165.3 + ], + [ + -122.852676, + 48.65815, + 166 + ], + [ + -122.852634, + 48.658148, + 166.5 + ], + [ + -122.852583, + 48.658141, + 166.8 + ], + [ + -122.852546, + 48.658157, + 167.2 + ], + [ + -122.852544, + 48.658188, + 167.4 + ], + [ + -122.852546, + 48.658219, + 167.4 + ], + [ + -122.852527, + 48.658247, + 168.2 + ], + [ + -122.852499, + 48.658271, + 169.5 + ], + [ + -122.852473, + 48.658293, + 170.6 + ], + [ + -122.852454, + 48.658323, + 172.1 + ], + [ + -122.852458, + 48.658351, + 173.8 + ], + [ + -122.852474, + 48.658384, + 175.8 + ], + [ + -122.852505, + 48.658402, + 177 + ], + [ + -122.852551, + 48.658421, + 178.8 + ], + [ + -122.852595, + 48.658431, + 179.5 + ], + [ + -122.852638, + 48.658444, + 180.1 + ], + [ + -122.852686, + 48.658455, + 180.4 + ], + [ + -122.852733, + 48.658475, + 181.1 + ], + [ + -122.852794, + 48.65848, + 180.7 + ], + [ + -122.852855, + 48.658502, + 180.7 + ], + [ + -122.852898, + 48.658525, + 181 + ], + [ + -122.852946, + 48.658553, + 181.3 + ], + [ + -122.852983, + 48.658565, + 181 + ], + [ + -122.853026, + 48.65858, + 180.6 + ], + [ + -122.853067, + 48.658596, + 180.6 + ], + [ + -122.853112, + 48.658611, + 180.5 + ], + [ + -122.853161, + 48.658614, + 180.1 + ], + [ + -122.853204, + 48.658636, + 180.3 + ], + [ + -122.853247, + 48.658666, + 180.9 + ], + [ + -122.853277, + 48.658694, + 180.9 + ], + [ + -122.853288, + 48.658727, + 181 + ], + [ + -122.853302, + 48.658756, + 180.9 + ], + [ + -122.85331, + 48.658791, + 181 + ], + [ + -122.853301, + 48.658823, + 181.7 + ], + [ + -122.853306, + 48.658858, + 182.1 + ], + [ + -122.853309, + 48.658889, + 182.6 + ], + [ + -122.85331, + 48.658926, + 183.3 + ], + [ + -122.853312, + 48.658957, + 184.1 + ], + [ + -122.853307, + 48.658995, + 185.4 + ], + [ + -122.853309, + 48.659026, + 186.5 + ], + [ + -122.853319, + 48.659052, + 187.7 + ], + [ + -122.853341, + 48.659087, + 189.3 + ], + [ + -122.853365, + 48.65911, + 190.2 + ], + [ + -122.853411, + 48.659135, + 190.5 + ], + [ + -122.853458, + 48.659146, + 189.8 + ], + [ + -122.853496, + 48.659162, + 189.1 + ], + [ + -122.853524, + 48.65919, + 188.9 + ], + [ + -122.853574, + 48.659196, + 189 + ], + [ + -122.853617, + 48.659209, + 190 + ], + [ + -122.853655, + 48.659231, + 191.1 + ], + [ + -122.853677, + 48.659263, + 191.7 + ], + [ + -122.853713, + 48.659287, + 191.6 + ], + [ + -122.85375, + 48.65931, + 191 + ], + [ + -122.853774, + 48.65934, + 190.9 + ], + [ + -122.853735, + 48.659356, + 191.8 + ], + [ + -122.853689, + 48.659374, + 193.1 + ], + [ + -122.85365, + 48.659358, + 193.5 + ], + [ + -122.853619, + 48.659325, + 193 + ], + [ + -122.853567, + 48.659346, + 193.3 + ], + [ + -122.853609, + 48.65936, + 193.7 + ], + [ + -122.853656, + 48.659385, + 193.8 + ], + [ + -122.853705, + 48.659405, + 193.1 + ], + [ + -122.853759, + 48.659417, + 192.5 + ], + [ + -122.853805, + 48.659433, + 192.7 + ], + [ + -122.853844, + 48.65944, + 193 + ], + [ + -122.853892, + 48.659454, + 193.3 + ], + [ + -122.853945, + 48.659462, + 193.4 + ], + [ + -122.853995, + 48.659472, + 193.3 + ], + [ + -122.854035, + 48.659455, + 192.7 + ], + [ + -122.85408, + 48.659455, + 192.3 + ], + [ + -122.854126, + 48.659472, + 192.8 + ], + [ + -122.854181, + 48.659484, + 193.6 + ], + [ + -122.854221, + 48.659498, + 194.7 + ], + [ + -122.854268, + 48.659519, + 195.8 + ], + [ + -122.854317, + 48.65954, + 196.7 + ], + [ + -122.85435, + 48.659564, + 197.9 + ], + [ + -122.854375, + 48.659596, + 199.8 + ], + [ + -122.854391, + 48.659622, + 201.5 + ], + [ + -122.854425, + 48.659658, + 203.7 + ], + [ + -122.854461, + 48.659675, + 204.2 + ], + [ + -122.854503, + 48.659685, + 203 + ], + [ + -122.854567, + 48.659691, + 200.2 + ], + [ + -122.854606, + 48.659682, + 198.2 + ], + [ + -122.854617, + 48.659646, + 196.2 + ], + [ + -122.854593, + 48.659614, + 195.8 + ], + [ + -122.854579, + 48.659586, + 195.7 + ], + [ + -122.854603, + 48.659551, + 193.1 + ], + [ + -122.854656, + 48.659531, + 190.4 + ], + [ + -122.854692, + 48.659515, + 189.4 + ], + [ + -122.854741, + 48.659517, + 190.7 + ], + [ + -122.854785, + 48.659525, + 193 + ], + [ + -122.854833, + 48.659515, + 194.6 + ], + [ + -122.854864, + 48.659497, + 194.4 + ], + [ + -122.854911, + 48.6595, + 195.4 + ], + [ + -122.854954, + 48.659506, + 196.4 + ], + [ + -122.855003, + 48.659516, + 197.6 + ], + [ + -122.85505, + 48.659526, + 198.8 + ], + [ + -122.855105, + 48.659533, + 200 + ], + [ + -122.855155, + 48.659542, + 201.2 + ], + [ + -122.855208, + 48.659551, + 202.2 + ], + [ + -122.855263, + 48.659551, + 202.7 + ], + [ + -122.855321, + 48.659549, + 202.6 + ], + [ + -122.855367, + 48.659548, + 202.4 + ], + [ + -122.855431, + 48.659537, + 201.9 + ], + [ + -122.855454, + 48.659537, + 202 + ], + [ + -122.855496, + 48.659541, + 202.3 + ], + [ + -122.855548, + 48.659542, + 202.8 + ], + [ + -122.855594, + 48.659538, + 203.1 + ], + [ + -122.855644, + 48.659553, + 204.8 + ], + [ + -122.855688, + 48.659565, + 205.6 + ], + [ + -122.855732, + 48.659577, + 205.8 + ], + [ + -122.85577, + 48.659596, + 206.2 + ], + [ + -122.855804, + 48.659617, + 206.8 + ], + [ + -122.855836, + 48.659637, + 207.4 + ], + [ + -122.855884, + 48.65966, + 208.1 + ], + [ + -122.855923, + 48.659675, + 208.2 + ], + [ + -122.855963, + 48.659688, + 208.3 + ], + [ + -122.856003, + 48.659698, + 208.4 + ], + [ + -122.856054, + 48.659707, + 208.3 + ], + [ + -122.856095, + 48.659715, + 208.3 + ], + [ + -122.856136, + 48.659733, + 208.6 + ], + [ + -122.856174, + 48.659743, + 208.7 + ], + [ + -122.856224, + 48.659746, + 208.7 + ], + [ + -122.85626, + 48.659765, + 209.5 + ], + [ + -122.856293, + 48.659789, + 210.1 + ], + [ + -122.856317, + 48.659812, + 210.6 + ], + [ + -122.856342, + 48.659848, + 211.2 + ], + [ + -122.856358, + 48.659874, + 211.3 + ], + [ + -122.856375, + 48.659909, + 211.5 + ], + [ + -122.856395, + 48.659945, + 211.5 + ], + [ + -122.856411, + 48.659975, + 211.4 + ], + [ + -122.85642, + 48.660008, + 211.3 + ], + [ + -122.856421, + 48.660039, + 211 + ], + [ + -122.856416, + 48.660071, + 210.5 + ], + [ + -122.856408, + 48.660101, + 210.1 + ], + [ + -122.856396, + 48.660129, + 210.1 + ], + [ + -122.856409, + 48.660162, + 211 + ], + [ + -122.85643, + 48.660188, + 212.1 + ], + [ + -122.856468, + 48.660212, + 213.2 + ], + [ + -122.856514, + 48.660233, + 214.1 + ], + [ + -122.856553, + 48.660245, + 214.4 + ], + [ + -122.856602, + 48.660248, + 214.2 + ], + [ + -122.856637, + 48.660264, + 214.7 + ], + [ + -122.856678, + 48.660272, + 214.6 + ], + [ + -122.856677, + 48.660301, + 215.9 + ], + [ + -122.856637, + 48.660286, + 215.6 + ], + [ + -122.856633, + 48.660336, + 218.2 + ], + [ + -122.856674, + 48.660316, + 216.6 + ], + [ + -122.856632, + 48.660275, + 215.2 + ], + [ + -122.85667, + 48.660263, + 214.2 + ], + [ + -122.856691, + 48.660236, + 212.8 + ], + [ + -122.856732, + 48.660236, + 212.7 + ], + [ + -122.85679, + 48.660225, + 212.3 + ], + [ + -122.856816, + 48.660263, + 213.7 + ], + [ + -122.856844, + 48.660286, + 214.8 + ], + [ + -122.856916, + 48.66029, + 214.6 + ], + [ + -122.856916, + 48.660329, + 216.3 + ], + [ + -122.856903, + 48.660355, + 217.4 + ], + [ + -122.856861, + 48.660355, + 217.6 + ], + [ + -122.856821, + 48.660361, + 217.7 + ], + [ + -122.856762, + 48.660366, + 217.9 + ], + [ + -122.85672, + 48.660371, + 218.4 + ], + [ + -122.856749, + 48.660395, + 219.2 + ], + [ + -122.856782, + 48.660414, + 220 + ], + [ + -122.856819, + 48.660398, + 219.5 + ], + [ + -122.856868, + 48.660383, + 218.8 + ], + [ + -122.856921, + 48.660378, + 218.4 + ], + [ + -122.85688, + 48.660381, + 218.6 + ], + [ + -122.856872, + 48.660413, + 220 + ], + [ + -122.856874, + 48.660442, + 221.3 + ], + [ + -122.856897, + 48.660464, + 222.3 + ], + [ + -122.856933, + 48.660479, + 223.1 + ], + [ + -122.856935, + 48.660506, + 224.7 + ], + [ + -122.856899, + 48.660487, + 223.5 + ], + [ + -122.856849, + 48.660494, + 223.8 + ], + [ + -122.856889, + 48.660511, + 224.7 + ], + [ + -122.856929, + 48.660525, + 225.7 + ], + [ + -122.856929, + 48.660553, + 227.2 + ], + [ + -122.856971, + 48.660558, + 227.4 + ], + [ + -122.857001, + 48.660581, + 228.8 + ], + [ + -122.856981, + 48.660605, + 230.2 + ], + [ + -122.856905, + 48.660625, + 230.7 + ], + [ + -122.856843, + 48.660619, + 229.6 + ], + [ + -122.856775, + 48.660621, + 229.4 + ], + [ + -122.856732, + 48.660647, + 230.8 + ], + [ + -122.8567, + 48.660671, + 232.1 + ], + [ + -122.856668, + 48.6607, + 233.6 + ], + [ + -122.856654, + 48.660732, + 235.1 + ], + [ + -122.856617, + 48.660746, + 235.8 + ], + [ + -122.85661, + 48.660779, + 237.2 + ], + [ + -122.856628, + 48.660806, + 238.2 + ], + [ + -122.856595, + 48.660825, + 238.7 + ], + [ + -122.856547, + 48.660834, + 238.6 + ], + [ + -122.856595, + 48.660847, + 239.5 + ], + [ + -122.856605, + 48.660873, + 240.4 + ], + [ + -122.856607, + 48.660903, + 241.1 + ], + [ + -122.856638, + 48.660928, + 242.2 + ], + [ + -122.856679, + 48.660948, + 243.3 + ], + [ + -122.85671, + 48.660971, + 244.5 + ], + [ + -122.856747, + 48.660985, + 245.2 + ], + [ + -122.856794, + 48.660996, + 245.7 + ], + [ + -122.856836, + 48.660994, + 245.7 + ], + [ + -122.856871, + 48.661023, + 247.2 + ], + [ + -122.856881, + 48.66105, + 248.7 + ], + [ + -122.856876, + 48.661085, + 250.5 + ], + [ + -122.856885, + 48.661113, + 252 + ], + [ + -122.856903, + 48.661148, + 253.7 + ], + [ + -122.856855, + 48.661172, + 254.7 + ], + [ + -122.856803, + 48.661178, + 254.8 + ], + [ + -122.856765, + 48.661189, + 255 + ], + [ + -122.856746, + 48.661221, + 256.3 + ], + [ + -122.856704, + 48.661243, + 257.3 + ], + [ + -122.856662, + 48.661223, + 256 + ], + [ + -122.856659, + 48.66126, + 257.7 + ], + [ + -122.856658, + 48.661291, + 259 + ], + [ + -122.85663, + 48.661312, + 259.8 + ], + [ + -122.856593, + 48.661325, + 260.2 + ], + [ + -122.856561, + 48.661346, + 260.7 + ], + [ + -122.856541, + 48.661378, + 261.5 + ], + [ + -122.856526, + 48.661416, + 263 + ], + [ + -122.85651, + 48.661444, + 263.9 + ], + [ + -122.856474, + 48.661468, + 264.6 + ], + [ + -122.856428, + 48.661488, + 265 + ], + [ + -122.856396, + 48.661509, + 265.6 + ], + [ + -122.856388, + 48.661537, + 266.5 + ], + [ + -122.856404, + 48.661571, + 267.6 + ], + [ + -122.856384, + 48.661611, + 268.8 + ], + [ + -122.856386, + 48.661648, + 270.1 + ], + [ + -122.856346, + 48.66167, + 270.7 + ], + [ + -122.85633, + 48.6617, + 271.6 + ], + [ + -122.856343, + 48.66173, + 272.7 + ], + [ + -122.856375, + 48.661768, + 274.3 + ], + [ + -122.856332, + 48.661741, + 273.2 + ], + [ + -122.856279, + 48.661651, + 269.6 + ], + [ + -122.856255, + 48.66162, + 268.5 + ], + [ + -122.856108, + 48.661491, + 262.8 + ], + [ + -122.856162, + 48.661517, + 264.1 + ], + [ + -122.856192, + 48.661546, + 265.6 + ], + [ + -122.856245, + 48.661593, + 267.5 + ], + [ + -122.85628, + 48.661636, + 269.1 + ], + [ + -122.856306, + 48.661666, + 270.2 + ], + [ + -122.856353, + 48.661726, + 272.6 + ], + [ + -122.856302, + 48.661688, + 271 + ], + [ + -122.856354, + 48.661699, + 271.7 + ], + [ + -122.856405, + 48.661709, + 272.2 + ], + [ + -122.856437, + 48.661746, + 273.8 + ], + [ + -122.856412, + 48.661782, + 274.9 + ], + [ + -122.856369, + 48.661742, + 273.3 + ], + [ + -122.856346, + 48.661714, + 272.1 + ], + [ + -122.856325, + 48.661747, + 273.4 + ], + [ + -122.856339, + 48.661779, + 274.6 + ], + [ + -122.856356, + 48.661809, + 275.5 + ], + [ + -122.856347, + 48.661838, + 276.4 + ], + [ + -122.856334, + 48.661872, + 277.3 + ], + [ + -122.856328, + 48.661899, + 278.2 + ], + [ + -122.856348, + 48.661925, + 279.3 + ], + [ + -122.856359, + 48.661953, + 280.5 + ], + [ + -122.856333, + 48.661976, + 280.9 + ], + [ + -122.85635, + 48.662004, + 282 + ], + [ + -122.856314, + 48.662027, + 282.4 + ], + [ + -122.856306, + 48.662058, + 283.3 + ], + [ + -122.856331, + 48.66208, + 283.9 + ], + [ + -122.856333, + 48.662108, + 284.6 + ], + [ + -122.856337, + 48.662143, + 285.3 + ], + [ + -122.856354, + 48.662171, + 286 + ], + [ + -122.856387, + 48.662193, + 286.4 + ], + [ + -122.85642, + 48.662213, + 287 + ], + [ + -122.856438, + 48.662242, + 287.7 + ], + [ + -122.856463, + 48.662278, + 288.7 + ], + [ + -122.856498, + 48.662307, + 289.4 + ], + [ + -122.856512, + 48.662333, + 289.8 + ], + [ + -122.856479, + 48.66236, + 290.1 + ], + [ + -122.856444, + 48.662383, + 290.7 + ], + [ + -122.856442, + 48.662411, + 291.2 + ], + [ + -122.856463, + 48.662435, + 291.5 + ], + [ + -122.856428, + 48.66242, + 291.4 + ], + [ + -122.856397, + 48.662396, + 291.4 + ], + [ + -122.856433, + 48.66241, + 291.3 + ], + [ + -122.856462, + 48.662439, + 291.6 + ], + [ + -122.856487, + 48.662465, + 292.1 + ], + [ + -122.856506, + 48.662495, + 292.7 + ], + [ + -122.856529, + 48.662522, + 293.3 + ], + [ + -122.856533, + 48.662552, + 293.9 + ], + [ + -122.856557, + 48.662581, + 294.6 + ], + [ + -122.856585, + 48.662609, + 295.4 + ], + [ + -122.856583, + 48.662641, + 295.9 + ], + [ + -122.856583, + 48.662675, + 296.5 + ], + [ + -122.85661, + 48.6627, + 297.3 + ], + [ + -122.856643, + 48.662719, + 297.9 + ], + [ + -122.856653, + 48.662749, + 298.3 + ], + [ + -122.856631, + 48.662783, + 298.3 + ], + [ + -122.856615, + 48.662813, + 298.4 + ], + [ + -122.85659, + 48.662836, + 298.8 + ], + [ + -122.856594, + 48.662864, + 299.4 + ], + [ + -122.856611, + 48.662895, + 300 + ], + [ + -122.856652, + 48.662915, + 300.6 + ], + [ + -122.856675, + 48.662939, + 300.9 + ], + [ + -122.856688, + 48.662984, + 301.4 + ], + [ + -122.856701, + 48.663023, + 302.1 + ], + [ + -122.856713, + 48.663049, + 302.7 + ], + [ + -122.856718, + 48.663079, + 303.3 + ], + [ + -122.856741, + 48.663106, + 303.9 + ], + [ + -122.856792, + 48.663122, + 304.4 + ], + [ + -122.856815, + 48.663148, + 304.9 + ], + [ + -122.856832, + 48.663173, + 305.6 + ], + [ + -122.856848, + 48.663209, + 306.1 + ], + [ + -122.856862, + 48.663241, + 306.2 + ], + [ + -122.856893, + 48.663265, + 306.6 + ], + [ + -122.856925, + 48.663288, + 307 + ], + [ + -122.856945, + 48.66332, + 307.5 + ], + [ + -122.856973, + 48.66334, + 307.9 + ], + [ + -122.856999, + 48.663374, + 308.2 + ], + [ + -122.857012, + 48.663404, + 307.8 + ], + [ + -122.857014, + 48.663433, + 307.2 + ], + [ + -122.857009, + 48.663462, + 306.6 + ], + [ + -122.857002, + 48.663497, + 306.2 + ], + [ + -122.856983, + 48.663529, + 306 + ], + [ + -122.856951, + 48.663557, + 305.6 + ], + [ + -122.856953, + 48.663586, + 305.5 + ], + [ + -122.85698, + 48.663607, + 305.7 + ], + [ + -122.857024, + 48.663635, + 306.2 + ], + [ + -122.857044, + 48.663668, + 306.2 + ], + [ + -122.857065, + 48.663699, + 306.1 + ], + [ + -122.857076, + 48.663729, + 305.8 + ], + [ + -122.857081, + 48.663758, + 305.7 + ], + [ + -122.857079, + 48.66379, + 305.6 + ], + [ + -122.857077, + 48.663827, + 305.6 + ], + [ + -122.857071, + 48.663854, + 305.6 + ], + [ + -122.85706, + 48.663885, + 305.3 + ], + [ + -122.857081, + 48.663916, + 305.3 + ], + [ + -122.857126, + 48.663938, + 306.1 + ], + [ + -122.857135, + 48.663972, + 306.7 + ], + [ + -122.857155, + 48.664011, + 307.4 + ], + [ + -122.857151, + 48.664046, + 307.6 + ], + [ + -122.8571, + 48.664056, + 306.6 + ], + [ + -122.85706, + 48.664046, + 305.7 + ], + [ + -122.857084, + 48.664077, + 306.8 + ], + [ + -122.857107, + 48.664107, + 307.4 + ], + [ + -122.857121, + 48.664134, + 308 + ], + [ + -122.857103, + 48.664159, + 308.1 + ], + [ + -122.857067, + 48.664185, + 306.9 + ], + [ + -122.857073, + 48.664214, + 307.2 + ], + [ + -122.857011, + 48.664236, + 304.5 + ], + [ + -122.856953, + 48.66426, + 303.4 + ], + [ + -122.856929, + 48.664217, + 302.4 + ], + [ + -122.856933, + 48.664169, + 302.9 + ], + [ + -122.856948, + 48.664131, + 303.8 + ], + [ + -122.857051, + 48.66409, + 306.1 + ], + [ + -122.857144, + 48.664092, + 307.5 + ], + [ + -122.857197, + 48.664069, + 309.8 + ], + [ + -122.85729, + 48.664053, + 313.4 + ], + [ + -122.857366, + 48.664048, + 316.8 + ], + [ + -122.857342, + 48.664077, + 315.8 + ], + [ + -122.857294, + 48.664094, + 313.7 + ], + [ + -122.857182, + 48.664129, + 309.3 + ], + [ + -122.857108, + 48.66414, + 307.9 + ], + [ + -122.857061, + 48.664181, + 306.6 + ], + [ + -122.857044, + 48.664227, + 305.7 + ], + [ + -122.857089, + 48.664243, + 307.7 + ], + [ + -122.857139, + 48.664252, + 309.7 + ], + [ + -122.857114, + 48.664273, + 308.3 + ], + [ + -122.857131, + 48.664302, + 308.5 + ], + [ + -122.85711, + 48.664328, + 306.9 + ], + [ + -122.857091, + 48.664354, + 306.6 + ], + [ + -122.85709, + 48.664394, + 307.9 + ], + [ + -122.857102, + 48.664421, + 308.9 + ], + [ + -122.857116, + 48.664453, + 309.9 + ], + [ + -122.857156, + 48.664469, + 310.4 + ], + [ + -122.857194, + 48.664498, + 311.4 + ], + [ + -122.857195, + 48.664531, + 312.3 + ], + [ + -122.857179, + 48.664557, + 313.2 + ], + [ + -122.857158, + 48.664593, + 314.3 + ], + [ + -122.857148, + 48.664653, + 314.2 + ], + [ + -122.857142, + 48.664668, + 313.9 + ], + [ + -122.857108, + 48.664698, + 313.4 + ], + [ + -122.857099, + 48.664726, + 313.1 + ], + [ + -122.857091, + 48.66476, + 313.3 + ], + [ + -122.857088, + 48.664791, + 314.1 + ], + [ + -122.857109, + 48.664816, + 315.2 + ], + [ + -122.857128, + 48.664848, + 316.9 + ], + [ + -122.85714, + 48.664874, + 318.6 + ], + [ + -122.857102, + 48.66489, + 319.7 + ], + [ + -122.857112, + 48.66492, + 321.4 + ], + [ + -122.857103, + 48.664948, + 322.7 + ], + [ + -122.857134, + 48.664972, + 324.3 + ], + [ + -122.857153, + 48.664998, + 325.5 + ], + [ + -122.857153, + 48.665025, + 326.7 + ], + [ + -122.857131, + 48.665062, + 327.6 + ], + [ + -122.857129, + 48.665091, + 328.4 + ], + [ + -122.857127, + 48.665124, + 329.1 + ], + [ + -122.857107, + 48.665161, + 329.5 + ], + [ + -122.857133, + 48.665181, + 330.5 + ], + [ + -122.857144, + 48.665208, + 331.4 + ], + [ + -122.857155, + 48.66524, + 332.5 + ], + [ + -122.85719, + 48.665217, + 333 + ], + [ + -122.85718, + 48.665245, + 333.3 + ], + [ + -122.857158, + 48.665279, + 333.4 + ], + [ + -122.85716, + 48.665311, + 333.9 + ], + [ + -122.857167, + 48.665342, + 334.4 + ], + [ + -122.857161, + 48.665371, + 334.7 + ], + [ + -122.857152, + 48.665409, + 335.3 + ], + [ + -122.857151, + 48.665439, + 335.5 + ], + [ + -122.857149, + 48.665472, + 335.8 + ], + [ + -122.85716, + 48.665506, + 336 + ], + [ + -122.85716, + 48.665536, + 336.1 + ], + [ + -122.857154, + 48.665568, + 335.8 + ], + [ + -122.857144, + 48.665597, + 335.4 + ], + [ + -122.857162, + 48.665624, + 336.1 + ], + [ + -122.857165, + 48.665654, + 336.1 + ], + [ + -122.857167, + 48.665691, + 336 + ], + [ + -122.857189, + 48.66572, + 336.5 + ], + [ + -122.857225, + 48.665737, + 337.6 + ], + [ + -122.857258, + 48.665767, + 338.3 + ], + [ + -122.857289, + 48.665789, + 339 + ], + [ + -122.857322, + 48.665818, + 339.6 + ], + [ + -122.85735, + 48.665845, + 339.8 + ], + [ + -122.857388, + 48.665869, + 340.2 + ], + [ + -122.857434, + 48.665891, + 340.8 + ], + [ + -122.857473, + 48.66591, + 341.6 + ], + [ + -122.857511, + 48.665929, + 342.1 + ], + [ + -122.857546, + 48.66596, + 342.7 + ], + [ + -122.857581, + 48.665984, + 343.7 + ], + [ + -122.857623, + 48.665975, + 344.9 + ], + [ + -122.857665, + 48.665982, + 345.6 + ], + [ + -122.857623, + 48.665986, + 344.8 + ], + [ + -122.857577, + 48.665994, + 343.5 + ], + [ + -122.857531, + 48.666008, + 342.6 + ], + [ + -122.857602, + 48.665994, + 344.2 + ], + [ + -122.85761, + 48.665967, + 344.6 + ], + [ + -122.857623, + 48.665936, + 344.3 + ], + [ + -122.857617, + 48.665907, + 343.6 + ], + [ + -122.857604, + 48.665871, + 343.2 + ], + [ + -122.857607, + 48.66582, + 343.9 + ], + [ + -122.857598, + 48.665892, + 343.1 + ], + [ + -122.857648, + 48.665912, + 344.3 + ], + [ + -122.857698, + 48.66593, + 345.5 + ], + [ + -122.857729, + 48.665949, + 346.4 + ], + [ + -122.857758, + 48.665975, + 346.8 + ], + [ + -122.857789, + 48.665994, + 346.5 + ], + [ + -122.85784, + 48.666005, + 346.2 + ], + [ + -122.857885, + 48.666013, + 345.9 + ], + [ + -122.857931, + 48.666031, + 345.5 + ], + [ + -122.857975, + 48.666024, + 345.4 + ], + [ + -122.858023, + 48.666032, + 345 + ], + [ + -122.858054, + 48.666051, + 344.3 + ], + [ + -122.858077, + 48.666079, + 344.3 + ], + [ + -122.858102, + 48.666108, + 344.8 + ], + [ + -122.858129, + 48.666142, + 345.5 + ], + [ + -122.858158, + 48.666171, + 346.4 + ], + [ + -122.858179, + 48.666195, + 347.4 + ], + [ + -122.858194, + 48.666225, + 348.7 + ], + [ + -122.858209, + 48.66626, + 350.1 + ], + [ + -122.858211, + 48.666287, + 351.2 + ], + [ + -122.858205, + 48.666319, + 352.4 + ], + [ + -122.858217, + 48.666359, + 353.5 + ], + [ + -122.858228, + 48.666393, + 354.3 + ], + [ + -122.858224, + 48.666424, + 355.3 + ], + [ + -122.858209, + 48.666449, + 356.1 + ], + [ + -122.858217, + 48.666484, + 357.1 + ], + [ + -122.85823, + 48.666509, + 357.8 + ], + [ + -122.858239, + 48.666545, + 358.8 + ], + [ + -122.858232, + 48.666574, + 359.1 + ], + [ + -122.858236, + 48.666605, + 359.5 + ], + [ + -122.858251, + 48.666634, + 360 + ], + [ + -122.858273, + 48.666661, + 360.8 + ], + [ + -122.858285, + 48.666692, + 361.5 + ], + [ + -122.858288, + 48.666723, + 361.9 + ], + [ + -122.858291, + 48.666752, + 362.2 + ], + [ + -122.858295, + 48.666788, + 362.7 + ], + [ + -122.858304, + 48.666817, + 363.1 + ], + [ + -122.858289, + 48.66685, + 362.7 + ], + [ + -122.858271, + 48.666884, + 362.3 + ], + [ + -122.858263, + 48.66692, + 362.3 + ], + [ + -122.858258, + 48.666949, + 362.2 + ], + [ + -122.85825, + 48.666975, + 362.1 + ], + [ + -122.858245, + 48.667006, + 362.2 + ], + [ + -122.858243, + 48.667038, + 362.3 + ], + [ + -122.85822, + 48.667075, + 362.3 + ], + [ + -122.858192, + 48.667099, + 362.4 + ], + [ + -122.858133, + 48.667122, + 362.6 + ], + [ + -122.858091, + 48.667147, + 363.2 + ], + [ + -122.858051, + 48.667162, + 363.6 + ], + [ + -122.857996, + 48.667186, + 364.5 + ], + [ + -122.857961, + 48.667211, + 365.2 + ], + [ + -122.857927, + 48.667238, + 366.2 + ], + [ + -122.857876, + 48.667244, + 366.9 + ], + [ + -122.857843, + 48.667261, + 368 + ], + [ + -122.857803, + 48.667282, + 369.5 + ], + [ + -122.857762, + 48.667301, + 370.6 + ], + [ + -122.857705, + 48.667304, + 370.3 + ], + [ + -122.857648, + 48.667306, + 369.3 + ], + [ + -122.857603, + 48.667306, + 368.2 + ], + [ + -122.857555, + 48.667304, + 367 + ], + [ + -122.857512, + 48.667295, + 365.9 + ], + [ + -122.857471, + 48.667266, + 364.9 + ], + [ + -122.857433, + 48.667255, + 364.4 + ], + [ + -122.857376, + 48.667259, + 363.9 + ], + [ + -122.857316, + 48.667269, + 363.6 + ], + [ + -122.857267, + 48.667277, + 363.5 + ], + [ + -122.857213, + 48.667279, + 363.3 + ], + [ + -122.857171, + 48.667288, + 363.4 + ], + [ + -122.857138, + 48.667305, + 363.5 + ], + [ + -122.857126, + 48.667336, + 364.1 + ], + [ + -122.857145, + 48.667367, + 365.1 + ], + [ + -122.857153, + 48.667396, + 366.1 + ], + [ + -122.857154, + 48.667425, + 366.9 + ], + [ + -122.857137, + 48.667452, + 367 + ], + [ + -122.857094, + 48.667469, + 366.1 + ], + [ + -122.857138, + 48.667509, + 367.7 + ], + [ + -122.857192, + 48.66754, + 369.3 + ], + [ + -122.857165, + 48.667564, + 368.7 + ], + [ + -122.857133, + 48.667589, + 368 + ], + [ + -122.857101, + 48.667609, + 367.9 + ], + [ + -122.857092, + 48.667637, + 368.8 + ], + [ + -122.857071, + 48.667664, + 370.2 + ], + [ + -122.85707, + 48.667692, + 371.1 + ], + [ + -122.85707, + 48.667722, + 372.4 + ], + [ + -122.857062, + 48.667754, + 373.9 + ], + [ + -122.856994, + 48.667758, + 375.8 + ], + [ + -122.85698, + 48.667793, + 377.7 + ], + [ + -122.856984, + 48.667817, + 378.7 + ], + [ + -122.85702, + 48.667839, + 378.6 + ], + [ + -122.857036, + 48.667867, + 379.6 + ], + [ + -122.857028, + 48.6679, + 381.5 + ], + [ + -122.857046, + 48.667924, + 382.1 + ], + [ + -122.857078, + 48.667945, + 382.3 + ], + [ + -122.857124, + 48.667952, + 381.6 + ], + [ + -122.857134, + 48.667981, + 382.7 + ], + [ + -122.857143, + 48.668011, + 383.7 + ], + [ + -122.857109, + 48.668033, + 385.5 + ], + [ + -122.8571, + 48.668066, + 387 + ], + [ + -122.857083, + 48.668105, + 389.5 + ], + [ + -122.857101, + 48.668136, + 390.3 + ], + [ + -122.857117, + 48.668162, + 391.1 + ], + [ + -122.857123, + 48.668194, + 392.6 + ], + [ + -122.857085, + 48.668223, + 394.7 + ], + [ + -122.857071, + 48.668249, + 395.5 + ], + [ + -122.857069, + 48.66828, + 396.3 + ], + [ + -122.857075, + 48.668311, + 397.1 + ], + [ + -122.857061, + 48.668337, + 396.9 + ], + [ + -122.857048, + 48.668368, + 396.8 + ], + [ + -122.857063, + 48.668402, + 397.4 + ], + [ + -122.857085, + 48.668437, + 398 + ], + [ + -122.857088, + 48.668474, + 398 + ], + [ + -122.857072, + 48.6685, + 398.3 + ], + [ + -122.857073, + 48.668528, + 398.7 + ], + [ + -122.85709, + 48.668561, + 399.4 + ], + [ + -122.857104, + 48.668588, + 400 + ], + [ + -122.857113, + 48.668619, + 400.5 + ], + [ + -122.857122, + 48.668646, + 400.8 + ], + [ + -122.857133, + 48.668676, + 401.1 + ], + [ + -122.857136, + 48.668706, + 401.5 + ], + [ + -122.857151, + 48.668731, + 401.7 + ], + [ + -122.857133, + 48.668764, + 402.3 + ], + [ + -122.857142, + 48.668798, + 402.4 + ], + [ + -122.857138, + 48.668829, + 402.2 + ], + [ + -122.857153, + 48.668869, + 401.4 + ], + [ + -122.85715, + 48.668902, + 400.5 + ], + [ + -122.857148, + 48.668942, + 399.8 + ], + [ + -122.857128, + 48.668976, + 399.7 + ], + [ + -122.857109, + 48.669008, + 399.7 + ], + [ + -122.857096, + 48.669036, + 399.6 + ], + [ + -122.85712, + 48.669062, + 399.1 + ], + [ + -122.857137, + 48.669089, + 399.2 + ], + [ + -122.857144, + 48.669122, + 399.7 + ], + [ + -122.857132, + 48.669152, + 400.3 + ], + [ + -122.857127, + 48.669193, + 401.2 + ], + [ + -122.857128, + 48.669223, + 402.1 + ], + [ + -122.857126, + 48.669252, + 403 + ], + [ + -122.857147, + 48.669276, + 403.7 + ], + [ + -122.857141, + 48.669305, + 403.9 + ], + [ + -122.857136, + 48.669337, + 404 + ], + [ + -122.857147, + 48.669363, + 404.7 + ], + [ + -122.857166, + 48.66939, + 405.7 + ], + [ + -122.857153, + 48.669417, + 406.3 + ], + [ + -122.857153, + 48.669445, + 407 + ], + [ + -122.857178, + 48.669474, + 408.2 + ], + [ + -122.857187, + 48.669505, + 408.7 + ], + [ + -122.857198, + 48.669531, + 409 + ], + [ + -122.857224, + 48.669559, + 409.6 + ], + [ + -122.8572, + 48.669589, + 409.4 + ], + [ + -122.857197, + 48.66963, + 410.1 + ], + [ + -122.857188, + 48.669662, + 410.8 + ], + [ + -122.85717, + 48.669692, + 411.5 + ], + [ + -122.857187, + 48.669726, + 412.8 + ], + [ + -122.857168, + 48.669754, + 413.9 + ], + [ + -122.85716, + 48.669798, + 415.2 + ], + [ + -122.857136, + 48.669831, + 416.7 + ], + [ + -122.85708, + 48.669879, + 418.2 + ], + [ + -122.857069, + 48.669911, + 419.4 + ], + [ + -122.857044, + 48.669942, + 420.6 + ], + [ + -122.857082, + 48.66992, + 419.9 + ], + [ + -122.857112, + 48.669901, + 419 + ], + [ + -122.857159, + 48.669905, + 419.4 + ], + [ + -122.857209, + 48.669909, + 419.8 + ], + [ + -122.857249, + 48.669926, + 420.3 + ], + [ + -122.85728, + 48.669949, + 420.9 + ], + [ + -122.857327, + 48.669975, + 421.4 + ], + [ + -122.857381, + 48.670008, + 422.1 + ], + [ + -122.857398, + 48.670024, + 422.7 + ], + [ + -122.857414, + 48.670041, + 423.6 + ], + [ + -122.85743, + 48.670057, + 424.3 + ], + [ + -122.857447, + 48.670074, + 425 + ], + [ + -122.857463, + 48.67009, + 425.7 + ], + [ + -122.857479, + 48.670107, + 426.5 + ], + [ + -122.857496, + 48.670123, + 427.5 + ], + [ + -122.857512, + 48.67014, + 428.4 + ], + [ + -122.857528, + 48.670156, + 429.3 + ], + [ + -122.857545, + 48.670173, + 430.2 + ], + [ + -122.857561, + 48.670189, + 430.9 + ], + [ + -122.857577, + 48.670206, + 431.7 + ], + [ + -122.857594, + 48.670223, + 432.4 + ], + [ + -122.85757, + 48.670254, + 434 + ], + [ + -122.857611, + 48.670229, + 432.7 + ], + [ + -122.857654, + 48.670226, + 432.4 + ], + [ + -122.857697, + 48.670246, + 433.5 + ], + [ + -122.857693, + 48.670277, + 435 + ], + [ + -122.857717, + 48.670245, + 433.4 + ], + [ + -122.857769, + 48.670237, + 432.9 + ], + [ + -122.857817, + 48.670232, + 433.1 + ], + [ + -122.857857, + 48.670241, + 433.6 + ], + [ + -122.857886, + 48.67027, + 435.2 + ], + [ + -122.85791, + 48.670296, + 436.5 + ], + [ + -122.857904, + 48.670324, + 437.7 + ], + [ + -122.857863, + 48.670351, + 438.3 + ], + [ + -122.857853, + 48.67038, + 439.4 + ], + [ + -122.857862, + 48.670414, + 440.9 + ], + [ + -122.857847, + 48.670443, + 442.2 + ], + [ + -122.857829, + 48.670469, + 443.2 + ], + [ + -122.857814, + 48.670504, + 444.6 + ], + [ + -122.857846, + 48.670528, + 445.5 + ], + [ + -122.857884, + 48.670561, + 446.7 + ], + [ + -122.857884, + 48.670533, + 445.7 + ], + [ + -122.857845, + 48.670545, + 446.2 + ], + [ + -122.857812, + 48.670564, + 446.8 + ], + [ + -122.857814, + 48.670591, + 447.8 + ], + [ + -122.857796, + 48.670622, + 448.9 + ], + [ + -122.857774, + 48.670645, + 449.9 + ], + [ + -122.857747, + 48.670676, + 451 + ], + [ + -122.857719, + 48.670703, + 451.8 + ], + [ + -122.857687, + 48.670728, + 452.5 + ], + [ + -122.857737, + 48.670734, + 452.7 + ], + [ + -122.857735, + 48.670765, + 453.8 + ], + [ + -122.857701, + 48.670788, + 454.6 + ], + [ + -122.857624, + 48.670777, + 453.7 + ], + [ + -122.857588, + 48.670762, + 452.7 + ], + [ + -122.857524, + 48.67079, + 452.5 + ], + [ + -122.857505, + 48.670761, + 451.5 + ], + [ + -122.857452, + 48.670767, + 450.7 + ], + [ + -122.8574, + 48.670755, + 450.2 + ], + [ + -122.857445, + 48.670748, + 450.5 + ], + [ + -122.857483, + 48.670759, + 451.1 + ], + [ + -122.857484, + 48.670793, + 451.7 + ], + [ + -122.857452, + 48.670811, + 451.2 + ], + [ + -122.857431, + 48.670838, + 451 + ], + [ + -122.85741, + 48.670867, + 451.2 + ], + [ + -122.857366, + 48.670887, + 452.6 + ], + [ + -122.857326, + 48.670904, + 454.2 + ], + [ + -122.857271, + 48.670907, + 454.8 + ], + [ + -122.857217, + 48.670924, + 455.6 + ], + [ + -122.857186, + 48.670949, + 456.5 + ], + [ + -122.857162, + 48.670972, + 457.1 + ], + [ + -122.85716, + 48.671001, + 458.1 + ], + [ + -122.857168, + 48.67103, + 459.3 + ], + [ + -122.857172, + 48.671063, + 460.5 + ], + [ + -122.857174, + 48.671093, + 461.5 + ], + [ + -122.857144, + 48.671119, + 461.9 + ], + [ + -122.85711, + 48.671061, + 459.6 + ], + [ + -122.857104, + 48.67103, + 458.4 + ], + [ + -122.857112, + 48.671064, + 459.7 + ], + [ + -122.857135, + 48.671095, + 461 + ], + [ + -122.857147, + 48.671126, + 462.2 + ], + [ + -122.857125, + 48.6711, + 461 + ], + [ + -122.857155, + 48.671125, + 462.3 + ], + [ + -122.857146, + 48.671166, + 463.3 + ], + [ + -122.857119, + 48.671186, + 463.4 + ], + [ + -122.857101, + 48.671219, + 464 + ], + [ + -122.857107, + 48.671251, + 464.9 + ], + [ + -122.857114, + 48.671283, + 465.9 + ], + [ + -122.857116, + 48.671316, + 466.7 + ], + [ + -122.857131, + 48.671344, + 467.7 + ], + [ + -122.857156, + 48.671368, + 468.6 + ], + [ + -122.857165, + 48.671395, + 469.4 + ], + [ + -122.85718, + 48.671426, + 470.3 + ], + [ + -122.857195, + 48.671454, + 471 + ], + [ + -122.857204, + 48.671483, + 471.6 + ], + [ + -122.857215, + 48.671514, + 472.1 + ], + [ + -122.857259, + 48.671523, + 471.9 + ], + [ + -122.85729, + 48.671542, + 472 + ], + [ + -122.857304, + 48.671571, + 472.6 + ], + [ + -122.857336, + 48.671602, + 473.4 + ], + [ + -122.857355, + 48.671628, + 474.4 + ], + [ + -122.85736, + 48.671662, + 475.5 + ], + [ + -122.85738, + 48.671691, + 476.3 + ], + [ + -122.857409, + 48.671711, + 476.6 + ], + [ + -122.85739, + 48.671739, + 477.5 + ], + [ + -122.857355, + 48.671768, + 477.8 + ], + [ + -122.85735, + 48.671807, + 477.5 + ], + [ + -122.857349, + 48.671834, + 477 + ], + [ + -122.857357, + 48.671867, + 476.7 + ], + [ + -122.857363, + 48.671899, + 477.7 + ], + [ + -122.857331, + 48.671935, + 479.9 + ], + [ + -122.857314, + 48.67196, + 481.9 + ], + [ + -122.857308, + 48.671988, + 482.8 + ], + [ + -122.857299, + 48.672021, + 483.6 + ], + [ + -122.857305, + 48.672049, + 483.9 + ], + [ + -122.857247, + 48.672077, + 484.8 + ], + [ + -122.857214, + 48.672094, + 485.3 + ], + [ + -122.857198, + 48.672133, + 486.4 + ], + [ + -122.857199, + 48.672172, + 487.7 + ], + [ + -122.857211, + 48.672201, + 488.7 + ], + [ + -122.857226, + 48.672226, + 489.7 + ], + [ + -122.857255, + 48.672245, + 490.4 + ], + [ + -122.85722, + 48.672267, + 491.4 + ], + [ + -122.857196, + 48.672296, + 492.3 + ], + [ + -122.857175, + 48.672323, + 492.5 + ], + [ + -122.857151, + 48.672346, + 492.6 + ], + [ + -122.85717, + 48.67237, + 493.4 + ], + [ + -122.857214, + 48.672393, + 494.7 + ], + [ + -122.857173, + 48.672417, + 494.5 + ], + [ + -122.857126, + 48.672399, + 493.5 + ], + [ + -122.857044, + 48.672385, + 494.9 + ], + [ + -122.856999, + 48.67238, + 495.8 + ], + [ + -122.857056, + 48.672377, + 494.4 + ], + [ + -122.857099, + 48.672379, + 493.2 + ], + [ + -122.857156, + 48.672384, + 493.4 + ], + [ + -122.857173, + 48.672417, + 494.5 + ], + [ + -122.85716, + 48.672474, + 495.6 + ], + [ + -122.857204, + 48.672415, + 495.1 + ], + [ + -122.857196, + 48.672384, + 494.2 + ], + [ + -122.857257, + 48.672389, + 495 + ], + [ + -122.857185, + 48.672366, + 493.6 + ], + [ + -122.857194, + 48.672409, + 494.8 + ], + [ + -122.857186, + 48.672438, + 495.3 + ], + [ + -122.857193, + 48.672467, + 496.2 + ], + [ + -122.857191, + 48.672499, + 497 + ], + [ + -122.857155, + 48.672515, + 496.6 + ], + [ + -122.857136, + 48.672548, + 497.2 + ], + [ + -122.857122, + 48.672573, + 497.7 + ], + [ + -122.857117, + 48.672615, + 498.8 + ], + [ + -122.857138, + 48.672654, + 500.3 + ], + [ + -122.857153, + 48.672687, + 501.4 + ], + [ + -122.857166, + 48.672721, + 502.4 + ], + [ + -122.857169, + 48.672753, + 503.1 + ], + [ + -122.857165, + 48.672788, + 503.8 + ], + [ + -122.857165, + 48.672825, + 504.6 + ], + [ + -122.857171, + 48.672859, + 505.2 + ], + [ + -122.857187, + 48.672886, + 505.6 + ], + [ + -122.85719, + 48.672921, + 506.1 + ], + [ + -122.857191, + 48.672954, + 506.6 + ], + [ + -122.857198, + 48.672985, + 507 + ], + [ + -122.857205, + 48.673013, + 507.1 + ], + [ + -122.857218, + 48.673044, + 506.9 + ], + [ + -122.857219, + 48.673075, + 506.6 + ], + [ + -122.857207, + 48.673108, + 506.1 + ], + [ + -122.857205, + 48.673151, + 506.3 + ], + [ + -122.857205, + 48.673184, + 506.7 + ], + [ + -122.857217, + 48.673217, + 507.5 + ], + [ + -122.857222, + 48.673251, + 508.1 + ], + [ + -122.857215, + 48.67329, + 508.5 + ], + [ + -122.857212, + 48.673321, + 508.8 + ], + [ + -122.857213, + 48.673358, + 509.1 + ], + [ + -122.857212, + 48.67339, + 509.3 + ], + [ + -122.857211, + 48.673423, + 509.7 + ], + [ + -122.857205, + 48.673457, + 510.4 + ], + [ + -122.857214, + 48.673486, + 510.7 + ], + [ + -122.857247, + 48.673509, + 510.3 + ], + [ + -122.857279, + 48.673535, + 509.9 + ], + [ + -122.857306, + 48.673559, + 509.5 + ], + [ + -122.857334, + 48.673586, + 509.2 + ], + [ + -122.857354, + 48.673623, + 509.3 + ], + [ + -122.857371, + 48.67365, + 509.4 + ], + [ + -122.857405, + 48.673665, + 509.3 + ], + [ + -122.857449, + 48.673676, + 509.3 + ], + [ + -122.857472, + 48.673704, + 509.6 + ], + [ + -122.857507, + 48.673719, + 509.7 + ], + [ + -122.857547, + 48.673708, + 509.4 + ], + [ + -122.857494, + 48.673718, + 509.7 + ], + [ + -122.857441, + 48.673737, + 509.9 + ], + [ + -122.857487, + 48.673757, + 509.6 + ], + [ + -122.857514, + 48.673783, + 509.2 + ], + [ + -122.857557, + 48.673784, + 509.1 + ], + [ + -122.857606, + 48.673782, + 508.8 + ], + [ + -122.857655, + 48.673792, + 507.4 + ], + [ + -122.857711, + 48.673803, + 508.9 + ], + [ + -122.857748, + 48.673817, + 510.4 + ], + [ + -122.857789, + 48.673827, + 511.1 + ], + [ + -122.857805, + 48.673854, + 512 + ], + [ + -122.857823, + 48.673889, + 513.2 + ], + [ + -122.857857, + 48.673911, + 514.3 + ], + [ + -122.857886, + 48.673942, + 515.6 + ], + [ + -122.857897, + 48.673973, + 516.9 + ], + [ + -122.857884, + 48.674005, + 518 + ], + [ + -122.857938, + 48.674018, + 518.8 + ], + [ + -122.85796, + 48.673985, + 517.7 + ], + [ + -122.857913, + 48.673978, + 517.2 + ], + [ + -122.857926, + 48.674014, + 518.6 + ], + [ + -122.857922, + 48.674041, + 519.4 + ], + [ + -122.85792, + 48.674076, + 520.4 + ], + [ + -122.85793, + 48.67411, + 521.5 + ], + [ + -122.857929, + 48.674146, + 522.3 + ], + [ + -122.857949, + 48.674175, + 523.4 + ], + [ + -122.857983, + 48.674197, + 524.4 + ], + [ + -122.858002, + 48.674231, + 525.7 + ], + [ + -122.857985, + 48.674261, + 526.5 + ], + [ + -122.858014, + 48.674296, + 528 + ], + [ + -122.858011, + 48.67433, + 529.2 + ], + [ + -122.858002, + 48.674365, + 530.3 + ], + [ + -122.858007, + 48.674401, + 531.4 + ], + [ + -122.857967, + 48.674441, + 532.3 + ], + [ + -122.857963, + 48.674479, + 533.2 + ], + [ + -122.857943, + 48.674504, + 533.7 + ], + [ + -122.857895, + 48.674523, + 533.9 + ], + [ + -122.857881, + 48.674549, + 534.6 + ], + [ + -122.857842, + 48.674569, + 535 + ], + [ + -122.857821, + 48.674594, + 535.6 + ], + [ + -122.85778, + 48.674618, + 536.3 + ], + [ + -122.857749, + 48.674644, + 536.9 + ], + [ + -122.85775, + 48.674673, + 537.9 + ], + [ + -122.857758, + 48.674705, + 539 + ], + [ + -122.857738, + 48.674733, + 539.6 + ], + [ + -122.857758, + 48.674762, + 540.5 + ], + [ + -122.857728, + 48.674781, + 540.8 + ], + [ + -122.857707, + 48.67481, + 541.5 + ], + [ + -122.857695, + 48.674841, + 542.2 + ], + [ + -122.857673, + 48.674871, + 542.7 + ], + [ + -122.857651, + 48.674898, + 543.2 + ], + [ + -122.857619, + 48.674931, + 544 + ], + [ + -122.857594, + 48.674961, + 544.7 + ], + [ + -122.857572, + 48.674991, + 545.3 + ], + [ + -122.857549, + 48.675019, + 545.5 + ], + [ + -122.857523, + 48.675045, + 546 + ], + [ + -122.857474, + 48.67506, + 546.1 + ], + [ + -122.857434, + 48.675088, + 546.6 + ], + [ + -122.857407, + 48.675116, + 547 + ], + [ + -122.857394, + 48.675151, + 547.6 + ], + [ + -122.857369, + 48.675175, + 547.9 + ], + [ + -122.857306, + 48.675182, + 547.9 + ], + [ + -122.857266, + 48.675194, + 548.3 + ], + [ + -122.857229, + 48.675211, + 548.9 + ], + [ + -122.857207, + 48.67524, + 549.4 + ], + [ + -122.857187, + 48.675267, + 549.7 + ], + [ + -122.857171, + 48.675302, + 549.9 + ], + [ + -122.857152, + 48.675327, + 550.2 + ], + [ + -122.857131, + 48.675354, + 550.2 + ], + [ + -122.857113, + 48.675381, + 549.9 + ], + [ + -122.857099, + 48.67541, + 549.7 + ], + [ + -122.857105, + 48.675443, + 549.5 + ], + [ + -122.857108, + 48.67548, + 549.5 + ], + [ + -122.857108, + 48.675511, + 549.5 + ], + [ + -122.85715, + 48.675536, + 549.4 + ], + [ + -122.857162, + 48.675564, + 549.2 + ], + [ + -122.857175, + 48.675591, + 549 + ], + [ + -122.857175, + 48.675621, + 548.9 + ], + [ + -122.85717, + 48.675654, + 548.8 + ], + [ + -122.85718, + 48.675684, + 548.8 + ], + [ + -122.857186, + 48.675719, + 549 + ], + [ + -122.857184, + 48.675749, + 549.6 + ], + [ + -122.857184, + 48.675777, + 549.9 + ], + [ + -122.857175, + 48.675818, + 550.1 + ], + [ + -122.857168, + 48.675847, + 550.3 + ], + [ + -122.857166, + 48.675884, + 550.9 + ], + [ + -122.857171, + 48.675911, + 551.3 + ], + [ + -122.857184, + 48.675944, + 552.3 + ], + [ + -122.857204, + 48.675969, + 553 + ], + [ + -122.857217, + 48.675995, + 553.7 + ], + [ + -122.857235, + 48.676034, + 555 + ], + [ + -122.85724, + 48.676061, + 555.9 + ], + [ + -122.857261, + 48.676096, + 557.4 + ], + [ + -122.857253, + 48.676126, + 558.2 + ], + [ + -122.85726, + 48.676162, + 559.4 + ], + [ + -122.857246, + 48.676194, + 560 + ], + [ + -122.857256, + 48.676227, + 561.3 + ], + [ + -122.857253, + 48.67626, + 562.2 + ], + [ + -122.857241, + 48.676292, + 562.8 + ], + [ + -122.857218, + 48.676333, + 563.2 + ], + [ + -122.857185, + 48.676359, + 562.8 + ], + [ + -122.857149, + 48.676392, + 562.7 + ], + [ + -122.857126, + 48.676419, + 562.8 + ], + [ + -122.857092, + 48.676462, + 562.9 + ], + [ + -122.857121, + 48.676483, + 563.7 + ], + [ + -122.857153, + 48.676505, + 565.1 + ], + [ + -122.857154, + 48.67654, + 566.1 + ], + [ + -122.857141, + 48.676571, + 566.4 + ], + [ + -122.857146, + 48.676606, + 567.5 + ], + [ + -122.857151, + 48.676636, + 568.5 + ], + [ + -122.857147, + 48.676666, + 569.1 + ], + [ + -122.857149, + 48.676707, + 569.8 + ], + [ + -122.857167, + 48.676739, + 571 + ], + [ + -122.857161, + 48.676767, + 571.1 + ], + [ + -122.857155, + 48.676796, + 571.1 + ], + [ + -122.857144, + 48.676826, + 571.1 + ], + [ + -122.857131, + 48.676852, + 570.9 + ], + [ + -122.857132, + 48.676882, + 571.1 + ], + [ + -122.857136, + 48.67691, + 571.3 + ], + [ + -122.857138, + 48.676948, + 571.5 + ], + [ + -122.85714, + 48.676984, + 571.7 + ], + [ + -122.857159, + 48.677011, + 572.3 + ], + [ + -122.857194, + 48.677045, + 573.2 + ], + [ + -122.857225, + 48.677065, + 573.9 + ], + [ + -122.857249, + 48.677095, + 574.3 + ], + [ + -122.857255, + 48.677127, + 574.4 + ], + [ + -122.857255, + 48.677161, + 574.6 + ], + [ + -122.857251, + 48.677197, + 574.6 + ], + [ + -122.857244, + 48.677234, + 574.2 + ], + [ + -122.857246, + 48.677267, + 574 + ], + [ + -122.85729, + 48.677301, + 574 + ], + [ + -122.857272, + 48.677328, + 573.6 + ], + [ + -122.857235, + 48.677348, + 573.3 + ], + [ + -122.857193, + 48.677347, + 573.5 + ], + [ + -122.857147, + 48.677353, + 573.7 + ], + [ + -122.857108, + 48.677365, + 573.6 + ], + [ + -122.857058, + 48.677379, + 572.7 + ], + [ + -122.85702, + 48.677393, + 571.9 + ], + [ + -122.856984, + 48.677407, + 571.5 + ], + [ + -122.856943, + 48.677432, + 571 + ], + [ + -122.856895, + 48.677444, + 570.4 + ], + [ + -122.856845, + 48.677453, + 569.4 + ], + [ + -122.856789, + 48.677462, + 567.7 + ], + [ + -122.856745, + 48.67747, + 566.7 + ], + [ + -122.85669, + 48.677484, + 566.5 + ], + [ + -122.856647, + 48.677496, + 566.8 + ], + [ + -122.856605, + 48.677519, + 567.2 + ], + [ + -122.856584, + 48.677545, + 567.7 + ], + [ + -122.85657, + 48.677582, + 568 + ], + [ + -122.856537, + 48.677605, + 569.1 + ], + [ + -122.856494, + 48.677612, + 570.8 + ], + [ + -122.856464, + 48.677631, + 571.4 + ], + [ + -122.856423, + 48.677633, + 571.6 + ], + [ + -122.856377, + 48.677628, + 571.9 + ], + [ + -122.856327, + 48.677633, + 572.5 + ], + [ + -122.856277, + 48.677628, + 572.7 + ], + [ + -122.856227, + 48.67763, + 572.3 + ], + [ + -122.856178, + 48.677626, + 571.7 + ], + [ + -122.856134, + 48.677625, + 571.6 + ], + [ + -122.856091, + 48.677635, + 571.8 + ], + [ + -122.85605, + 48.677642, + 572.2 + ], + [ + -122.85601, + 48.677658, + 572.9 + ], + [ + -122.855959, + 48.677663, + 573.2 + ], + [ + -122.855926, + 48.677627, + 572.9 + ], + [ + -122.855888, + 48.677608, + 573.2 + ], + [ + -122.855835, + 48.677602, + 574 + ], + [ + -122.855784, + 48.67761, + 575 + ], + [ + -122.85573, + 48.677613, + 575.8 + ], + [ + -122.855673, + 48.677617, + 576.5 + ], + [ + -122.855613, + 48.677622, + 577.3 + ], + [ + -122.855555, + 48.677627, + 577.9 + ], + [ + -122.855514, + 48.677627, + 578 + ], + [ + -122.855468, + 48.677615, + 577.9 + ], + [ + -122.855426, + 48.677621, + 578.3 + ], + [ + -122.855387, + 48.677643, + 579.5 + ], + [ + -122.855359, + 48.677664, + 580.1 + ], + [ + -122.855318, + 48.677683, + 580.6 + ], + [ + -122.855264, + 48.677694, + 580.9 + ], + [ + -122.855224, + 48.677701, + 581.4 + ], + [ + -122.855172, + 48.677714, + 582.4 + ], + [ + -122.855125, + 48.677712, + 582.9 + ], + [ + -122.855086, + 48.677724, + 583.9 + ], + [ + -122.855051, + 48.677744, + 585.4 + ], + [ + -122.855005, + 48.677745, + 586.3 + ], + [ + -122.854964, + 48.677755, + 587.5 + ], + [ + -122.854929, + 48.67774, + 587.7 + ], + [ + -122.854885, + 48.67773, + 588.2 + ], + [ + -122.854832, + 48.677737, + 589.3 + ], + [ + -122.85479, + 48.677732, + 589.9 + ], + [ + -122.854753, + 48.677745, + 590.8 + ], + [ + -122.85472, + 48.677769, + 591.7 + ], + [ + -122.8547, + 48.677802, + 592.3 + ], + [ + -122.854664, + 48.677819, + 592.4 + ], + [ + -122.854624, + 48.677827, + 592.5 + ], + [ + -122.854601, + 48.677858, + 592.9 + ], + [ + -122.854592, + 48.677887, + 593.5 + ], + [ + -122.85458, + 48.677919, + 594.4 + ], + [ + -122.854573, + 48.677953, + 595.4 + ], + [ + -122.854582, + 48.677985, + 595.9 + ], + [ + -122.854568, + 48.678011, + 596.5 + ], + [ + -122.854536, + 48.678036, + 597 + ], + [ + -122.854487, + 48.678049, + 597.3 + ], + [ + -122.854443, + 48.678058, + 597.4 + ], + [ + -122.854403, + 48.678055, + 597.3 + ], + [ + -122.854363, + 48.67804, + 597.4 + ], + [ + -122.854324, + 48.678022, + 598.1 + ], + [ + -122.854284, + 48.678001, + 599.2 + ], + [ + -122.854253, + 48.677982, + 599.9 + ], + [ + -122.854219, + 48.677962, + 600.4 + ], + [ + -122.854183, + 48.677947, + 601 + ], + [ + -122.85415, + 48.677968, + 601.8 + ], + [ + -122.854089, + 48.677977, + 602.5 + ], + [ + -122.854042, + 48.677988, + 602.7 + ], + [ + -122.854005, + 48.678001, + 602.9 + ], + [ + -122.853952, + 48.678015, + 602.9 + ], + [ + -122.853909, + 48.67803, + 602.9 + ], + [ + -122.853871, + 48.678044, + 602.8 + ], + [ + -122.853828, + 48.678067, + 602.8 + ], + [ + -122.853789, + 48.678083, + 602.7 + ], + [ + -122.853766, + 48.678109, + 602.7 + ], + [ + -122.853748, + 48.678144, + 602.8 + ], + [ + -122.853729, + 48.67818, + 602.8 + ], + [ + -122.853699, + 48.67821, + 602.9 + ], + [ + -122.853691, + 48.678246, + 603.1 + ], + [ + -122.853689, + 48.678274, + 603.5 + ], + [ + -122.853673, + 48.678302, + 604.4 + ], + [ + -122.853646, + 48.678331, + 605.7 + ], + [ + -122.853621, + 48.678362, + 606.9 + ], + [ + -122.853595, + 48.678389, + 607.6 + ], + [ + -122.853568, + 48.678415, + 608 + ], + [ + -122.853527, + 48.678438, + 608.3 + ], + [ + -122.853479, + 48.678452, + 608.7 + ], + [ + -122.85344, + 48.678468, + 609.3 + ], + [ + -122.853403, + 48.678489, + 609.8 + ], + [ + -122.853369, + 48.678516, + 610.2 + ], + [ + -122.853318, + 48.678548, + 610.7 + ], + [ + -122.85329, + 48.678572, + 610.8 + ], + [ + -122.853255, + 48.678603, + 610.8 + ], + [ + -122.853233, + 48.678626, + 610.9 + ], + [ + -122.853207, + 48.678658, + 610.9 + ], + [ + -122.853192, + 48.678686, + 610.7 + ], + [ + -122.853163, + 48.678705, + 610.7 + ], + [ + -122.853133, + 48.678732, + 610.7 + ], + [ + -122.853137, + 48.678766, + 610.3 + ], + [ + -122.85313, + 48.678798, + 609.8 + ], + [ + -122.853101, + 48.678822, + 609.4 + ], + [ + -122.853063, + 48.67884, + 609.4 + ], + [ + -122.853023, + 48.678863, + 609.2 + ], + [ + -122.852996, + 48.678885, + 608.9 + ], + [ + -122.852968, + 48.678911, + 608.7 + ], + [ + -122.852952, + 48.678962, + 608.5 + ], + [ + -122.852945, + 48.678976, + 608.5 + ], + [ + -122.85292, + 48.679008, + 608.5 + ], + [ + -122.852897, + 48.679031, + 608.6 + ], + [ + -122.852865, + 48.679049, + 608.6 + ], + [ + -122.852861, + 48.679077, + 608.4 + ], + [ + -122.852839, + 48.679111, + 608.5 + ], + [ + -122.852819, + 48.67914, + 608.7 + ], + [ + -122.852795, + 48.679172, + 608.9 + ], + [ + -122.85278, + 48.679202, + 609 + ], + [ + -122.852765, + 48.679236, + 609.1 + ], + [ + -122.852755, + 48.679268, + 608.8 + ], + [ + -122.852742, + 48.679299, + 608.6 + ], + [ + -122.852724, + 48.679325, + 608.3 + ], + [ + -122.852694, + 48.679354, + 608.2 + ], + [ + -122.852684, + 48.679381, + 607.9 + ], + [ + -122.852669, + 48.679415, + 607.4 + ], + [ + -122.852647, + 48.679443, + 607.1 + ], + [ + -122.852622, + 48.679473, + 606.9 + ], + [ + -122.852602, + 48.679512, + 606.8 + ], + [ + -122.852568, + 48.67953, + 606.6 + ], + [ + -122.852532, + 48.679553, + 606.3 + ], + [ + -122.852506, + 48.679581, + 606.2 + ], + [ + -122.852472, + 48.679606, + 605.8 + ], + [ + -122.852425, + 48.679628, + 605.1 + ], + [ + -122.852403, + 48.67964, + 604.8 + ], + [ + -122.852373, + 48.679662, + 604.4 + ], + [ + -122.852351, + 48.679686, + 604 + ], + [ + -122.852318, + 48.679709, + 603.5 + ], + [ + -122.852284, + 48.679727, + 602.8 + ], + [ + -122.85224, + 48.679748, + 602 + ], + [ + -122.852198, + 48.679776, + 601.5 + ], + [ + -122.852182, + 48.679802, + 601.1 + ], + [ + -122.852156, + 48.679834, + 600.7 + ], + [ + -122.852133, + 48.679856, + 600.4 + ], + [ + -122.852098, + 48.679879, + 599.9 + ], + [ + -122.852069, + 48.679899, + 599.5 + ], + [ + -122.852023, + 48.67992, + 599.4 + ], + [ + -122.851992, + 48.679945, + 599.5 + ], + [ + -122.851964, + 48.679974, + 599.4 + ], + [ + -122.851937, + 48.680001, + 599.1 + ], + [ + -122.851913, + 48.680023, + 598.8 + ], + [ + -122.851876, + 48.680043, + 598.8 + ], + [ + -122.851831, + 48.680062, + 599 + ], + [ + -122.851789, + 48.680084, + 599.4 + ], + [ + -122.851763, + 48.680106, + 599.7 + ], + [ + -122.851719, + 48.68013, + 600.2 + ], + [ + -122.851672, + 48.680152, + 600.6 + ], + [ + -122.85163, + 48.680158, + 601 + ], + [ + -122.851631, + 48.680124, + 600.9 + ], + [ + -122.851674, + 48.680113, + 600.5 + ], + [ + -122.851678, + 48.68007, + 600.3 + ], + [ + -122.851653, + 48.680045, + 600.2 + ], + [ + -122.851588, + 48.68011, + 601.1 + ], + [ + -122.851591, + 48.680142, + 601.1 + ], + [ + -122.851546, + 48.680141, + 601.7 + ], + [ + -122.851516, + 48.680117, + 601.7 + ], + [ + -122.851523, + 48.680151, + 602.1 + ], + [ + -122.851543, + 48.680179, + 602.1 + ], + [ + -122.851516, + 48.680153, + 602.2 + ], + [ + -122.851477, + 48.68014, + 602.6 + ], + [ + -122.851464, + 48.680109, + 602.4 + ], + [ + -122.851459, + 48.680077, + 602.3 + ], + [ + -122.851448, + 48.680041, + 602 + ], + [ + -122.851425, + 48.680007, + 601.8 + ], + [ + -122.851413, + 48.679975, + 601.3 + ], + [ + -122.851399, + 48.679946, + 601.1 + ], + [ + -122.851403, + 48.679913, + 600.7 + ], + [ + -122.851394, + 48.679883, + 600.4 + ], + [ + -122.851387, + 48.679849, + 600 + ], + [ + -122.851375, + 48.679817, + 599.7 + ], + [ + -122.851392, + 48.679791, + 599.4 + ], + [ + -122.851407, + 48.679759, + 599.2 + ], + [ + -122.851407, + 48.67973, + 598.9 + ], + [ + -122.851412, + 48.679701, + 598.8 + ], + [ + -122.851422, + 48.679674, + 598.5 + ], + [ + -122.851427, + 48.679644, + 598.3 + ], + [ + -122.851421, + 48.679606, + 597.9 + ], + [ + -122.851411, + 48.67957, + 597.7 + ], + [ + -122.851396, + 48.679544, + 597.8 + ], + [ + -122.85139, + 48.679513, + 597.8 + ], + [ + -122.851397, + 48.679484, + 597.6 + ], + [ + -122.851401, + 48.679454, + 597.5 + ], + [ + -122.85138, + 48.679428, + 597.5 + ], + [ + -122.851366, + 48.679398, + 597.2 + ], + [ + -122.851362, + 48.679369, + 597.5 + ], + [ + -122.851357, + 48.679341, + 597.4 + ], + [ + -122.851354, + 48.679309, + 597.2 + ], + [ + -122.851362, + 48.679279, + 597 + ], + [ + -122.85137, + 48.67925, + 596.6 + ], + [ + -122.851376, + 48.679222, + 596.4 + ], + [ + -122.851386, + 48.679191, + 596.4 + ], + [ + -122.851401, + 48.679156, + 596.2 + ], + [ + -122.851404, + 48.679126, + 596.1 + ], + [ + -122.851387, + 48.679093, + 596.3 + ], + [ + -122.851378, + 48.679062, + 595.9 + ], + [ + -122.851383, + 48.679029, + 595.4 + ], + [ + -122.851408, + 48.679004, + 594.9 + ], + [ + -122.851401, + 48.678975, + 594.4 + ], + [ + -122.851325, + 48.678928, + 593.1 + ], + [ + -122.851284, + 48.678943, + 593 + ], + [ + -122.851329, + 48.678954, + 593.7 + ], + [ + -122.851327, + 48.678987, + 594.5 + ], + [ + -122.851334, + 48.678925, + 593.1 + ], + [ + -122.851337, + 48.678894, + 592.6 + ], + [ + -122.85134, + 48.678867, + 592.3 + ], + [ + -122.85135, + 48.678831, + 592 + ], + [ + -122.851352, + 48.678791, + 591.8 + ], + [ + -122.851351, + 48.678762, + 591.6 + ], + [ + -122.851372, + 48.678725, + 591.8 + ], + [ + -122.851385, + 48.678686, + 591.9 + ], + [ + -122.851402, + 48.678653, + 592.2 + ], + [ + -122.851413, + 48.67862, + 592.3 + ], + [ + -122.851436, + 48.678596, + 592.6 + ], + [ + -122.85144, + 48.678563, + 592.8 + ], + [ + -122.851459, + 48.678538, + 593 + ], + [ + -122.851469, + 48.678508, + 593.2 + ], + [ + -122.851478, + 48.678479, + 593.4 + ], + [ + -122.851504, + 48.678453, + 593.4 + ], + [ + -122.851536, + 48.678419, + 593.2 + ], + [ + -122.85155, + 48.67839, + 593.3 + ], + [ + -122.851557, + 48.678363, + 593.5 + ], + [ + -122.851581, + 48.678333, + 593.9 + ], + [ + -122.851593, + 48.678299, + 594.2 + ], + [ + -122.851596, + 48.678269, + 594.5 + ], + [ + -122.851591, + 48.678232, + 595 + ], + [ + -122.851585, + 48.678203, + 596.1 + ], + [ + -122.851588, + 48.678155, + 596.9 + ], + [ + -122.851625, + 48.678142, + 596.8 + ], + [ + -122.851647, + 48.678117, + 596.5 + ], + [ + -122.851639, + 48.678082, + 596.1 + ], + [ + -122.85163, + 48.678044, + 595.6 + ], + [ + -122.851645, + 48.678011, + 595.4 + ], + [ + -122.851652, + 48.67798, + 595.8 + ], + [ + -122.851644, + 48.677949, + 596.3 + ], + [ + -122.851615, + 48.677929, + 596.5 + ], + [ + -122.851629, + 48.677893, + 597.2 + ], + [ + -122.851642, + 48.67786, + 597.9 + ], + [ + -122.851634, + 48.677826, + 599 + ], + [ + -122.851602, + 48.677793, + 600 + ], + [ + -122.851564, + 48.677778, + 600.4 + ], + [ + -122.851539, + 48.677754, + 600.9 + ], + [ + -122.851522, + 48.677713, + 601.2 + ], + [ + -122.851518, + 48.677682, + 601.4 + ], + [ + -122.851514, + 48.677653, + 601.5 + ], + [ + -122.851509, + 48.67762, + 601.7 + ], + [ + -122.851478, + 48.677583, + 601.6 + ], + [ + -122.851461, + 48.677555, + 601.8 + ], + [ + -122.851452, + 48.677521, + 602 + ], + [ + -122.851466, + 48.677489, + 602.1 + ], + [ + -122.851477, + 48.677454, + 602.1 + ], + [ + -122.851478, + 48.677418, + 602.3 + ], + [ + -122.851461, + 48.677392, + 602.5 + ], + [ + -122.851456, + 48.677364, + 602.6 + ], + [ + -122.851448, + 48.677326, + 602.6 + ], + [ + -122.851463, + 48.677284, + 601.9 + ], + [ + -122.851473, + 48.677249, + 601.1 + ], + [ + -122.851494, + 48.677218, + 600 + ], + [ + -122.851504, + 48.67719, + 599.3 + ], + [ + -122.851489, + 48.677161, + 599.1 + ], + [ + -122.851465, + 48.677135, + 599.1 + ], + [ + -122.851449, + 48.677095, + 598.8 + ], + [ + -122.851448, + 48.677058, + 598.4 + ], + [ + -122.851446, + 48.677029, + 598.1 + ], + [ + -122.851431, + 48.677, + 597.7 + ], + [ + -122.851417, + 48.676965, + 596.6 + ], + [ + -122.851415, + 48.676935, + 595.7 + ], + [ + -122.851412, + 48.676904, + 595.2 + ], + [ + -122.851401, + 48.676862, + 595.6 + ], + [ + -122.851404, + 48.676829, + 596.4 + ], + [ + -122.851414, + 48.676797, + 596.9 + ], + [ + -122.851418, + 48.676771, + 597 + ], + [ + -122.851405, + 48.676738, + 597 + ], + [ + -122.851413, + 48.676707, + 596.8 + ], + [ + -122.851405, + 48.676678, + 596.5 + ], + [ + -122.851403, + 48.676646, + 596 + ], + [ + -122.851396, + 48.676612, + 595.5 + ], + [ + -122.851412, + 48.676584, + 594.9 + ], + [ + -122.851399, + 48.676555, + 594.5 + ], + [ + -122.85139, + 48.676524, + 593.9 + ], + [ + -122.851403, + 48.676493, + 593.3 + ], + [ + -122.851398, + 48.676463, + 592.7 + ], + [ + -122.851389, + 48.676431, + 592.1 + ], + [ + -122.851379, + 48.676387, + 591.5 + ], + [ + -122.851387, + 48.676349, + 591.2 + ], + [ + -122.851402, + 48.676315, + 591.2 + ], + [ + -122.851438, + 48.676294, + 592 + ], + [ + -122.851478, + 48.676277, + 592.9 + ], + [ + -122.851455, + 48.676235, + 592.4 + ], + [ + -122.851433, + 48.676207, + 591.6 + ], + [ + -122.851437, + 48.67617, + 591.5 + ], + [ + -122.851448, + 48.67614, + 591.5 + ], + [ + -122.851485, + 48.676118, + 591.8 + ], + [ + -122.851499, + 48.676089, + 591.4 + ], + [ + -122.851507, + 48.676058, + 590.9 + ], + [ + -122.851555, + 48.676028, + 591 + ], + [ + -122.851568, + 48.675998, + 590.9 + ], + [ + -122.851566, + 48.675965, + 590.3 + ], + [ + -122.851584, + 48.675936, + 590.1 + ], + [ + -122.851605, + 48.675911, + 590.2 + ], + [ + -122.851591, + 48.675875, + 589.8 + ], + [ + -122.851561, + 48.67584, + 589.9 + ], + [ + -122.851544, + 48.675802, + 589.9 + ], + [ + -122.851533, + 48.675774, + 589.9 + ], + [ + -122.851513, + 48.675739, + 590.1 + ], + [ + -122.85152, + 48.675709, + 589.7 + ], + [ + -122.851497, + 48.67567, + 590.3 + ], + [ + -122.851478, + 48.675641, + 590.3 + ], + [ + -122.851456, + 48.675611, + 590.4 + ], + [ + -122.851438, + 48.675586, + 590.8 + ], + [ + -122.851427, + 48.675556, + 590.8 + ], + [ + -122.851409, + 48.675523, + 590.6 + ], + [ + -122.851398, + 48.675489, + 590.3 + ], + [ + -122.851381, + 48.675457, + 589.9 + ], + [ + -122.85137, + 48.675422, + 589.5 + ], + [ + -122.851357, + 48.675389, + 589.9 + ], + [ + -122.851332, + 48.675342, + 590.9 + ], + [ + -122.851324, + 48.675297, + 591.9 + ], + [ + -122.851312, + 48.675264, + 592.2 + ], + [ + -122.85131, + 48.675225, + 593 + ], + [ + -122.851307, + 48.675196, + 593.2 + ], + [ + -122.851331, + 48.675166, + 593.5 + ], + [ + -122.851366, + 48.675148, + 594 + ], + [ + -122.851364, + 48.675118, + 594.5 + ], + [ + -122.851365, + 48.675077, + 595.2 + ], + [ + -122.851365, + 48.675047, + 595.6 + ], + [ + -122.851362, + 48.675017, + 596.4 + ], + [ + -122.851371, + 48.674988, + 597.1 + ], + [ + -122.851386, + 48.674963, + 597.8 + ], + [ + -122.851395, + 48.674933, + 598.6 + ], + [ + -122.851395, + 48.674898, + 599.7 + ], + [ + -122.851382, + 48.674862, + 600.8 + ], + [ + -122.851374, + 48.674835, + 601.5 + ], + [ + -122.851376, + 48.674803, + 602.7 + ], + [ + -122.85138, + 48.674775, + 603.3 + ], + [ + -122.851387, + 48.674739, + 603.8 + ], + [ + -122.85142, + 48.67471, + 603.9 + ], + [ + -122.851446, + 48.674682, + 604.1 + ], + [ + -122.851493, + 48.674673, + 604.2 + ], + [ + -122.85154, + 48.674656, + 604.8 + ], + [ + -122.851582, + 48.674656, + 605 + ], + [ + -122.851636, + 48.674646, + 605.5 + ], + [ + -122.851688, + 48.674654, + 605.8 + ], + [ + -122.851747, + 48.674644, + 606.6 + ], + [ + -122.851798, + 48.674633, + 607.2 + ], + [ + -122.85185, + 48.67463, + 607.9 + ], + [ + -122.851898, + 48.674634, + 608.4 + ], + [ + -122.85194, + 48.674628, + 609.7 + ], + [ + -122.851986, + 48.674623, + 611.4 + ], + [ + -122.852039, + 48.674612, + 613.1 + ], + [ + -122.852082, + 48.674619, + 613.7 + ], + [ + -122.852037, + 48.674643, + 612.2 + ], + [ + -122.852, + 48.674626, + 611.7 + ], + [ + -122.851961, + 48.674614, + 610.9 + ], + [ + -122.851921, + 48.674605, + 610.1 + ], + [ + -122.851889, + 48.674582, + 610.9 + ], + [ + -122.851846, + 48.674559, + 612.2 + ], + [ + -122.851824, + 48.674524, + 614.1 + ], + [ + -122.851814, + 48.674497, + 615.8 + ], + [ + -122.851795, + 48.674463, + 618 + ], + [ + -122.851773, + 48.674433, + 618.4 + ], + [ + -122.851745, + 48.674409, + 618.5 + ], + [ + -122.851729, + 48.674376, + 619.3 + ], + [ + -122.851726, + 48.674348, + 620 + ], + [ + -122.851703, + 48.674315, + 620.8 + ], + [ + -122.851665, + 48.674292, + 621.2 + ], + [ + -122.85163, + 48.674262, + 622 + ], + [ + -122.85162, + 48.674226, + 623.7 + ], + [ + -122.851587, + 48.674199, + 625.3 + ], + [ + -122.851552, + 48.674163, + 625.7 + ], + [ + -122.851529, + 48.674135, + 625.6 + ], + [ + -122.851494, + 48.674115, + 625.3 + ], + [ + -122.851468, + 48.674091, + 625.1 + ], + [ + -122.851446, + 48.674061, + 624.9 + ], + [ + -122.85144, + 48.674033, + 625.2 + ], + [ + -122.851441, + 48.674005, + 625.9 + ], + [ + -122.851457, + 48.673979, + 626.9 + ], + [ + -122.851478, + 48.673946, + 627.9 + ], + [ + -122.8515, + 48.673921, + 628.8 + ], + [ + -122.851483, + 48.673896, + 629.5 + ], + [ + -122.851459, + 48.673861, + 630.8 + ], + [ + -122.851437, + 48.673835, + 631.2 + ], + [ + -122.851454, + 48.673807, + 631.7 + ], + [ + -122.851493, + 48.673794, + 631.8 + ], + [ + -122.851479, + 48.673828, + 631.5 + ], + [ + -122.851447, + 48.673852, + 630.9 + ], + [ + -122.851507, + 48.673836, + 631.2 + ], + [ + -122.851532, + 48.673818, + 631.4 + ], + [ + -122.85153, + 48.673788, + 631.8 + ], + [ + -122.851533, + 48.673756, + 632 + ], + [ + -122.851516, + 48.673721, + 632.3 + ], + [ + -122.851497, + 48.673685, + 632.5 + ], + [ + -122.851479, + 48.67365, + 632.7 + ], + [ + -122.851454, + 48.673626, + 632.9 + ], + [ + -122.851436, + 48.673595, + 632.8 + ], + [ + -122.851423, + 48.673556, + 632.6 + ], + [ + -122.851424, + 48.673527, + 632.3 + ], + [ + -122.851426, + 48.673493, + 632 + ], + [ + -122.851404, + 48.673466, + 631.9 + ], + [ + -122.851376, + 48.673434, + 631.6 + ], + [ + -122.851347, + 48.673409, + 631.8 + ], + [ + -122.851319, + 48.673385, + 632.2 + ], + [ + -122.851305, + 48.673355, + 632.5 + ], + [ + -122.851284, + 48.673322, + 633.2 + ], + [ + -122.851263, + 48.673298, + 633.4 + ], + [ + -122.851224, + 48.673271, + 634 + ], + [ + -122.851185, + 48.673247, + 634.4 + ], + [ + -122.851156, + 48.673224, + 634.2 + ], + [ + -122.851133, + 48.673201, + 634.6 + ], + [ + -122.851098, + 48.673179, + 635.1 + ], + [ + -122.851071, + 48.673158, + 635.3 + ], + [ + -122.851041, + 48.673135, + 635.3 + ], + [ + -122.851, + 48.673106, + 635.8 + ], + [ + -122.850967, + 48.673078, + 636.2 + ], + [ + -122.850918, + 48.673058, + 636.7 + ], + [ + -122.85087, + 48.673055, + 637.3 + ], + [ + -122.850846, + 48.673021, + 637.2 + ], + [ + -122.850829, + 48.672993, + 637.1 + ], + [ + -122.850801, + 48.672957, + 637.3 + ], + [ + -122.85078, + 48.672932, + 637.3 + ], + [ + -122.850732, + 48.67293, + 637 + ], + [ + -122.850683, + 48.672915, + 636.7 + ], + [ + -122.850659, + 48.67289, + 636.6 + ], + [ + -122.850629, + 48.672864, + 636.6 + ], + [ + -122.850602, + 48.672838, + 636.7 + ], + [ + -122.850572, + 48.672806, + 636.9 + ], + [ + -122.850538, + 48.67278, + 637.1 + ], + [ + -122.850487, + 48.672777, + 637 + ], + [ + -122.850431, + 48.672761, + 637.4 + ], + [ + -122.850408, + 48.672736, + 637.7 + ], + [ + -122.850384, + 48.672767, + 637.7 + ], + [ + -122.850347, + 48.67273, + 638.1 + ], + [ + -122.850292, + 48.672747, + 638.1 + ], + [ + -122.850264, + 48.672722, + 638.3 + ], + [ + -122.850313, + 48.67274, + 638.1 + ], + [ + -122.850304, + 48.672692, + 638.2 + ], + [ + -122.850225, + 48.672679, + 638.4 + ], + [ + -122.850187, + 48.672669, + 638.6 + ], + [ + -122.850139, + 48.672661, + 639.3 + ], + [ + -122.850127, + 48.672628, + 639.2 + ], + [ + -122.850073, + 48.67259, + 638.8 + ], + [ + -122.850039, + 48.672571, + 638.4 + ], + [ + -122.849995, + 48.672563, + 638.5 + ], + [ + -122.849954, + 48.672558, + 638.9 + ], + [ + -122.849915, + 48.672536, + 639.2 + ], + [ + -122.849874, + 48.672524, + 639.6 + ], + [ + -122.84983, + 48.672504, + 640 + ], + [ + -122.849823, + 48.67247, + 639.8 + ], + [ + -122.849807, + 48.672436, + 640.2 + ], + [ + -122.849789, + 48.672402, + 640.5 + ], + [ + -122.849772, + 48.672371, + 640.5 + ], + [ + -122.849745, + 48.672342, + 640.3 + ], + [ + -122.8497, + 48.672326, + 640.4 + ], + [ + -122.84966, + 48.672304, + 640.3 + ], + [ + -122.849636, + 48.672278, + 640 + ], + [ + -122.849609, + 48.672252, + 639.7 + ], + [ + -122.849578, + 48.672223, + 639.4 + ], + [ + -122.849534, + 48.672219, + 639.2 + ], + [ + -122.849495, + 48.672232, + 639.1 + ], + [ + -122.849452, + 48.672253, + 639.1 + ], + [ + -122.84941, + 48.672253, + 638.8 + ], + [ + -122.84937, + 48.672268, + 638.8 + ], + [ + -122.849328, + 48.67228, + 638.6 + ], + [ + -122.849268, + 48.672287, + 638.5 + ], + [ + -122.849226, + 48.672282, + 637.9 + ], + [ + -122.849165, + 48.672273, + 637 + ], + [ + -122.849128, + 48.67226, + 636.7 + ], + [ + -122.849091, + 48.672234, + 636.6 + ], + [ + -122.849072, + 48.67221, + 636.8 + ], + [ + -122.849025, + 48.672189, + 637.1 + ], + [ + -122.848988, + 48.672173, + 637.6 + ], + [ + -122.848951, + 48.672159, + 638 + ], + [ + -122.84893, + 48.672135, + 638.1 + ], + [ + -122.848911, + 48.672103, + 638.3 + ], + [ + -122.848886, + 48.672081, + 638.5 + ], + [ + -122.848866, + 48.672039, + 639.1 + ], + [ + -122.848823, + 48.67199, + 640.1 + ], + [ + -122.848786, + 48.671962, + 640.3 + ], + [ + -122.848749, + 48.671929, + 640.8 + ], + [ + -122.848728, + 48.671892, + 640.8 + ], + [ + -122.848718, + 48.671862, + 640.8 + ], + [ + -122.848714, + 48.671828, + 640.6 + ], + [ + -122.848711, + 48.671792, + 640.5 + ], + [ + -122.848722, + 48.671765, + 640.4 + ], + [ + -122.848711, + 48.671725, + 640.4 + ], + [ + -122.848706, + 48.67169, + 640.4 + ], + [ + -122.848695, + 48.671663, + 640.5 + ], + [ + -122.848672, + 48.671637, + 640.6 + ], + [ + -122.848653, + 48.671612, + 640.2 + ], + [ + -122.848635, + 48.671585, + 639.8 + ], + [ + -122.848619, + 48.671559, + 639.7 + ], + [ + -122.848589, + 48.671527, + 639.1 + ], + [ + -122.848558, + 48.671507, + 638.1 + ], + [ + -122.848527, + 48.671482, + 637.3 + ], + [ + -122.848521, + 48.671453, + 636.8 + ], + [ + -122.848513, + 48.671416, + 636.3 + ], + [ + -122.848485, + 48.671392, + 636 + ], + [ + -122.848445, + 48.671384, + 635.9 + ], + [ + -122.848397, + 48.671365, + 636 + ], + [ + -122.848333, + 48.671349, + 636.3 + ], + [ + -122.848295, + 48.671333, + 636.6 + ], + [ + -122.848263, + 48.671315, + 636.9 + ], + [ + -122.84823, + 48.671283, + 636.7 + ], + [ + -122.848219, + 48.671246, + 635.9 + ], + [ + -122.848178, + 48.67122, + 635.3 + ], + [ + -122.848131, + 48.671211, + 634.6 + ], + [ + -122.848084, + 48.671206, + 634.3 + ], + [ + -122.848042, + 48.671204, + 634.2 + ], + [ + -122.847993, + 48.671203, + 634 + ], + [ + -122.847934, + 48.671208, + 633.4 + ], + [ + -122.84789, + 48.671201, + 632.9 + ], + [ + -122.847851, + 48.671166, + 633.4 + ], + [ + -122.847828, + 48.671141, + 633.6 + ], + [ + -122.847803, + 48.671117, + 633.7 + ], + [ + -122.847762, + 48.671089, + 633.7 + ], + [ + -122.847731, + 48.67107, + 633.8 + ], + [ + -122.847688, + 48.671053, + 633.2 + ], + [ + -122.847653, + 48.671034, + 632.8 + ], + [ + -122.847622, + 48.671014, + 632.6 + ], + [ + -122.847599, + 48.67099, + 632.7 + ], + [ + -122.847573, + 48.670966, + 632.8 + ], + [ + -122.847543, + 48.670945, + 633 + ], + [ + -122.847498, + 48.67092, + 633.2 + ], + [ + -122.84746, + 48.670894, + 633.5 + ], + [ + -122.847416, + 48.670888, + 633.7 + ], + [ + -122.847367, + 48.67087, + 634.3 + ], + [ + -122.847336, + 48.670847, + 635.2 + ], + [ + -122.847297, + 48.670828, + 635.6 + ], + [ + -122.847257, + 48.670819, + 635.7 + ], + [ + -122.847215, + 48.670787, + 636.3 + ], + [ + -122.847188, + 48.670766, + 636.7 + ], + [ + -122.847148, + 48.670754, + 636.8 + ], + [ + -122.847126, + 48.67073, + 637.3 + ], + [ + -122.847092, + 48.670712, + 637.6 + ], + [ + -122.847068, + 48.670668, + 638.1 + ], + [ + -122.847047, + 48.670642, + 638.4 + ], + [ + -122.847013, + 48.670614, + 638.7 + ], + [ + -122.846977, + 48.670595, + 638.9 + ], + [ + -122.846938, + 48.670578, + 639.2 + ], + [ + -122.84689, + 48.670561, + 639.3 + ], + [ + -122.846848, + 48.670537, + 639.4 + ], + [ + -122.846806, + 48.670525, + 639.7 + ], + [ + -122.846763, + 48.670515, + 640.1 + ], + [ + -122.846718, + 48.670514, + 640.4 + ], + [ + -122.846676, + 48.670508, + 640 + ], + [ + -122.846625, + 48.670498, + 639.5 + ], + [ + -122.846576, + 48.670488, + 639 + ], + [ + -122.846537, + 48.670476, + 638.4 + ], + [ + -122.846503, + 48.67046, + 637 + ], + [ + -122.846463, + 48.670455, + 636 + ], + [ + -122.846412, + 48.670468, + 635.6 + ], + [ + -122.846364, + 48.67047, + 634.8 + ], + [ + -122.8463, + 48.670426, + 633 + ], + [ + -122.846273, + 48.670403, + 633 + ], + [ + -122.846266, + 48.670374, + 633.2 + ], + [ + -122.846327, + 48.670342, + 633.4 + ], + [ + -122.846354, + 48.670321, + 633.5 + ], + [ + -122.846305, + 48.670308, + 633.5 + ], + [ + -122.846274, + 48.670354, + 633.3 + ], + [ + -122.846243, + 48.670322, + 633.4 + ], + [ + -122.84628, + 48.670291, + 633.7 + ], + [ + -122.846321, + 48.670276, + 633.8 + ], + [ + -122.846372, + 48.670279, + 633.8 + ], + [ + -122.846424, + 48.670269, + 634.2 + ], + [ + -122.84646, + 48.670253, + 634.7 + ], + [ + -122.846501, + 48.670238, + 635.1 + ], + [ + -122.846552, + 48.670225, + 634.9 + ], + [ + -122.84659, + 48.670205, + 634.8 + ], + [ + -122.846626, + 48.670189, + 634.5 + ], + [ + -122.846666, + 48.670173, + 633.6 + ], + [ + -122.846714, + 48.670168, + 632.2 + ], + [ + -122.846745, + 48.670149, + 631.6 + ], + [ + -122.846755, + 48.670119, + 631.7 + ], + [ + -122.846779, + 48.670092, + 631.7 + ], + [ + -122.846831, + 48.670086, + 630.2 + ], + [ + -122.846879, + 48.670081, + 629.1 + ], + [ + -122.846932, + 48.670069, + 628.2 + ], + [ + -122.846987, + 48.670063, + 627.4 + ], + [ + -122.847042, + 48.67006, + 627.2 + ], + [ + -122.847088, + 48.670045, + 626.5 + ], + [ + -122.847131, + 48.670047, + 626.4 + ], + [ + -122.847173, + 48.670045, + 626.2 + ], + [ + -122.847175, + 48.670017, + 625 + ], + [ + -122.84718, + 48.669983, + 625.1 + ], + [ + -122.847188, + 48.669955, + 625.5 + ], + [ + -122.847211, + 48.669926, + 625.2 + ], + [ + -122.847245, + 48.669904, + 624.5 + ], + [ + -122.847281, + 48.669877, + 623.6 + ], + [ + -122.847303, + 48.669851, + 623.5 + ], + [ + -122.847339, + 48.669827, + 622.4 + ], + [ + -122.847354, + 48.669801, + 622 + ], + [ + -122.84735, + 48.669773, + 622.5 + ], + [ + -122.847379, + 48.669745, + 621 + ], + [ + -122.847391, + 48.669712, + 620.1 + ], + [ + -122.847397, + 48.669677, + 619.6 + ], + [ + -122.847385, + 48.669645, + 620.2 + ], + [ + -122.847378, + 48.669609, + 620.3 + ], + [ + -122.84739, + 48.669581, + 619.3 + ], + [ + -122.847411, + 48.669557, + 617.6 + ], + [ + -122.847439, + 48.669529, + 615 + ], + [ + -122.847479, + 48.669494, + 611.9 + ], + [ + -122.847482, + 48.669461, + 611.4 + ], + [ + -122.847483, + 48.669433, + 611 + ], + [ + -122.847505, + 48.669403, + 609.7 + ], + [ + -122.847543, + 48.669369, + 607.6 + ], + [ + -122.84757, + 48.669345, + 606.4 + ], + [ + -122.847598, + 48.66932, + 605 + ], + [ + -122.847627, + 48.669283, + 603.4 + ], + [ + -122.847654, + 48.669242, + 602.4 + ], + [ + -122.84767, + 48.669206, + 602.1 + ], + [ + -122.847672, + 48.669175, + 602 + ], + [ + -122.847692, + 48.669137, + 601.3 + ], + [ + -122.847731, + 48.669123, + 599.5 + ], + [ + -122.847781, + 48.669105, + 596.8 + ], + [ + -122.847827, + 48.669119, + 594.8 + ], + [ + -122.847863, + 48.669146, + 592.7 + ], + [ + -122.847893, + 48.669167, + 590.8 + ], + [ + -122.847918, + 48.669197, + 588.8 + ], + [ + -122.847935, + 48.669222, + 586.8 + ], + [ + -122.847941, + 48.669256, + 586.6 + ], + [ + -122.847957, + 48.669292, + 585.7 + ], + [ + -122.84796, + 48.669329, + 586.3 + ], + [ + -122.847989, + 48.669358, + 586 + ], + [ + -122.848, + 48.669392, + 587.2 + ], + [ + -122.847996, + 48.669421, + 588.6 + ], + [ + -122.848028, + 48.669442, + 590.1 + ], + [ + -122.847983, + 48.669484, + 592.2 + ], + [ + -122.847952, + 48.669514, + 593.9 + ], + [ + -122.847981, + 48.669493, + 592.8 + ], + [ + -122.847991, + 48.669461, + 590.9 + ], + [ + -122.84802, + 48.669435, + 589.6 + ], + [ + -122.848053, + 48.669413, + 588.7 + ], + [ + -122.848072, + 48.669381, + 587 + ], + [ + -122.848084, + 48.669353, + 585.5 + ], + [ + -122.848098, + 48.669328, + 583.9 + ], + [ + -122.84812, + 48.6693, + 582.3 + ], + [ + -122.848146, + 48.669274, + 580.9 + ], + [ + -122.848196, + 48.669257, + 580.6 + ], + [ + -122.848245, + 48.669233, + 579.9 + ], + [ + -122.848283, + 48.669218, + 579.4 + ], + [ + -122.848348, + 48.669196, + 578.9 + ], + [ + -122.848405, + 48.669184, + 579.2 + ], + [ + -122.848448, + 48.669166, + 579 + ], + [ + -122.848505, + 48.669168, + 579.7 + ], + [ + -122.848566, + 48.669157, + 579.6 + ], + [ + -122.848617, + 48.669162, + 578.9 + ], + [ + -122.848664, + 48.66918, + 578.1 + ], + [ + -122.848704, + 48.669204, + 577.9 + ], + [ + -122.848731, + 48.669226, + 578 + ], + [ + -122.84876, + 48.669247, + 578.1 + ], + [ + -122.848712, + 48.669244, + 579.7 + ], + [ + -122.848683, + 48.669225, + 579.7 + ], + [ + -122.848614, + 48.669238, + 582.4 + ], + [ + -122.848558, + 48.669256, + 584.3 + ], + [ + -122.848517, + 48.669269, + 585.1 + ], + [ + -122.848473, + 48.66926, + 584.5 + ], + [ + -122.84849, + 48.669228, + 582.9 + ], + [ + -122.848471, + 48.669198, + 581 + ], + [ + -122.848445, + 48.669171, + 579.2 + ], + [ + -122.848413, + 48.669153, + 577.5 + ], + [ + -122.848367, + 48.669158, + 577.1 + ], + [ + -122.84832, + 48.669178, + 577.4 + ], + [ + -122.848281, + 48.669188, + 577.4 + ], + [ + -122.848237, + 48.669189, + 577 + ], + [ + -122.84823, + 48.669157, + 575.3 + ], + [ + -122.848197, + 48.669128, + 573.7 + ], + [ + -122.848147, + 48.669113, + 572.8 + ], + [ + -122.848122, + 48.669089, + 572.7 + ], + [ + -122.848081, + 48.669075, + 574 + ], + [ + -122.848043, + 48.669062, + 576 + ], + [ + -122.848062, + 48.669028, + 575.5 + ], + [ + -122.848077, + 48.668998, + 574.6 + ], + [ + -122.848101, + 48.668969, + 573.7 + ], + [ + -122.848115, + 48.668941, + 573 + ], + [ + -122.848161, + 48.668917, + 570.9 + ], + [ + -122.848214, + 48.668903, + 569.1 + ], + [ + -122.848277, + 48.668935, + 569.3 + ], + [ + -122.848307, + 48.668903, + 568.2 + ], + [ + -122.848328, + 48.668871, + 567.2 + ], + [ + -122.848341, + 48.668842, + 566.5 + ], + [ + -122.848365, + 48.668799, + 565.4 + ], + [ + -122.848396, + 48.668762, + 564.4 + ], + [ + -122.848432, + 48.66873, + 563.7 + ], + [ + -122.848475, + 48.668708, + 563.3 + ], + [ + -122.848516, + 48.668687, + 562.3 + ], + [ + -122.848569, + 48.668679, + 561.2 + ], + [ + -122.848611, + 48.668681, + 560.3 + ], + [ + -122.848651, + 48.668693, + 559.5 + ], + [ + -122.848693, + 48.668706, + 558.3 + ], + [ + -122.848737, + 48.668712, + 556.8 + ], + [ + -122.848783, + 48.668718, + 555.3 + ], + [ + -122.848828, + 48.668705, + 553.4 + ], + [ + -122.848872, + 48.668721, + 552.5 + ], + [ + -122.848912, + 48.668731, + 551.2 + ], + [ + -122.848936, + 48.668756, + 551.3 + ], + [ + -122.848965, + 48.668779, + 551.1 + ], + [ + -122.849003, + 48.668795, + 550.3 + ], + [ + -122.849043, + 48.668812, + 549.7 + ], + [ + -122.84909, + 48.668804, + 548.6 + ], + [ + -122.849138, + 48.668804, + 548 + ], + [ + -122.849181, + 48.668818, + 548.1 + ], + [ + -122.849204, + 48.668842, + 548.6 + ], + [ + -122.849192, + 48.668868, + 549.4 + ], + [ + -122.849161, + 48.668888, + 550.4 + ], + [ + -122.849113, + 48.668893, + 551.5 + ], + [ + -122.849074, + 48.668871, + 551.4 + ], + [ + -122.849023, + 48.668868, + 552.5 + ], + [ + -122.848975, + 48.668858, + 553.4 + ], + [ + -122.848955, + 48.668828, + 553.1 + ], + [ + -122.848924, + 48.668807, + 553.5 + ], + [ + -122.84888, + 48.668807, + 554.9 + ], + [ + -122.848817, + 48.668808, + 557.1 + ], + [ + -122.84876, + 48.668797, + 558.8 + ], + [ + -122.848727, + 48.668778, + 559.2 + ], + [ + -122.848725, + 48.668747, + 558.4 + ], + [ + -122.848727, + 48.668711, + 557.1 + ], + [ + -122.848726, + 48.668679, + 556.1 + ], + [ + -122.848721, + 48.668651, + 555.3 + ], + [ + -122.848735, + 48.668624, + 553.5 + ], + [ + -122.848731, + 48.668589, + 552 + ], + [ + -122.848739, + 48.668553, + 550.1 + ], + [ + -122.848726, + 48.668518, + 548.8 + ], + [ + -122.848751, + 48.668492, + 546.8 + ], + [ + -122.848786, + 48.668468, + 544.2 + ], + [ + -122.848826, + 48.668445, + 542 + ], + [ + -122.848869, + 48.668425, + 540.1 + ], + [ + -122.848909, + 48.668406, + 538.8 + ], + [ + -122.848952, + 48.668396, + 538 + ], + [ + -122.848945, + 48.66843, + 538.9 + ], + [ + -122.848914, + 48.668455, + 540.4 + ], + [ + -122.848882, + 48.668484, + 542.3 + ], + [ + -122.848842, + 48.668522, + 545.1 + ], + [ + -122.848785, + 48.66856, + 548.8 + ], + [ + -122.848734, + 48.668582, + 551.6 + ], + [ + -122.848738, + 48.668535, + 549.2 + ], + [ + -122.848737, + 48.668497, + 547.5 + ], + [ + -122.848744, + 48.668452, + 545 + ], + [ + -122.84883, + 48.668402, + 540 + ], + [ + -122.848792, + 48.66838, + 540.3 + ], + [ + -122.848736, + 48.668372, + 541.3 + ], + [ + -122.848683, + 48.668368, + 542.7 + ], + [ + -122.848639, + 48.668363, + 544.2 + ], + [ + -122.848619, + 48.668334, + 543.4 + ], + [ + -122.848597, + 48.668303, + 542.7 + ], + [ + -122.84859, + 48.668271, + 541.4 + ], + [ + -122.848616, + 48.668236, + 538.4 + ], + [ + -122.848666, + 48.668205, + 535.3 + ], + [ + -122.848709, + 48.668176, + 533.2 + ], + [ + -122.84874, + 48.668149, + 531.4 + ], + [ + -122.848766, + 48.668123, + 530.2 + ], + [ + -122.848796, + 48.668102, + 529.2 + ], + [ + -122.848832, + 48.66809, + 528.6 + ], + [ + -122.848799, + 48.668067, + 528.5 + ], + [ + -122.848752, + 48.668061, + 528.6 + ], + [ + -122.848706, + 48.668053, + 528.4 + ], + [ + -122.848651, + 48.668051, + 528.8 + ], + [ + -122.848607, + 48.66806, + 530.2 + ], + [ + -122.848634, + 48.66803, + 528.1 + ], + [ + -122.848662, + 48.667996, + 526.1 + ], + [ + -122.848683, + 48.667955, + 524.3 + ], + [ + -122.848708, + 48.667918, + 523.1 + ], + [ + -122.84873, + 48.667893, + 521.9 + ], + [ + -122.848719, + 48.667862, + 520.8 + ], + [ + -122.848735, + 48.667836, + 519.5 + ], + [ + -122.848762, + 48.667815, + 518.2 + ], + [ + -122.84881, + 48.667811, + 517.2 + ], + [ + -122.848861, + 48.667822, + 516.5 + ], + [ + -122.848903, + 48.667837, + 516.2 + ], + [ + -122.848948, + 48.667854, + 515.9 + ], + [ + -122.849001, + 48.66786, + 515.2 + ], + [ + -122.849052, + 48.667869, + 515.1 + ], + [ + -122.849099, + 48.667875, + 514.6 + ], + [ + -122.849141, + 48.667879, + 513.9 + ], + [ + -122.849185, + 48.667883, + 512.9 + ], + [ + -122.849242, + 48.667886, + 511.7 + ], + [ + -122.849271, + 48.667908, + 511.8 + ], + [ + -122.849229, + 48.667908, + 513.1 + ], + [ + -122.849194, + 48.667922, + 514.4 + ], + [ + -122.849154, + 48.667939, + 515.7 + ], + [ + -122.84911, + 48.667934, + 516.4 + ], + [ + -122.849069, + 48.667926, + 516.9 + ], + [ + -122.849029, + 48.667908, + 516.9 + ], + [ + -122.848997, + 48.667887, + 516.5 + ], + [ + -122.848969, + 48.667861, + 515.8 + ], + [ + -122.848947, + 48.667832, + 515 + ], + [ + -122.848913, + 48.667817, + 515.1 + ], + [ + -122.848861, + 48.667811, + 516 + ], + [ + -122.848827, + 48.66779, + 515.9 + ], + [ + -122.848851, + 48.667756, + 514.2 + ], + [ + -122.848889, + 48.667716, + 511.8 + ], + [ + -122.848933, + 48.667684, + 510 + ], + [ + -122.84896, + 48.667663, + 508.7 + ], + [ + -122.848961, + 48.667629, + 507.6 + ], + [ + -122.848951, + 48.667598, + 507 + ], + [ + -122.848972, + 48.667553, + 505 + ], + [ + -122.849005, + 48.667514, + 502.5 + ], + [ + -122.849046, + 48.667509, + 500.6 + ], + [ + -122.849088, + 48.667513, + 499.1 + ], + [ + -122.849129, + 48.667515, + 497.8 + ], + [ + -122.849165, + 48.667535, + 497.6 + ], + [ + -122.849212, + 48.667541, + 496.5 + ], + [ + -122.849255, + 48.66753, + 494.8 + ], + [ + -122.849319, + 48.667518, + 492.6 + ], + [ + -122.84937, + 48.667525, + 491.8 + ], + [ + -122.849413, + 48.667544, + 491.7 + ], + [ + -122.849453, + 48.66756, + 491.5 + ], + [ + -122.849499, + 48.667569, + 491.4 + ], + [ + -122.849537, + 48.667589, + 491.8 + ], + [ + -122.849571, + 48.667605, + 492.8 + ], + [ + -122.849603, + 48.667626, + 494.1 + ], + [ + -122.849651, + 48.667617, + 492.4 + ], + [ + -122.849685, + 48.667595, + 490.1 + ], + [ + -122.849727, + 48.667585, + 488.2 + ], + [ + -122.849766, + 48.667575, + 486.8 + ], + [ + -122.849814, + 48.667583, + 486.6 + ], + [ + -122.849853, + 48.667607, + 487.6 + ], + [ + -122.849896, + 48.667648, + 488.4 + ], + [ + -122.849938, + 48.667688, + 488.7 + ], + [ + -122.849889, + 48.667679, + 489.1 + ], + [ + -122.849846, + 48.667711, + 490.6 + ], + [ + -122.849815, + 48.667735, + 491.6 + ], + [ + -122.849852, + 48.667709, + 490.5 + ], + [ + -122.8499, + 48.667682, + 489.1 + ], + [ + -122.849945, + 48.667661, + 487.8 + ], + [ + -122.84999, + 48.66765, + 486.5 + ], + [ + -122.850035, + 48.667646, + 485.9 + ], + [ + -122.850081, + 48.667658, + 486 + ], + [ + -122.850129, + 48.667672, + 485.2 + ], + [ + -122.850166, + 48.667689, + 484.1 + ], + [ + -122.850208, + 48.667703, + 483.7 + ], + [ + -122.850249, + 48.667713, + 483.2 + ], + [ + -122.850291, + 48.667725, + 483.1 + ], + [ + -122.850333, + 48.667745, + 482.3 + ], + [ + -122.850359, + 48.667768, + 482.1 + ], + [ + -122.85039, + 48.66779, + 482.6 + ], + [ + -122.850438, + 48.667796, + 481.6 + ], + [ + -122.850482, + 48.667803, + 481 + ], + [ + -122.850526, + 48.667807, + 479.9 + ], + [ + -122.850572, + 48.667801, + 478.3 + ], + [ + -122.85062, + 48.667804, + 477.2 + ], + [ + -122.850665, + 48.667813, + 476.2 + ], + [ + -122.850709, + 48.667825, + 475.4 + ], + [ + -122.850742, + 48.667844, + 475.8 + ], + [ + -122.850781, + 48.667857, + 475.8 + ], + [ + -122.850826, + 48.667868, + 475.1 + ], + [ + -122.850876, + 48.667869, + 473.3 + ], + [ + -122.850918, + 48.667869, + 471.7 + ], + [ + -122.850959, + 48.667878, + 470 + ], + [ + -122.851005, + 48.667901, + 469.4 + ], + [ + -122.851046, + 48.667924, + 469.8 + ], + [ + -122.851088, + 48.667945, + 469.7 + ], + [ + -122.851126, + 48.667958, + 469 + ], + [ + -122.851161, + 48.667975, + 468.7 + ], + [ + -122.851191, + 48.667999, + 469 + ], + [ + -122.851215, + 48.668026, + 469.8 + ], + [ + -122.851259, + 48.668031, + 468.8 + ], + [ + -122.8513, + 48.668026, + 467.5 + ], + [ + -122.85134, + 48.668037, + 466.9 + ], + [ + -122.851373, + 48.668066, + 466.8 + ], + [ + -122.851415, + 48.668082, + 466.5 + ], + [ + -122.851467, + 48.668083, + 465.1 + ], + [ + -122.851507, + 48.668075, + 464 + ], + [ + -122.851546, + 48.668091, + 463.6 + ], + [ + -122.851584, + 48.668112, + 463.4 + ], + [ + -122.851627, + 48.668113, + 462.6 + ], + [ + -122.851627, + 48.66815, + 463.6 + ], + [ + -122.851608, + 48.668177, + 464.9 + ], + [ + -122.85158, + 48.668201, + 466.6 + ], + [ + -122.851616, + 48.668225, + 466.3 + ], + [ + -122.851724, + 48.668221, + 464 + ], + [ + -122.851765, + 48.668205, + 463.3 + ], + [ + -122.851803, + 48.668183, + 462.6 + ], + [ + -122.851849, + 48.668174, + 462.2 + ], + [ + -122.851885, + 48.668151, + 461.5 + ], + [ + -122.851936, + 48.668131, + 460.7 + ], + [ + -122.851979, + 48.668133, + 460.3 + ], + [ + -122.852035, + 48.668142, + 459.2 + ], + [ + -122.851996, + 48.668156, + 460.8 + ], + [ + -122.852022, + 48.668134, + 459.3 + ], + [ + -122.851982, + 48.668122, + 459.9 + ], + [ + -122.851947, + 48.668107, + 459.8 + ], + [ + -122.851904, + 48.66812, + 460.5 + ], + [ + -122.851859, + 48.668143, + 461.3 + ], + [ + -122.851817, + 48.668127, + 461.1 + ], + [ + -122.851776, + 48.668117, + 460.9 + ], + [ + -122.85175, + 48.668068, + 459.3 + ], + [ + -122.85171, + 48.668056, + 459.3 + ], + [ + -122.851712, + 48.668023, + 458.3 + ], + [ + -122.851686, + 48.668002, + 458.4 + ], + [ + -122.851628, + 48.668009, + 459.7 + ], + [ + -122.851587, + 48.667995, + 459.7 + ], + [ + -122.851541, + 48.667985, + 460.4 + ], + [ + -122.851515, + 48.667964, + 460.4 + ], + [ + -122.851498, + 48.667938, + 460.1 + ], + [ + -122.851463, + 48.667916, + 460.2 + ], + [ + -122.851441, + 48.667891, + 459.6 + ], + [ + -122.851384, + 48.667879, + 460.2 + ], + [ + -122.851342, + 48.667881, + 461 + ], + [ + -122.851283, + 48.667882, + 462.1 + ], + [ + -122.851242, + 48.667876, + 462.7 + ], + [ + -122.851205, + 48.667857, + 462.8 + ], + [ + -122.851182, + 48.667833, + 462.3 + ], + [ + -122.851168, + 48.667803, + 461.5 + ], + [ + -122.851134, + 48.667774, + 461.1 + ], + [ + -122.851106, + 48.667744, + 460.5 + ], + [ + -122.851082, + 48.667717, + 459.7 + ], + [ + -122.851053, + 48.667693, + 459 + ], + [ + -122.85102, + 48.667672, + 458.3 + ], + [ + -122.850978, + 48.667652, + 458.1 + ], + [ + -122.850938, + 48.667652, + 458.8 + ], + [ + -122.850893, + 48.667658, + 459.6 + ], + [ + -122.850839, + 48.667657, + 460.7 + ], + [ + -122.850798, + 48.667647, + 461.5 + ], + [ + -122.850775, + 48.667622, + 460.7 + ], + [ + -122.850761, + 48.667592, + 459.3 + ], + [ + -122.850768, + 48.667552, + 456.6 + ], + [ + -122.85078, + 48.667519, + 454.4 + ], + [ + -122.850801, + 48.66749, + 452.4 + ], + [ + -122.850834, + 48.667464, + 450.5 + ], + [ + -122.850859, + 48.667438, + 448.8 + ], + [ + -122.850873, + 48.667412, + 447.7 + ], + [ + -122.850917, + 48.667383, + 446.1 + ], + [ + -122.850967, + 48.66736, + 444.6 + ], + [ + -122.851013, + 48.667348, + 443.7 + ], + [ + -122.851051, + 48.667331, + 442.8 + ], + [ + -122.851081, + 48.667312, + 441.9 + ], + [ + -122.851121, + 48.667295, + 441.2 + ], + [ + -122.851151, + 48.667271, + 440.4 + ], + [ + -122.851193, + 48.667263, + 440 + ], + [ + -122.851246, + 48.66725, + 439.2 + ], + [ + -122.851274, + 48.667243, + 438.6 + ], + [ + -122.851331, + 48.667245, + 437.7 + ], + [ + -122.851374, + 48.667237, + 436.9 + ], + [ + -122.851429, + 48.667231, + 435.8 + ], + [ + -122.851475, + 48.66721, + 434.3 + ], + [ + -122.851517, + 48.667195, + 432.9 + ], + [ + -122.85156, + 48.66718, + 431.5 + ], + [ + -122.851607, + 48.667156, + 429.4 + ], + [ + -122.851643, + 48.667135, + 428.1 + ], + [ + -122.851709, + 48.667132, + 426.7 + ], + [ + -122.851772, + 48.667132, + 425.6 + ], + [ + -122.851815, + 48.667132, + 424.9 + ], + [ + -122.851858, + 48.667152, + 425 + ], + [ + -122.851913, + 48.667166, + 424.7 + ], + [ + -122.851953, + 48.66719, + 425 + ], + [ + -122.851976, + 48.667233, + 426.4 + ], + [ + -122.851999, + 48.667262, + 427.2 + ], + [ + -122.852038, + 48.667269, + 426.6 + ], + [ + -122.852077, + 48.667291, + 426.7 + ], + [ + -122.852051, + 48.667317, + 428 + ], + [ + -122.852009, + 48.667347, + 429.9 + ], + [ + -122.851978, + 48.667368, + 430.7 + ], + [ + -122.852005, + 48.667345, + 429.8 + ], + [ + -122.852044, + 48.667318, + 428.2 + ], + [ + -122.852043, + 48.667288, + 427.2 + ], + [ + -122.852007, + 48.667273, + 427.5 + ], + [ + -122.851955, + 48.66726, + 427.8 + ], + [ + -122.851934, + 48.66723, + 426.9 + ], + [ + -122.851937, + 48.667198, + 425.6 + ], + [ + -122.851915, + 48.667173, + 424.9 + ], + [ + -122.851902, + 48.667138, + 423.9 + ], + [ + -122.851909, + 48.66711, + 422.9 + ], + [ + -122.851881, + 48.66708, + 422.6 + ], + [ + -122.851855, + 48.667053, + 422.8 + ], + [ + -122.851832, + 48.66703, + 423.1 + ], + [ + -122.851836, + 48.667002, + 422.9 + ], + [ + -122.851813, + 48.66698, + 423.1 + ], + [ + -122.851853, + 48.666942, + 422.1 + ], + [ + -122.851839, + 48.666908, + 421.6 + ], + [ + -122.851827, + 48.666879, + 421 + ], + [ + -122.851833, + 48.666842, + 420.1 + ], + [ + -122.851835, + 48.666813, + 419.7 + ], + [ + -122.85185, + 48.666786, + 419.4 + ], + [ + -122.851862, + 48.666747, + 418.7 + ], + [ + -122.851874, + 48.666716, + 418.1 + ], + [ + -122.85186, + 48.666688, + 418.4 + ], + [ + -122.851892, + 48.666651, + 417.5 + ], + [ + -122.851899, + 48.666619, + 416.4 + ], + [ + -122.851904, + 48.666587, + 415.6 + ], + [ + -122.851925, + 48.666563, + 414.4 + ], + [ + -122.851942, + 48.66653, + 413.4 + ], + [ + -122.851958, + 48.666497, + 412.3 + ], + [ + -122.851969, + 48.666467, + 411 + ], + [ + -122.851987, + 48.666437, + 409.6 + ], + [ + -122.852001, + 48.666409, + 408.6 + ], + [ + -122.852038, + 48.666388, + 407.5 + ], + [ + -122.852075, + 48.666356, + 406 + ], + [ + -122.852113, + 48.666335, + 404.7 + ], + [ + -122.852145, + 48.666317, + 403.3 + ], + [ + -122.852187, + 48.6663, + 401.6 + ], + [ + -122.852236, + 48.666306, + 400.6 + ], + [ + -122.852278, + 48.666311, + 399.5 + ], + [ + -122.852313, + 48.666335, + 399.2 + ], + [ + -122.852336, + 48.666357, + 399.2 + ], + [ + -122.852363, + 48.666382, + 399.4 + ], + [ + -122.852407, + 48.666385, + 398 + ], + [ + -122.852477, + 48.66639, + 396 + ], + [ + -122.852529, + 48.66639, + 394.7 + ], + [ + -122.852576, + 48.666396, + 393.6 + ], + [ + -122.852557, + 48.666423, + 394.8 + ], + [ + -122.852586, + 48.666442, + 394.6 + ], + [ + -122.852634, + 48.666462, + 394.6 + ], + [ + -122.852658, + 48.66648, + 394.7 + ], + [ + -122.852682, + 48.666505, + 395 + ], + [ + -122.852714, + 48.666531, + 395.2 + ], + [ + -122.852739, + 48.666554, + 395.4 + ], + [ + -122.852764, + 48.66653, + 394.3 + ], + [ + -122.852775, + 48.666497, + 393 + ], + [ + -122.852821, + 48.666498, + 391.9 + ], + [ + -122.852871, + 48.66649, + 390.4 + ], + [ + -122.852912, + 48.666513, + 390 + ], + [ + -122.852937, + 48.666539, + 389.9 + ], + [ + -122.852979, + 48.666529, + 388.5 + ], + [ + -122.853021, + 48.666544, + 387.8 + ], + [ + -122.853042, + 48.666568, + 387.9 + ], + [ + -122.853072, + 48.666593, + 388 + ], + [ + -122.853111, + 48.666605, + 387.7 + ], + [ + -122.853149, + 48.666615, + 387.3 + ], + [ + -122.853163, + 48.666649, + 388 + ], + [ + -122.853206, + 48.666665, + 388 + ], + [ + -122.853255, + 48.666666, + 386.9 + ], + [ + -122.853301, + 48.666661, + 385.7 + ], + [ + -122.853344, + 48.666655, + 384.7 + ], + [ + -122.853382, + 48.666675, + 384.5 + ], + [ + -122.853415, + 48.666701, + 384.7 + ], + [ + -122.853467, + 48.666713, + 384 + ], + [ + -122.853513, + 48.666694, + 382.4 + ], + [ + -122.853545, + 48.666715, + 382.1 + ], + [ + -122.853564, + 48.666746, + 382.4 + ], + [ + -122.853591, + 48.666767, + 381.9 + ], + [ + -122.853647, + 48.666767, + 380.5 + ], + [ + -122.853681, + 48.666784, + 379.9 + ], + [ + -122.85371, + 48.666806, + 379.7 + ], + [ + -122.853752, + 48.666798, + 378.9 + ], + [ + -122.853785, + 48.666781, + 377.8 + ], + [ + -122.853812, + 48.666754, + 375.7 + ], + [ + -122.853818, + 48.666787, + 377.1 + ], + [ + -122.85382, + 48.666817, + 378.1 + ], + [ + -122.853824, + 48.666844, + 378.7 + ], + [ + -122.853816, + 48.666882, + 380.1 + ], + [ + -122.853792, + 48.666914, + 381.5 + ], + [ + -122.853759, + 48.66689, + 380.9 + ], + [ + -122.853734, + 48.666867, + 380.8 + ], + [ + -122.853692, + 48.666865, + 381.3 + ], + [ + -122.853644, + 48.666857, + 382.4 + ], + [ + -122.853586, + 48.666852, + 384 + ], + [ + -122.853543, + 48.666842, + 385.1 + ], + [ + -122.853558, + 48.666814, + 384 + ], + [ + -122.85351, + 48.666805, + 385.2 + ], + [ + -122.853476, + 48.666784, + 385.5 + ], + [ + -122.853461, + 48.666757, + 385.3 + ], + [ + -122.853469, + 48.666728, + 384.3 + ], + [ + -122.853466, + 48.666699, + 383.6 + ], + [ + -122.853463, + 48.666671, + 382.8 + ], + [ + -122.853459, + 48.666642, + 381.8 + ], + [ + -122.853442, + 48.666615, + 381.3 + ], + [ + -122.85344, + 48.666586, + 380.3 + ], + [ + -122.853443, + 48.666559, + 379.2 + ], + [ + -122.853452, + 48.666531, + 377.9 + ], + [ + -122.853448, + 48.666493, + 377 + ], + [ + -122.853434, + 48.666461, + 376.5 + ], + [ + -122.853425, + 48.666433, + 376 + ], + [ + -122.853444, + 48.666409, + 374.8 + ], + [ + -122.853471, + 48.666381, + 373.6 + ], + [ + -122.853505, + 48.666357, + 372.5 + ], + [ + -122.853535, + 48.666337, + 371.6 + ], + [ + -122.85354, + 48.666308, + 370.9 + ], + [ + -122.853517, + 48.666282, + 370.6 + ], + [ + -122.853486, + 48.666261, + 370.4 + ], + [ + -122.853442, + 48.666246, + 371 + ], + [ + -122.853411, + 48.666224, + 371.1 + ], + [ + -122.853392, + 48.666197, + 370.9 + ], + [ + -122.853364, + 48.666171, + 370.9 + ], + [ + -122.853379, + 48.666142, + 369.5 + ], + [ + -122.85339, + 48.666111, + 368.4 + ], + [ + -122.853371, + 48.66608, + 368.1 + ], + [ + -122.853344, + 48.666049, + 368 + ], + [ + -122.853327, + 48.666021, + 367.3 + ], + [ + -122.853303, + 48.665995, + 366.9 + ], + [ + -122.853259, + 48.66599, + 367.4 + ], + [ + -122.853251, + 48.665963, + 366.8 + ], + [ + -122.853216, + 48.665929, + 366.3 + ], + [ + -122.853185, + 48.6659, + 365.6 + ], + [ + -122.853173, + 48.665873, + 364.7 + ], + [ + -122.853133, + 48.665864, + 365 + ], + [ + -122.853135, + 48.665834, + 364.3 + ], + [ + -122.853132, + 48.665806, + 363.9 + ], + [ + -122.85309, + 48.665789, + 364.4 + ], + [ + -122.853068, + 48.665758, + 364 + ], + [ + -122.85305, + 48.665726, + 363.3 + ], + [ + -122.853037, + 48.665695, + 362.1 + ], + [ + -122.852998, + 48.665674, + 362.2 + ], + [ + -122.852998, + 48.665635, + 360.7 + ], + [ + -122.852991, + 48.665608, + 359.8 + ], + [ + -122.853024, + 48.665575, + 358 + ], + [ + -122.853046, + 48.665549, + 356.7 + ], + [ + -122.853078, + 48.665525, + 355.4 + ], + [ + -122.853113, + 48.665504, + 354.1 + ], + [ + -122.85314, + 48.66548, + 352.7 + ], + [ + -122.853174, + 48.665455, + 351 + ], + [ + -122.853204, + 48.665436, + 349.8 + ], + [ + -122.853254, + 48.665438, + 349 + ], + [ + -122.853298, + 48.66543, + 347.9 + ], + [ + -122.853338, + 48.665438, + 347.5 + ], + [ + -122.853382, + 48.665448, + 346.8 + ], + [ + -122.853429, + 48.665459, + 346.4 + ], + [ + -122.853485, + 48.66546, + 345.4 + ], + [ + -122.853535, + 48.665455, + 344.2 + ], + [ + -122.853575, + 48.665465, + 342.8 + ], + [ + -122.85361, + 48.665481, + 341.6 + ], + [ + -122.853641, + 48.665506, + 341.5 + ], + [ + -122.853683, + 48.66552, + 341.6 + ], + [ + -122.853735, + 48.665531, + 341 + ], + [ + -122.85378, + 48.665544, + 340.2 + ], + [ + -122.85381, + 48.665568, + 340.3 + ], + [ + -122.853875, + 48.665575, + 338.3 + ], + [ + -122.853866, + 48.665603, + 339.6 + ], + [ + -122.853901, + 48.665626, + 339 + ], + [ + -122.853947, + 48.665631, + 337.4 + ], + [ + -122.853988, + 48.665639, + 336.4 + ], + [ + -122.854022, + 48.665658, + 335.7 + ], + [ + -122.854068, + 48.66567, + 334.8 + ], + [ + -122.8541, + 48.665698, + 334.9 + ], + [ + -122.854096, + 48.665732, + 335.7 + ], + [ + -122.854094, + 48.665762, + 336.5 + ], + [ + -122.854074, + 48.665787, + 337.9 + ], + [ + -122.854052, + 48.665758, + 337.6 + ], + [ + -122.854011, + 48.665747, + 338.8 + ], + [ + -122.853966, + 48.66574, + 340.1 + ], + [ + -122.853922, + 48.665732, + 341.3 + ], + [ + -122.853912, + 48.665695, + 340.5 + ], + [ + -122.853907, + 48.665665, + 339.9 + ], + [ + -122.85391, + 48.665638, + 339 + ], + [ + -122.853918, + 48.665604, + 337.7 + ], + [ + -122.853917, + 48.66557, + 336.6 + ], + [ + -122.853935, + 48.665544, + 335.6 + ], + [ + -122.853914, + 48.665514, + 334.7 + ], + [ + -122.853895, + 48.665481, + 334 + ], + [ + -122.853897, + 48.665446, + 332.5 + ], + [ + -122.853922, + 48.665413, + 330.2 + ], + [ + -122.853932, + 48.665385, + 329.1 + ], + [ + -122.853897, + 48.66537, + 329.2 + ], + [ + -122.853872, + 48.665344, + 328.6 + ], + [ + -122.85388, + 48.665304, + 327.2 + ], + [ + -122.853856, + 48.665272, + 327.3 + ], + [ + -122.85385, + 48.665244, + 326.9 + ], + [ + -122.853832, + 48.665216, + 326.9 + ], + [ + -122.853833, + 48.665185, + 326.3 + ], + [ + -122.853837, + 48.665156, + 325.9 + ], + [ + -122.853826, + 48.665118, + 325.2 + ], + [ + -122.853839, + 48.665091, + 323.9 + ], + [ + -122.853867, + 48.66507, + 322.7 + ], + [ + -122.853896, + 48.665041, + 321.3 + ], + [ + -122.853916, + 48.665068, + 322 + ], + [ + -122.853917, + 48.665102, + 322.9 + ], + [ + -122.853964, + 48.665107, + 322.5 + ], + [ + -122.854063, + 48.665088, + 319.7 + ], + [ + -122.854034, + 48.66511, + 320.3 + ], + [ + -122.854048, + 48.665069, + 320.1 + ], + [ + -122.854062, + 48.665038, + 319.6 + ], + [ + -122.854076, + 48.664991, + 318.1 + ], + [ + -122.854048, + 48.664957, + 317.3 + ], + [ + -122.853998, + 48.664967, + 318.3 + ], + [ + -122.854004, + 48.664935, + 316.8 + ], + [ + -122.853959, + 48.664937, + 317 + ], + [ + -122.853908, + 48.664943, + 317.4 + ], + [ + -122.853877, + 48.664916, + 317 + ], + [ + -122.853848, + 48.664891, + 316.9 + ], + [ + -122.853807, + 48.664883, + 318 + ], + [ + -122.853784, + 48.664861, + 318.4 + ], + [ + -122.85375, + 48.664844, + 319.3 + ], + [ + -122.853774, + 48.664822, + 318 + ], + [ + -122.853793, + 48.664794, + 316.6 + ], + [ + -122.853826, + 48.664773, + 314.9 + ], + [ + -122.853875, + 48.664768, + 313.5 + ], + [ + -122.853915, + 48.664755, + 312.2 + ], + [ + -122.853933, + 48.664727, + 311 + ], + [ + -122.853963, + 48.664698, + 309.5 + ], + [ + -122.854004, + 48.664689, + 308.4 + ], + [ + -122.854035, + 48.664668, + 307 + ], + [ + -122.854013, + 48.664644, + 306.8 + ], + [ + -122.853973, + 48.664649, + 307.7 + ], + [ + -122.85393, + 48.664657, + 308.6 + ], + [ + -122.853877, + 48.664659, + 309.9 + ], + [ + -122.853859, + 48.664633, + 309.5 + ], + [ + -122.85387, + 48.664604, + 308.2 + ], + [ + -122.853883, + 48.66457, + 306.6 + ], + [ + -122.853872, + 48.664539, + 306 + ], + [ + -122.853849, + 48.664507, + 305.9 + ], + [ + -122.853838, + 48.664467, + 304.9 + ], + [ + -122.853852, + 48.664439, + 303.5 + ], + [ + -122.853879, + 48.664415, + 301.9 + ], + [ + -122.853875, + 48.664383, + 300.9 + ], + [ + -122.853882, + 48.664346, + 299.6 + ], + [ + -122.853894, + 48.664315, + 298.3 + ], + [ + -122.853899, + 48.664287, + 297.6 + ], + [ + -122.853905, + 48.664252, + 297.1 + ], + [ + -122.853919, + 48.664222, + 296.3 + ], + [ + -122.853926, + 48.664181, + 295.7 + ], + [ + -122.853955, + 48.664142, + 294.8 + ], + [ + -122.853997, + 48.664122, + 293.6 + ], + [ + -122.854036, + 48.664112, + 292.4 + ], + [ + -122.854067, + 48.664091, + 291.2 + ], + [ + -122.854034, + 48.664061, + 291.6 + ], + [ + -122.854042, + 48.664029, + 291.1 + ], + [ + -122.85406, + 48.664001, + 290.5 + ], + [ + -122.854092, + 48.663972, + 289.4 + ], + [ + -122.854108, + 48.663941, + 289 + ], + [ + -122.854127, + 48.663915, + 288.7 + ], + [ + -122.854143, + 48.663887, + 288.5 + ], + [ + -122.854175, + 48.663853, + 288.2 + ], + [ + -122.854209, + 48.663829, + 288 + ], + [ + -122.854254, + 48.663809, + 287.5 + ], + [ + -122.854311, + 48.66379, + 287.4 + ], + [ + -122.854366, + 48.663773, + 287.7 + ], + [ + -122.854412, + 48.663764, + 288.1 + ], + [ + -122.854463, + 48.663762, + 288.8 + ], + [ + -122.854507, + 48.663772, + 289.2 + ], + [ + -122.854536, + 48.663792, + 289.3 + ], + [ + -122.854598, + 48.663789, + 289.4 + ], + [ + -122.854641, + 48.663781, + 289.1 + ], + [ + -122.854683, + 48.663773, + 287.7 + ], + [ + -122.854727, + 48.66377, + 286.2 + ], + [ + -122.854778, + 48.663774, + 285.2 + ], + [ + -122.854803, + 48.663802, + 284.7 + ], + [ + -122.854824, + 48.663829, + 284.3 + ], + [ + -122.854874, + 48.663843, + 283.1 + ], + [ + -122.854935, + 48.66385, + 281.8 + ], + [ + -122.854971, + 48.663867, + 281.4 + ], + [ + -122.855013, + 48.663877, + 281.2 + ], + [ + -122.85507, + 48.66388, + 281 + ], + [ + -122.855113, + 48.663877, + 280.5 + ], + [ + -122.855155, + 48.663877, + 279.7 + ], + [ + -122.8552, + 48.663883, + 278.9 + ], + [ + -122.855249, + 48.663908, + 278.8 + ], + [ + -122.855272, + 48.663932, + 278.9 + ], + [ + -122.85528, + 48.663962, + 279.4 + ], + [ + -122.855312, + 48.663985, + 279.5 + ], + [ + -122.855361, + 48.663982, + 278.9 + ], + [ + -122.855329, + 48.664005, + 279.7 + ], + [ + -122.855265, + 48.664021, + 281 + ], + [ + -122.855236, + 48.664, + 280.8 + ], + [ + -122.855221, + 48.663974, + 280.2 + ], + [ + -122.855219, + 48.663944, + 279.6 + ], + [ + -122.855216, + 48.663913, + 279.2 + ], + [ + -122.855224, + 48.66387, + 278.5 + ], + [ + -122.855239, + 48.663838, + 278 + ], + [ + -122.855242, + 48.66381, + 277.5 + ], + [ + -122.855236, + 48.663779, + 277.1 + ], + [ + -122.855215, + 48.663749, + 276.6 + ], + [ + -122.855208, + 48.663722, + 276.2 + ], + [ + -122.855173, + 48.663696, + 275.8 + ], + [ + -122.855158, + 48.663668, + 275.7 + ], + [ + -122.855125, + 48.663646, + 275.7 + ], + [ + -122.855088, + 48.663618, + 275.9 + ], + [ + -122.855063, + 48.663588, + 275.9 + ], + [ + -122.855059, + 48.663552, + 275.3 + ], + [ + -122.855022, + 48.663539, + 275.6 + ], + [ + -122.855011, + 48.663498, + 275 + ], + [ + -122.855015, + 48.663467, + 274.5 + ], + [ + -122.85503, + 48.66342, + 274.2 + ], + [ + -122.85503, + 48.66338, + 274.2 + ], + [ + -122.855034, + 48.66334, + 274.1 + ], + [ + -122.855032, + 48.663304, + 274 + ], + [ + -122.855039, + 48.663277, + 273.6 + ], + [ + -122.855044, + 48.663249, + 273 + ], + [ + -122.855046, + 48.663217, + 272.2 + ], + [ + -122.855, + 48.663213, + 272.5 + ], + [ + -122.854966, + 48.663188, + 272.1 + ], + [ + -122.854915, + 48.663179, + 271.8 + ], + [ + -122.85487, + 48.663168, + 270.1 + ], + [ + -122.854818, + 48.663173, + 269.7 + ], + [ + -122.854774, + 48.663163, + 270.1 + ], + [ + -122.85477, + 48.66312, + 267.2 + ], + [ + -122.854761, + 48.663088, + 266.5 + ], + [ + -122.85473, + 48.663063, + 266.1 + ], + [ + -122.854702, + 48.663037, + 266 + ], + [ + -122.854701, + 48.663009, + 265.5 + ], + [ + -122.854644, + 48.662987, + 266.1 + ], + [ + -122.854617, + 48.662958, + 265.9 + ], + [ + -122.854577, + 48.662944, + 266.5 + ], + [ + -122.854577, + 48.662912, + 265.3 + ], + [ + -122.854574, + 48.662872, + 264.3 + ], + [ + -122.854575, + 48.662833, + 264.1 + ], + [ + -122.854585, + 48.662802, + 264.4 + ], + [ + -122.854568, + 48.662775, + 264.4 + ], + [ + -122.854521, + 48.662785, + 263.4 + ], + [ + -122.854467, + 48.662785, + 263.9 + ], + [ + -122.854455, + 48.662756, + 263.4 + ], + [ + -122.854423, + 48.662725, + 262.8 + ], + [ + -122.854399, + 48.662698, + 262.8 + ], + [ + -122.854357, + 48.662702, + 262.7 + ], + [ + -122.854319, + 48.662712, + 263.5 + ], + [ + -122.854261, + 48.662708, + 264.8 + ], + [ + -122.854216, + 48.662708, + 266.3 + ], + [ + -122.854158, + 48.662725, + 269 + ], + [ + -122.854112, + 48.662721, + 270.2 + ], + [ + -122.854085, + 48.662693, + 269.2 + ], + [ + -122.854076, + 48.662652, + 266.6 + ], + [ + -122.854081, + 48.662613, + 263.6 + ], + [ + -122.854082, + 48.662583, + 261.8 + ], + [ + -122.854086, + 48.662546, + 261.5 + ], + [ + -122.854087, + 48.662517, + 262.6 + ], + [ + -122.854086, + 48.662474, + 263.1 + ], + [ + -122.854087, + 48.662424, + 261.7 + ], + [ + -122.85409, + 48.662397, + 260.1 + ], + [ + -122.854085, + 48.662363, + 257.6 + ], + [ + -122.854078, + 48.662327, + 254.5 + ], + [ + -122.854074, + 48.662294, + 252 + ], + [ + -122.85407, + 48.662262, + 249.8 + ], + [ + -122.854068, + 48.662228, + 247.6 + ], + [ + -122.854078, + 48.662189, + 245.7 + ], + [ + -122.854116, + 48.662173, + 246 + ], + [ + -122.854153, + 48.662153, + 246.1 + ], + [ + -122.854194, + 48.662136, + 246.6 + ], + [ + -122.854232, + 48.662115, + 246.6 + ], + [ + -122.854275, + 48.662101, + 247.4 + ], + [ + -122.854319, + 48.66209, + 248.4 + ], + [ + -122.854361, + 48.662075, + 248.9 + ], + [ + -122.854407, + 48.662062, + 249.5 + ], + [ + -122.854442, + 48.662038, + 249.2 + ], + [ + -122.854468, + 48.662016, + 248.9 + ], + [ + -122.854503, + 48.661988, + 248.5 + ], + [ + -122.854543, + 48.661972, + 249 + ], + [ + -122.854588, + 48.661965, + 250 + ], + [ + -122.854622, + 48.661988, + 251.8 + ], + [ + -122.854626, + 48.662016, + 252.9 + ], + [ + -122.854595, + 48.662059, + 253.7 + ], + [ + -122.854579, + 48.662094, + 254.8 + ], + [ + -122.854547, + 48.662124, + 255.9 + ], + [ + -122.85451, + 48.662148, + 257 + ], + [ + -122.854469, + 48.662163, + 257 + ], + [ + -122.854435, + 48.662187, + 257.9 + ], + [ + -122.854403, + 48.662211, + 259.2 + ], + [ + -122.854354, + 48.662219, + 258.6 + ], + [ + -122.854315, + 48.66219, + 254.5 + ], + [ + -122.854308, + 48.662145, + 251.1 + ], + [ + -122.854295, + 48.662113, + 248.7 + ], + [ + -122.854318, + 48.662087, + 248.2 + ], + [ + -122.854337, + 48.662045, + 246.8 + ], + [ + -122.854363, + 48.662015, + 246.2 + ], + [ + -122.854398, + 48.661988, + 245.9 + ], + [ + -122.854425, + 48.661962, + 245.6 + ], + [ + -122.854452, + 48.661926, + 244.7 + ], + [ + -122.854478, + 48.661894, + 244 + ], + [ + -122.854509, + 48.661857, + 242.9 + ], + [ + -122.854546, + 48.661839, + 242.9 + ], + [ + -122.854585, + 48.661811, + 242.4 + ], + [ + -122.85461, + 48.661777, + 241.5 + ], + [ + -122.854606, + 48.661746, + 239.8 + ], + [ + -122.854566, + 48.661738, + 238.4 + ], + [ + -122.854579, + 48.661707, + 237.5 + ], + [ + -122.854607, + 48.661679, + 237.2 + ], + [ + -122.854636, + 48.661642, + 236.4 + ], + [ + -122.854659, + 48.661618, + 236 + ], + [ + -122.854685, + 48.661593, + 235.7 + ], + [ + -122.85475, + 48.661575, + 236.3 + ], + [ + -122.854788, + 48.661567, + 236.6 + ], + [ + -122.854809, + 48.661532, + 235.8 + ], + [ + -122.854831, + 48.661503, + 235.4 + ], + [ + -122.854864, + 48.661476, + 235.2 + ], + [ + -122.854898, + 48.66146, + 235.5 + ], + [ + -122.854935, + 48.661436, + 235.7 + ], + [ + -122.85497, + 48.661397, + 235.1 + ], + [ + -122.854978, + 48.66137, + 234.6 + ], + [ + -122.854985, + 48.661342, + 234.3 + ], + [ + -122.855018, + 48.661319, + 234.3 + ], + [ + -122.855033, + 48.661262, + 234 + ], + [ + -122.855037, + 48.661246, + 234.1 + ], + [ + -122.855057, + 48.661217, + 234.2 + ], + [ + -122.855094, + 48.661182, + 234 + ], + [ + -122.855116, + 48.661159, + 233.8 + ], + [ + -122.855134, + 48.661127, + 233.6 + ], + [ + -122.855154, + 48.661102, + 233.4 + ], + [ + -122.855181, + 48.661077, + 232.9 + ], + [ + -122.855208, + 48.661055, + 232.4 + ], + [ + -122.855233, + 48.661033, + 231.6 + ], + [ + -122.855268, + 48.661008, + 230.5 + ], + [ + -122.855284, + 48.660975, + 229.9 + ], + [ + -122.855308, + 48.660952, + 229.1 + ], + [ + -122.85534, + 48.660929, + 228.1 + ], + [ + -122.855382, + 48.660903, + 226.8 + ], + [ + -122.855404, + 48.660879, + 226 + ], + [ + -122.855443, + 48.660849, + 224.3 + ], + [ + -122.855473, + 48.660828, + 222.9 + ], + [ + -122.855541, + 48.66081, + 221.2 + ], + [ + -122.855582, + 48.660793, + 220.5 + ], + [ + -122.855596, + 48.66076, + 219.3 + ], + [ + -122.855613, + 48.660724, + 218.6 + ], + [ + -122.855642, + 48.6607, + 218.4 + ], + [ + -122.855678, + 48.660661, + 217.7 + ], + [ + -122.855707, + 48.660641, + 217 + ], + [ + -122.855705, + 48.660605, + 215.7 + ], + [ + -122.855704, + 48.660574, + 214.9 + ], + [ + -122.855726, + 48.66055, + 214.3 + ], + [ + -122.855749, + 48.660527, + 213.8 + ], + [ + -122.855764, + 48.6605, + 213.6 + ], + [ + -122.855781, + 48.66047, + 213.5 + ], + [ + -122.855783, + 48.660441, + 213.5 + ], + [ + -122.855802, + 48.6604, + 213.2 + ], + [ + -122.855814, + 48.660362, + 212.8 + ], + [ + -122.855836, + 48.66033, + 212.6 + ], + [ + -122.855877, + 48.660321, + 212.5 + ], + [ + -122.855929, + 48.660309, + 212.4 + ], + [ + -122.855957, + 48.660284, + 211.9 + ], + [ + -122.855986, + 48.660247, + 211.3 + ], + [ + -122.856012, + 48.660215, + 210.6 + ], + [ + -122.856045, + 48.660186, + 209.7 + ], + [ + -122.856078, + 48.660166, + 208.9 + ], + [ + -122.856132, + 48.660144, + 208.5 + ], + [ + -122.856182, + 48.660133, + 208.4 + ], + [ + -122.856226, + 48.660112, + 208.4 + ], + [ + -122.856289, + 48.660084, + 208.8 + ], + [ + -122.856326, + 48.660071, + 209.3 + ], + [ + -122.856366, + 48.660065, + 210.1 + ], + [ + -122.856417, + 48.660057, + 210.7 + ], + [ + -122.85646, + 48.660055, + 210.5 + ], + [ + -122.856518, + 48.660054, + 209.1 + ], + [ + -122.856587, + 48.660055, + 206.7 + ], + [ + -122.856635, + 48.660054, + 205.4 + ], + [ + -122.856692, + 48.660054, + 204.8 + ], + [ + -122.856742, + 48.66006, + 205.4 + ], + [ + -122.856785, + 48.660037, + 204.9 + ], + [ + -122.856789, + 48.660071, + 206.3 + ], + [ + -122.856811, + 48.660096, + 207.4 + ], + [ + -122.856786, + 48.660126, + 208.5 + ], + [ + -122.856755, + 48.660153, + 209.2 + ], + [ + -122.856708, + 48.660165, + 209.5 + ], + [ + -122.856659, + 48.660172, + 209.6 + ], + [ + -122.856594, + 48.660176, + 210 + ], + [ + -122.856532, + 48.660175, + 210.9 + ], + [ + -122.856489, + 48.660173, + 211.2 + ], + [ + -122.856449, + 48.660163, + 211 + ], + [ + -122.856405, + 48.660146, + 210.6 + ], + [ + -122.856392, + 48.660114, + 209.9 + ], + [ + -122.856404, + 48.660078, + 210.4 + ], + [ + -122.856415, + 48.660046, + 210.9 + ], + [ + -122.856428, + 48.660012, + 211.3 + ], + [ + -122.856447, + 48.659985, + 211.3 + ], + [ + -122.856473, + 48.659963, + 211.2 + ], + [ + -122.856453, + 48.65993, + 211.4 + ], + [ + -122.856417, + 48.659913, + 211.6 + ], + [ + -122.85641, + 48.659881, + 211.2 + ], + [ + -122.856405, + 48.659842, + 210.2 + ], + [ + -122.856387, + 48.659812, + 209.9 + ], + [ + -122.85637, + 48.659786, + 209.6 + ], + [ + -122.856366, + 48.659759, + 208.9 + ], + [ + -122.856334, + 48.659733, + 208.3 + ], + [ + -122.856292, + 48.659721, + 207.9 + ], + [ + -122.85625, + 48.659714, + 207.6 + ], + [ + -122.856208, + 48.65971, + 207.5 + ], + [ + -122.856167, + 48.659685, + 207 + ], + [ + -122.856134, + 48.659652, + 206.1 + ], + [ + -122.856104, + 48.659626, + 205.5 + ], + [ + -122.856057, + 48.659606, + 205.1 + ], + [ + -122.856011, + 48.659602, + 205.4 + ], + [ + -122.855958, + 48.659599, + 205.8 + ], + [ + -122.855911, + 48.659595, + 206.2 + ], + [ + -122.855867, + 48.659572, + 205.9 + ], + [ + -122.855822, + 48.659562, + 205.5 + ], + [ + -122.855782, + 48.659551, + 205.2 + ], + [ + -122.855727, + 48.659557, + 205.5 + ], + [ + -122.855684, + 48.659559, + 205.5 + ], + [ + -122.855639, + 48.659564, + 205.1 + ], + [ + -122.855592, + 48.65957, + 204.6 + ], + [ + -122.855545, + 48.65957, + 204 + ], + [ + -122.855503, + 48.659581, + 204 + ], + [ + -122.855451, + 48.65959, + 204 + ], + [ + -122.855409, + 48.659569, + 203.5 + ], + [ + -122.855374, + 48.659553, + 202.7 + ], + [ + -122.855324, + 48.659542, + 202.1 + ], + [ + -122.855287, + 48.659555, + 202.9 + ], + [ + -122.855246, + 48.65956, + 202.9 + ], + [ + -122.855202, + 48.659571, + 203 + ], + [ + -122.855163, + 48.659586, + 203.1 + ], + [ + -122.855116, + 48.659607, + 203.1 + ], + [ + -122.855072, + 48.659616, + 202.5 + ], + [ + -122.855021, + 48.659624, + 202.1 + ], + [ + -122.854972, + 48.659635, + 202.1 + ], + [ + -122.854938, + 48.659653, + 202.7 + ], + [ + -122.854904, + 48.65967, + 203.1 + ], + [ + -122.854871, + 48.65969, + 203.3 + ], + [ + -122.854818, + 48.659695, + 201.5 + ], + [ + -122.854772, + 48.6597, + 199.8 + ], + [ + -122.854739, + 48.659678, + 198 + ], + [ + -122.854705, + 48.659654, + 196.2 + ], + [ + -122.854682, + 48.659631, + 195 + ], + [ + -122.854639, + 48.659612, + 194.1 + ], + [ + -122.854592, + 48.659604, + 195.5 + ], + [ + -122.854549, + 48.659593, + 197.3 + ], + [ + -122.854519, + 48.659574, + 198.3 + ], + [ + -122.854486, + 48.659545, + 197.5 + ], + [ + -122.85444, + 48.659532, + 196.8 + ], + [ + -122.854391, + 48.659519, + 196 + ], + [ + -122.854343, + 48.659494, + 195.1 + ], + [ + -122.854304, + 48.659463, + 193.8 + ], + [ + -122.854264, + 48.659454, + 193.3 + ], + [ + -122.854214, + 48.659461, + 193.1 + ], + [ + -122.854172, + 48.659472, + 193.1 + ], + [ + -122.854136, + 48.659487, + 193.2 + ], + [ + -122.854095, + 48.659481, + 192.8 + ], + [ + -122.854068, + 48.659455, + 192.4 + ], + [ + -122.85403, + 48.659439, + 192.5 + ], + [ + -122.853975, + 48.659425, + 192.6 + ], + [ + -122.853932, + 48.659417, + 192.7 + ], + [ + -122.853876, + 48.659412, + 192.4 + ], + [ + -122.853837, + 48.659398, + 191.8 + ], + [ + -122.853795, + 48.659383, + 191.5 + ], + [ + -122.853754, + 48.659364, + 191.5 + ], + [ + -122.853719, + 48.659346, + 192.1 + ], + [ + -122.853688, + 48.659323, + 192.5 + ], + [ + -122.853669, + 48.659293, + 192.2 + ], + [ + -122.853676, + 48.65926, + 191.6 + ], + [ + -122.853688, + 48.65922, + 191 + ], + [ + -122.853664, + 48.659191, + 189.9 + ], + [ + -122.853635, + 48.659163, + 188.6 + ], + [ + -122.853634, + 48.659131, + 187.3 + ], + [ + -122.853624, + 48.659102, + 186.3 + ], + [ + -122.853582, + 48.659102, + 186.5 + ], + [ + -122.853568, + 48.659067, + 185.4 + ], + [ + -122.853536, + 48.659051, + 185.4 + ], + [ + -122.853493, + 48.659032, + 185 + ], + [ + -122.853457, + 48.659018, + 184.7 + ], + [ + -122.853416, + 48.65901, + 184.6 + ], + [ + -122.853387, + 48.658991, + 184.1 + ], + [ + -122.853359, + 48.65897, + 183.7 + ], + [ + -122.853338, + 48.658941, + 183.2 + ], + [ + -122.8533, + 48.658919, + 183.3 + ], + [ + -122.853289, + 48.658885, + 182.9 + ], + [ + -122.853268, + 48.658854, + 182.8 + ], + [ + -122.853229, + 48.658832, + 183.6 + ], + [ + -122.853224, + 48.658802, + 183.5 + ], + [ + -122.853253, + 48.658768, + 182.5 + ], + [ + -122.853276, + 48.658741, + 181.6 + ], + [ + -122.853262, + 48.658711, + 181.7 + ], + [ + -122.853235, + 48.65869, + 181.8 + ], + [ + -122.853187, + 48.658695, + 182.6 + ], + [ + -122.853146, + 48.658692, + 182.8 + ], + [ + -122.853125, + 48.658667, + 182.1 + ], + [ + -122.853116, + 48.658634, + 181.2 + ], + [ + -122.853126, + 48.658605, + 180.1 + ], + [ + -122.853104, + 48.658576, + 179.2 + ], + [ + -122.853068, + 48.658551, + 178.8 + ], + [ + -122.853037, + 48.658521, + 178.2 + ], + [ + -122.852996, + 48.658512, + 178.7 + ], + [ + -122.852943, + 48.658512, + 179.7 + ], + [ + -122.852902, + 48.658501, + 179.9 + ], + [ + -122.852871, + 48.658483, + 179.6 + ], + [ + -122.852829, + 48.65848, + 180.3 + ], + [ + -122.852796, + 48.658461, + 179.7 + ], + [ + -122.852765, + 48.658431, + 178.2 + ], + [ + -122.852732, + 48.658402, + 176.6 + ], + [ + -122.852686, + 48.658389, + 175.9 + ], + [ + -122.852656, + 48.658366, + 174.4 + ], + [ + -122.852627, + 48.658343, + 172.9 + ], + [ + -122.852561, + 48.658331, + 172.5 + ], + [ + -122.852521, + 48.658309, + 171.3 + ], + [ + -122.85249, + 48.658283, + 170.1 + ], + [ + -122.852464, + 48.658261, + 169.3 + ], + [ + -122.852461, + 48.658222, + 168.4 + ], + [ + -122.852435, + 48.658194, + 168.5 + ], + [ + -122.8524, + 48.658161, + 168.8 + ], + [ + -122.852373, + 48.65812, + 168.8 + ], + [ + -122.852377, + 48.658088, + 168.7 + ], + [ + -122.852346, + 48.658061, + 169.3 + ], + [ + -122.852373, + 48.658037, + 169 + ], + [ + -122.852402, + 48.658013, + 168.5 + ], + [ + -122.852463, + 48.658, + 167.7 + ], + [ + -122.852522, + 48.657996, + 167 + ], + [ + -122.852583, + 48.657996, + 166.6 + ], + [ + -122.852638, + 48.657987, + 166.1 + ], + [ + -122.852692, + 48.657988, + 165.1 + ], + [ + -122.852748, + 48.657982, + 164.2 + ], + [ + -122.852792, + 48.657974, + 163.7 + ], + [ + -122.852835, + 48.657961, + 163.2 + ], + [ + -122.852882, + 48.657957, + 162.7 + ], + [ + -122.852924, + 48.657945, + 162.7 + ], + [ + -122.852954, + 48.657919, + 163.1 + ], + [ + -122.852973, + 48.657893, + 163.2 + ], + [ + -122.853022, + 48.657886, + 162.6 + ], + [ + -122.853062, + 48.657872, + 162.5 + ], + [ + -122.853096, + 48.657853, + 162.7 + ], + [ + -122.853145, + 48.657828, + 162.6 + ], + [ + -122.85317, + 48.657814, + 162.2 + ], + [ + -122.853175, + 48.657782, + 162.6 + ], + [ + -122.85322, + 48.657771, + 161.3 + ], + [ + -122.853258, + 48.657744, + 160.2 + ], + [ + -122.853258, + 48.657715, + 160.1 + ], + [ + -122.853289, + 48.657696, + 158.8 + ], + [ + -122.853323, + 48.657675, + 157.4 + ], + [ + -122.853373, + 48.657662, + 155.6 + ], + [ + -122.853385, + 48.657625, + 155.3 + ], + [ + -122.853395, + 48.65758, + 154.9 + ], + [ + -122.853395, + 48.657534, + 154.7 + ], + [ + -122.853397, + 48.657502, + 154.7 + ], + [ + -122.853443, + 48.657507, + 153.8 + ], + [ + -122.85347, + 48.657484, + 153.1 + ], + [ + -122.853497, + 48.657454, + 152.8 + ], + [ + -122.853552, + 48.657439, + 151.8 + ], + [ + -122.853593, + 48.657426, + 150.6 + ], + [ + -122.853611, + 48.657394, + 150.5 + ], + [ + -122.853618, + 48.657364, + 150.5 + ], + [ + -122.853626, + 48.657337, + 150.6 + ], + [ + -122.853648, + 48.657313, + 150.2 + ], + [ + -122.853666, + 48.657285, + 149.8 + ], + [ + -122.85369, + 48.657255, + 149.2 + ], + [ + -122.853724, + 48.657236, + 148.1 + ], + [ + -122.853762, + 48.657197, + 147.1 + ], + [ + -122.853803, + 48.657176, + 146.1 + ], + [ + -122.853835, + 48.657151, + 145.3 + ], + [ + -122.853885, + 48.657152, + 142.9 + ], + [ + -122.85391, + 48.657188, + 141.4 + ], + [ + -122.853939, + 48.657212, + 140.2 + ], + [ + -122.853979, + 48.657218, + 138.4 + ], + [ + -122.854021, + 48.657228, + 136.3 + ], + [ + -122.854059, + 48.657262, + 134.2 + ], + [ + -122.854078, + 48.657288, + 132.9 + ], + [ + -122.854093, + 48.657315, + 131.8 + ], + [ + -122.854105, + 48.657341, + 130.8 + ], + [ + -122.854125, + 48.657377, + 129.5 + ], + [ + -122.854136, + 48.657412, + 128.6 + ], + [ + -122.854143, + 48.65744, + 128 + ], + [ + -122.854101, + 48.657444, + 130 + ], + [ + -122.854058, + 48.657447, + 132.2 + ], + [ + -122.85409, + 48.657467, + 130.6 + ], + [ + -122.854103, + 48.657495, + 129.8 + ], + [ + -122.854113, + 48.657529, + 129.1 + ], + [ + -122.854125, + 48.657559, + 128.5 + ], + [ + -122.854164, + 48.657577, + 127 + ], + [ + -122.854203, + 48.657563, + 125.7 + ], + [ + -122.854165, + 48.657574, + 127 + ], + [ + -122.854194, + 48.657593, + 126.3 + ], + [ + -122.854237, + 48.657621, + 126.2 + ], + [ + -122.854279, + 48.657648, + 126.3 + ], + [ + -122.854304, + 48.657675, + 126.7 + ], + [ + -122.854342, + 48.657703, + 125.5 + ], + [ + -122.854377, + 48.657723, + 124.5 + ], + [ + -122.854421, + 48.657747, + 124.6 + ], + [ + -122.85446, + 48.657735, + 124 + ], + [ + -122.854502, + 48.657757, + 124.6 + ], + [ + -122.85455, + 48.657778, + 125.4 + ], + [ + -122.854597, + 48.657804, + 126.2 + ], + [ + -122.854632, + 48.657827, + 126.5 + ], + [ + -122.854603, + 48.657848, + 126.1 + ], + [ + -122.854574, + 48.657872, + 126.3 + ], + [ + -122.854595, + 48.65792, + 127.5 + ], + [ + -122.854562, + 48.657938, + 128.5 + ], + [ + -122.854609, + 48.657955, + 128.5 + ], + [ + -122.85465, + 48.657952, + 127.7 + ], + [ + -122.854661, + 48.657925, + 127.6 + ], + [ + -122.854649, + 48.657896, + 127.1 + ], + [ + -122.854614, + 48.65788, + 126.6 + ], + [ + -122.854576, + 48.657864, + 126.2 + ], + [ + -122.854532, + 48.657866, + 126.3 + ], + [ + -122.854489, + 48.657887, + 127.6 + ], + [ + -122.85444, + 48.657874, + 128.5 + ], + [ + -122.854385, + 48.657861, + 129.8 + ], + [ + -122.854378, + 48.657827, + 128.8 + ], + [ + -122.854406, + 48.65778, + 125.7 + ], + [ + -122.854431, + 48.657729, + 124.1 + ], + [ + -122.854438, + 48.65769, + 123.2 + ], + [ + -122.854428, + 48.657654, + 122.6 + ], + [ + -122.854408, + 48.657625, + 122.3 + ], + [ + -122.854368, + 48.65761, + 122.6 + ], + [ + -122.854366, + 48.657574, + 122.4 + ], + [ + -122.854341, + 48.657539, + 122.9 + ], + [ + -122.854319, + 48.657513, + 123 + ], + [ + -122.854286, + 48.657483, + 123 + ], + [ + -122.85429, + 48.65745, + 122.6 + ], + [ + -122.854306, + 48.657416, + 122.2 + ], + [ + -122.854314, + 48.657388, + 122 + ], + [ + -122.854347, + 48.657343, + 120.9 + ], + [ + -122.854366, + 48.657312, + 120.1 + ], + [ + -122.854379, + 48.657281, + 119.8 + ], + [ + -122.854391, + 48.657233, + 119.6 + ], + [ + -122.854402, + 48.657188, + 119.1 + ], + [ + -122.854408, + 48.657141, + 118.7 + ], + [ + -122.854407, + 48.657105, + 118.4 + ], + [ + -122.854421, + 48.657079, + 118.1 + ], + [ + -122.854448, + 48.657052, + 117.7 + ], + [ + -122.854477, + 48.65703, + 117.5 + ], + [ + -122.854471, + 48.656993, + 117.8 + ], + [ + -122.854492, + 48.656956, + 117.1 + ], + [ + -122.854525, + 48.656938, + 116.6 + ], + [ + -122.854548, + 48.656912, + 116.4 + ], + [ + -122.854569, + 48.656881, + 116 + ], + [ + -122.854595, + 48.65685, + 115.7 + ], + [ + -122.854609, + 48.656824, + 115.5 + ], + [ + -122.854611, + 48.656785, + 115.2 + ], + [ + -122.854615, + 48.65675, + 115 + ], + [ + -122.854619, + 48.656718, + 114.9 + ], + [ + -122.854631, + 48.656685, + 114.8 + ], + [ + -122.854649, + 48.65666, + 114.7 + ], + [ + -122.854691, + 48.656658, + 114.6 + ], + [ + -122.854752, + 48.656673, + 114.5 + ], + [ + -122.85482, + 48.656664, + 114.6 + ] + ], + "type": "LineString" + }, + "properties": { + "name": "Moran State Park Western Boundary Hike", + "time": "2015-04-18T15:51:49Z" + }, + "type": "Feature" + } + ], + "type": "FeatureCollection" +} diff --git a/ios/app/threestates.geojson b/ios/app/threestates.geojson new file mode 100644 index 000000000..9b7038878 --- /dev/null +++ b/ios/app/threestates.geojson @@ -0,0 +1,1612 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "geometry": { + "coordinates": [ + [ + [ + -75.80260539153913, + 39.722485154715464 + ], + [ + -75.76669272327231, + 39.722485154715464 + ], + [ + -75.76669272327231, + 39.765510893789376 + ], + [ + -75.73078005500548, + 39.765510893789376 + ], + [ + -75.73078005500548, + 39.79132633723372 + ], + [ + -75.69486738673865, + 39.79132633723372 + ], + [ + -75.69486738673865, + 39.817141780678064 + ], + [ + -75.623042050205, + 39.834352076307624 + ], + [ + -75.47939137713769, + 39.834352076307624 + ], + [ + -75.44347870887087, + 39.80853663286328 + ], + [ + -75.40756604060404, + 39.80853663286328 + ], + [ + -75.40756604060404, + 39.799931485048496 + ], + [ + -75.44347870887087, + 39.79132633723372 + ], + [ + -75.44347870887087, + 39.765510893789376 + ], + [ + -75.47939137713769, + 39.765510893789376 + ], + [ + -75.47939137713769, + 39.69666971127112 + ], + [ + -75.51530404540452, + 39.69666971127112 + ], + [ + -75.51530404540452, + 39.64503882438243 + ], + [ + -75.55121671367135, + 39.64503882438243 + ], + [ + -75.55121671367135, + 39.593407937493744 + ], + [ + -75.51530404540452, + 39.58480278967896 + ], + [ + -75.51530404540452, + 39.541777050605056 + ], + [ + -75.51530404540452, + 39.498751311531144 + ], + [ + -75.55121671367135, + 39.498751311531144 + ], + [ + -75.55121671367135, + 39.429910129012896 + ], + [ + -75.51530404540452, + 39.429910129012896 + ], + [ + -75.51530404540452, + 39.40409468556855 + ], + [ + -75.47939137713769, + 39.39548953775377 + ], + [ + -75.47939137713769, + 39.369674094309424 + ], + [ + -75.44347870887087, + 39.36106894649464 + ], + [ + -75.44347870887087, + 39.335253503050296 + ], + [ + -75.40756604060404, + 39.335253503050296 + ], + [ + -75.40756604060404, + 39.30943805960595 + ], + [ + -75.33574070407039, + 39.27501746834683 + ], + [ + -75.33574070407039, + 39.24920202490249 + ], + [ + -75.29982803580356, + 39.24920202490249 + ], + [ + -75.29982803580356, + 39.206176285828576 + ], + [ + -75.26391536753674, + 39.188965990199016 + ], + [ + -75.26391536753674, + 39.15454539893989 + ], + [ + -75.22800269926991, + 39.15454539893989 + ], + [ + -75.22800269926991, + 39.111519659865984 + ], + [ + -75.19209003100308, + 39.06849392079207 + ], + [ + -75.15617736273626, + 39.05988877297729 + ], + [ + -75.15617736273626, + 38.999652738273824 + ], + [ + -75.12026469446943, + 38.999652738273824 + ], + [ + -75.12026469446943, + 38.965232147014696 + ], + [ + -75.0843520262026, + 38.91360126012601 + ], + [ + -75.0843520262026, + 38.87918066886688 + ], + [ + -75.04843935793578, + 38.87918066886688 + ], + [ + -75.04843935793578, + 38.836154929792976 + ], + [ + -75.01252668966895, + 38.80173433853385 + ], + [ + -75.01252668966895, + 38.78452404290429 + ], + [ + -75.01252668966895, + 38.612421086608656 + ], + [ + -74.97661402140213, + 38.612421086608656 + ], + [ + -74.97661402140213, + 38.44892327812781 + ], + [ + -75.44347870887087, + 38.44892327812781 + ], + [ + -75.44347870887087, + 38.45752842594259 + ], + [ + -75.69486738673865, + 38.45752842594259 + ], + [ + -75.69486738673865, + 38.69847256475647 + ], + [ + -75.73078005500548, + 38.70707771257125 + ], + [ + -75.73078005500548, + 39.145940251125104 + ], + [ + -75.76669272327231, + 39.15454539893989 + ], + [ + -75.76669272327231, + 39.593407937493744 + ], + [ + -75.80260539153913, + 39.60201308530853 + ], + [ + -75.80260539153913, + 39.722485154715464 + ] + ] + ], + "type": "Polygon" + }, + "properties": { + "NAME": "Delaware" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + [ + [ + -80.50716493449343, + 40.634630823082304 + ], + [ + -80.50716493449343, + 42.32984494259426 + ], + [ + -80.36351426142612, + 42.34705523822382 + ], + [ + -80.18395092009199, + 42.381475829482945 + ], + [ + -80.0762129152915, + 42.39008097729772 + ], + [ + -80.00438757875786, + 42.42450156855685 + ], + [ + -79.7889115691569, + 42.50194789888988 + ], + [ + -79.75299890089008, + 42.51915819451945 + ], + [ + -79.75299890089008, + 42.00284932563255 + ], + [ + -79.53752289128911, + 42.00284932563255 + ], + [ + -79.50161022302228, + 41.99424417781778 + ], + [ + -79.42978488648863, + 42.00284932563255 + ], + [ + -78.96292019901988, + 42.00284932563255 + ], + [ + -78.92700753075306, + 41.99424417781778 + ], + [ + -78.7115315211521, + 41.99424417781778 + ], + [ + -78.7115315211521, + 42.00284932563255 + ], + [ + -77.92145281928191, + 42.00284932563255 + ], + [ + -77.92145281928191, + 41.99424417781778 + ], + [ + -77.81371481448143, + 41.99424417781778 + ], + [ + -77.74188947794778, + 42.00284932563255 + ], + [ + -77.16728678567856, + 42.00284932563255 + ], + [ + -76.37720808380836, + 42.00284932563255 + ], + [ + -76.37720808380836, + 41.99424417781778 + ], + [ + -76.19764474247422, + 41.99424417781778 + ], + [ + -76.1617320742074, + 42.00284932563255 + ], + [ + -75.87443072807278, + 42.00284932563255 + ], + [ + -75.83851805980596, + 41.99424417781778 + ], + [ + -75.65895471847183, + 41.99424417781778 + ], + [ + -75.623042050205, + 42.00284932563255 + ], + [ + -75.37165337233722, + 42.00284932563255 + ], + [ + -75.33574070407039, + 41.99424417781778 + ], + [ + -75.33574070407039, + 41.951218438743865 + ], + [ + -75.26391536753674, + 41.94261329092909 + ], + [ + -75.26391536753674, + 41.865166960596056 + ], + [ + -75.22800269926991, + 41.865166960596056 + ], + [ + -75.19209003100308, + 41.865166960596056 + ], + [ + -75.19209003100308, + 41.87377210841083 + ], + [ + -75.19209003100308, + 41.865166960596056 + ], + [ + -75.19209003100308, + 41.87377210841083 + ], + [ + -75.15617736273626, + 41.87377210841083 + ], + [ + -75.15617736273626, + 41.84795666496649 + ], + [ + -75.12026469446943, + 41.84795666496649 + ], + [ + -75.12026469446943, + 41.822141221522145 + ], + [ + -75.0843520262026, + 41.822141221522145 + ], + [ + -75.0843520262026, + 41.78772063026302 + ], + [ + -75.12026469446943, + 41.77051033463346 + ], + [ + -75.04843935793578, + 41.77051033463346 + ], + [ + -75.04843935793578, + 41.563986787078704 + ], + [ + -75.01252668966895, + 41.563986787078704 + ], + [ + -75.01252668966895, + 41.51235590019001 + ], + [ + -74.97661402140213, + 41.51235590019001 + ], + [ + -74.97661402140213, + 41.47793530893089 + ], + [ + -74.9407013531353, + 41.47793530893089 + ], + [ + -74.90478868486846, + 41.47793530893089 + ], + [ + -74.90478868486846, + 41.43490956985698 + ], + [ + -74.83296334833481, + 41.44351471767176 + ], + [ + -74.79705068006798, + 41.4263044220422 + ], + [ + -74.72522534353433, + 41.43490956985698 + ], + [ + -74.72522534353433, + 41.37467353515351 + ], + [ + -74.6893126752675, + 41.357463239523945 + ], + [ + -74.76113801180117, + 41.34885809170916 + ], + [ + -74.76113801180117, + 41.32304264826482 + ], + [ + -74.79705068006798, + 41.32304264826482 + ], + [ + -74.79705068006798, + 41.29722720482047 + ], + [ + -74.83296334833481, + 41.29722720482047 + ], + [ + -74.83296334833481, + 41.25420146574657 + ], + [ + -74.86887601660165, + 41.25420146574657 + ], + [ + -74.86887601660165, + 41.176755135413536 + ], + [ + -74.90478868486846, + 41.176755135413536 + ], + [ + -74.90478868486846, + 41.14233454415441 + ], + [ + -74.9407013531353, + 41.14233454415441 + ], + [ + -74.9407013531353, + 41.116519100710065 + ], + [ + -74.97661402140213, + 41.099308805080504 + ], + [ + -74.97661402140213, + 41.09070365726572 + ], + [ + -74.97661402140213, + 41.099308805080504 + ], + [ + -74.97661402140213, + 41.09070365726572 + ], + [ + -75.01252668966895, + 41.07349336163616 + ], + [ + -75.01252668966895, + 41.03907277037703 + ], + [ + -75.0843520262026, + 41.004652179117905 + ], + [ + -75.12026469446943, + 41.004652179117905 + ], + [ + -75.12026469446943, + 40.935810996599656 + ], + [ + -75.0843520262026, + 40.935810996599656 + ], + [ + -75.0843520262026, + 40.892785257525745 + ], + [ + -75.04843935793578, + 40.88418010971097 + ], + [ + -75.04843935793578, + 40.84975951845184 + ], + [ + -75.0843520262026, + 40.84975951845184 + ], + [ + -75.0843520262026, + 40.79812863156315 + ], + [ + -75.12026469446943, + 40.79812863156315 + ], + [ + -75.12026469446943, + 40.77231318811881 + ], + [ + -75.15617736273626, + 40.77231318811881 + ], + [ + -75.19209003100308, + 40.77231318811881 + ], + [ + -75.19209003100308, + 40.56578964056405 + ], + [ + -75.12026469446943, + 40.57439478837883 + ], + [ + -75.0843520262026, + 40.56578964056405 + ], + [ + -75.0843520262026, + 40.53136904930492 + ], + [ + -75.04843935793578, + 40.53136904930492 + ], + [ + -75.04843935793578, + 40.471133014601456 + ], + [ + -75.0843520262026, + 40.471133014601456 + ], + [ + -75.0843520262026, + 40.44531757115711 + ], + [ + -75.04843935793578, + 40.44531757115711 + ], + [ + -75.04843935793578, + 40.4022918320832 + ], + [ + -74.97661402140213, + 40.410896979897984 + ], + [ + -74.97661402140213, + 40.38508153645364 + ], + [ + -74.9407013531353, + 40.38508153645364 + ], + [ + -74.9407013531353, + 40.32484550175017 + ], + [ + -74.86887601660165, + 40.30763520612061 + ], + [ + -74.86887601660165, + 40.2646094670467 + ], + [ + -74.83296334833481, + 40.2646094670467 + ], + [ + -74.83296334833481, + 40.23879402360235 + ], + [ + -74.76113801180117, + 40.22158372797279 + ], + [ + -74.76113801180117, + 40.17855798889888 + ], + [ + -74.72522534353433, + 40.17855798889888 + ], + [ + -74.72522534353433, + 40.135532249824976 + ], + [ + -74.79705068006798, + 40.118321954195416 + ], + [ + -74.83296334833481, + 40.12692710201019 + ], + [ + -74.83296334833481, + 40.09250651075107 + ], + [ + -74.90478868486846, + 40.075296215121504 + ], + [ + -74.97661402140213, + 40.058085919491944 + ], + [ + -74.97661402140213, + 40.0322704760476 + ], + [ + -75.04843935793578, + 40.01506018041803 + ], + [ + -75.04843935793578, + 39.98063958915891 + ], + [ + -75.12026469446943, + 39.97203444134413 + ], + [ + -75.12026469446943, + 39.88598296319631 + ], + [ + -75.19209003100308, + 39.88598296319631 + ], + [ + -75.22800269926991, + 39.851562371937185 + ], + [ + -75.33574070407039, + 39.851562371937185 + ], + [ + -75.37165337233722, + 39.84295722412241 + ], + [ + -75.37165337233722, + 39.817141780678064 + ], + [ + -75.40756604060404, + 39.80853663286328 + ], + [ + -75.40756604060404, + 39.799931485048496 + ], + [ + -75.40756604060404, + 39.80853663286328 + ], + [ + -75.44347870887087, + 39.80853663286328 + ], + [ + -75.47939137713769, + 39.834352076307624 + ], + [ + -75.623042050205, + 39.834352076307624 + ], + [ + -75.69486738673865, + 39.817141780678064 + ], + [ + -75.69486738673865, + 39.79132633723372 + ], + [ + -75.73078005500548, + 39.79132633723372 + ], + [ + -75.73078005500548, + 39.765510893789376 + ], + [ + -75.76669272327231, + 39.765510893789376 + ], + [ + -75.76669272327231, + 39.722485154715464 + ], + [ + -75.80260539153913, + 39.722485154715464 + ], + [ + -76.52085875687567, + 39.722485154715464 + ], + [ + -77.02363611261124, + 39.722485154715464 + ], + [ + -77.84962748274826, + 39.722485154715464 + ], + [ + -78.49605551155113, + 39.722485154715464 + ], + [ + -78.81926952595258, + 39.722485154715464 + ], + [ + -79.46569755475545, + 39.722485154715464 + ], + [ + -80.0762129152915, + 39.722485154715464 + ], + [ + -80.50716493449343, + 39.722485154715464 + ], + [ + -80.50716493449343, + 40.634630823082304 + ] + ] + ], + "type": "Polygon" + }, + "properties": { + "NAME": "Pennsylvania" + }, + "type": "Feature" + }, + { + "geometry": { + "coordinates": [ + [ + [ + -75.15617736273626, + 40.77231318811881 + ], + [ + -75.12026469446943, + 40.77231318811881 + ], + [ + -75.12026469446943, + 40.79812863156315 + ], + [ + -75.0843520262026, + 40.79812863156315 + ], + [ + -75.0843520262026, + 40.84975951845184 + ], + [ + -75.04843935793578, + 40.84975951845184 + ], + [ + -75.04843935793578, + 40.88418010971097 + ], + [ + -75.0843520262026, + 40.892785257525745 + ], + [ + -75.0843520262026, + 40.935810996599656 + ], + [ + -75.12026469446943, + 40.935810996599656 + ], + [ + -75.12026469446943, + 41.004652179117905 + ], + [ + -75.0843520262026, + 41.004652179117905 + ], + [ + -75.01252668966895, + 41.03907277037703 + ], + [ + -75.01252668966895, + 41.07349336163616 + ], + [ + -74.97661402140213, + 41.09070365726572 + ], + [ + -74.97661402140213, + 41.099308805080504 + ], + [ + -74.97661402140213, + 41.09070365726572 + ], + [ + -74.97661402140213, + 41.099308805080504 + ], + [ + -74.9407013531353, + 41.116519100710065 + ], + [ + -74.9407013531353, + 41.14233454415441 + ], + [ + -74.90478868486846, + 41.14233454415441 + ], + [ + -74.90478868486846, + 41.176755135413536 + ], + [ + -74.86887601660165, + 41.176755135413536 + ], + [ + -74.86887601660165, + 41.25420146574657 + ], + [ + -74.83296334833481, + 41.25420146574657 + ], + [ + -74.83296334833481, + 41.29722720482047 + ], + [ + -74.79705068006798, + 41.29722720482047 + ], + [ + -74.79705068006798, + 41.32304264826482 + ], + [ + -74.76113801180117, + 41.32304264826482 + ], + [ + -74.76113801180117, + 41.34885809170916 + ], + [ + -74.6893126752675, + 41.357463239523945 + ], + [ + -74.58157467046702, + 41.29722720482047 + ], + [ + -74.50974933393337, + 41.28001690919091 + ], + [ + -74.50974933393337, + 41.26280661356135 + ], + [ + -74.25836065606559, + 41.14233454415441 + ], + [ + -74.15062265126511, + 41.116519100710065 + ], + [ + -74.07879731473146, + 41.064888213821376 + ], + [ + -74.0069719781978, + 41.047677918191816 + ], + [ + -73.93514664166415, + 41.004652179117905 + ], + [ + -73.89923397339732, + 41.004652179117905 + ], + [ + -73.89923397339732, + 40.92720584878487 + ], + [ + -73.93514664166415, + 40.91860070097009 + ], + [ + -73.93514664166415, + 40.84975951845184 + ], + [ + -73.97105930993098, + 40.84975951845184 + ], + [ + -73.97105930993098, + 40.78952348374837 + ], + [ + -74.0069719781978, + 40.78952348374837 + ], + [ + -74.0069719781978, + 40.712077153415336 + ], + [ + -74.04288464646463, + 40.70347200560055 + ], + [ + -74.04288464646463, + 40.68626170997099 + ], + [ + -74.04288464646463, + 40.651841118711864 + ], + [ + -74.18653531953193, + 40.64323597089708 + ], + [ + -74.18653531953193, + 40.59160508400839 + ], + [ + -74.22244798779876, + 40.59160508400839 + ], + [ + -74.22244798779876, + 40.55718449274927 + ], + [ + -74.25836065606559, + 40.54857934493449 + ], + [ + -74.25836065606559, + 40.47973816241623 + ], + [ + -74.18653531953193, + 40.47973816241623 + ], + [ + -74.07879731473146, + 40.4969484580458 + ], + [ + -73.97105930993098, + 40.522763901490144 + ], + [ + -73.93514664166415, + 40.522763901490144 + ], + [ + -73.89923397339732, + 40.488343310231016 + ], + [ + -73.89923397339732, + 40.23879402360235 + ], + [ + -73.93514664166415, + 40.22158372797279 + ], + [ + -73.93514664166415, + 40.15274254545454 + ], + [ + -73.97105930993098, + 40.12692710201019 + ], + [ + -73.97105930993098, + 40.023665328232816 + ], + [ + -74.0069719781978, + 40.01506018041803 + ], + [ + -74.0069719781978, + 39.82574692849284 + ], + [ + -74.04288464646463, + 39.80853663286328 + ], + [ + -74.04288464646463, + 39.722485154715464 + ], + [ + -74.07879731473146, + 39.705274859085904 + ], + [ + -74.07879731473146, + 39.653643972197216 + ], + [ + -74.22244798779876, + 39.498751311531144 + ], + [ + -74.22244798779876, + 39.4729358680868 + ], + [ + -74.25836065606559, + 39.45572557245724 + ], + [ + -74.25836065606559, + 39.42130498119811 + ], + [ + -74.29427332433241, + 39.37827924212421 + ], + [ + -74.36609866086607, + 39.34385865086508 + ], + [ + -74.36609866086607, + 39.318043207420736 + ], + [ + -74.47383666566655, + 39.300832911791176 + ], + [ + -74.47383666566655, + 39.27501746834683 + ], + [ + -74.50974933393337, + 39.26641232053205 + ], + [ + -74.50974933393337, + 39.240596877087704 + ], + [ + -74.58157467046702, + 39.21478143364336 + ], + [ + -74.58157467046702, + 39.17175569456945 + ], + [ + -74.65340000700068, + 39.128729955495544 + ], + [ + -74.65340000700068, + 39.05988877297729 + ], + [ + -74.6893126752675, + 39.05128362516251 + ], + [ + -74.6893126752675, + 39.016863033903384 + ], + [ + -74.72522534353433, + 39.016863033903384 + ], + [ + -74.72522534353433, + 38.95662699919991 + ], + [ + -74.79705068006798, + 38.93081155575557 + ], + [ + -74.79705068006798, + 38.904996112311224 + ], + [ + -74.83296334833481, + 38.887785816681664 + ], + [ + -74.90478868486846, + 38.87918066886688 + ], + [ + -75.01252668966895, + 38.80173433853385 + ], + [ + -75.01252668966895, + 38.78452404290429 + ], + [ + -75.01252668966895, + 38.80173433853385 + ], + [ + -75.04843935793578, + 38.836154929792976 + ], + [ + -75.04843935793578, + 38.87918066886688 + ], + [ + -75.0843520262026, + 38.87918066886688 + ], + [ + -75.0843520262026, + 38.91360126012601 + ], + [ + -75.12026469446943, + 38.965232147014696 + ], + [ + -75.12026469446943, + 38.999652738273824 + ], + [ + -75.15617736273626, + 38.999652738273824 + ], + [ + -75.15617736273626, + 39.05988877297729 + ], + [ + -75.19209003100308, + 39.06849392079207 + ], + [ + -75.22800269926991, + 39.111519659865984 + ], + [ + -75.22800269926991, + 39.15454539893989 + ], + [ + -75.26391536753674, + 39.15454539893989 + ], + [ + -75.26391536753674, + 39.188965990199016 + ], + [ + -75.29982803580356, + 39.206176285828576 + ], + [ + -75.29982803580356, + 39.24920202490249 + ], + [ + -75.33574070407039, + 39.24920202490249 + ], + [ + -75.33574070407039, + 39.27501746834683 + ], + [ + -75.40756604060404, + 39.30943805960595 + ], + [ + -75.40756604060404, + 39.335253503050296 + ], + [ + -75.44347870887087, + 39.335253503050296 + ], + [ + -75.44347870887087, + 39.36106894649464 + ], + [ + -75.47939137713769, + 39.369674094309424 + ], + [ + -75.47939137713769, + 39.39548953775377 + ], + [ + -75.51530404540452, + 39.40409468556855 + ], + [ + -75.51530404540452, + 39.429910129012896 + ], + [ + -75.55121671367135, + 39.429910129012896 + ], + [ + -75.55121671367135, + 39.498751311531144 + ], + [ + -75.51530404540452, + 39.498751311531144 + ], + [ + -75.51530404540452, + 39.541777050605056 + ], + [ + -75.51530404540452, + 39.58480278967896 + ], + [ + -75.55121671367135, + 39.593407937493744 + ], + [ + -75.55121671367135, + 39.64503882438243 + ], + [ + -75.51530404540452, + 39.64503882438243 + ], + [ + -75.51530404540452, + 39.69666971127112 + ], + [ + -75.47939137713769, + 39.69666971127112 + ], + [ + -75.47939137713769, + 39.765510893789376 + ], + [ + -75.44347870887087, + 39.765510893789376 + ], + [ + -75.44347870887087, + 39.79132633723372 + ], + [ + -75.40756604060404, + 39.799931485048496 + ], + [ + -75.40756604060404, + 39.80853663286328 + ], + [ + -75.37165337233722, + 39.817141780678064 + ], + [ + -75.37165337233722, + 39.84295722412241 + ], + [ + -75.33574070407039, + 39.851562371937185 + ], + [ + -75.22800269926991, + 39.851562371937185 + ], + [ + -75.19209003100308, + 39.88598296319631 + ], + [ + -75.12026469446943, + 39.88598296319631 + ], + [ + -75.12026469446943, + 39.97203444134413 + ], + [ + -75.04843935793578, + 39.98063958915891 + ], + [ + -75.04843935793578, + 40.01506018041803 + ], + [ + -74.97661402140213, + 40.0322704760476 + ], + [ + -74.97661402140213, + 40.058085919491944 + ], + [ + -74.90478868486846, + 40.075296215121504 + ], + [ + -74.83296334833481, + 40.09250651075107 + ], + [ + -74.83296334833481, + 40.12692710201019 + ], + [ + -74.79705068006798, + 40.118321954195416 + ], + [ + -74.72522534353433, + 40.135532249824976 + ], + [ + -74.72522534353433, + 40.17855798889888 + ], + [ + -74.76113801180117, + 40.17855798889888 + ], + [ + -74.76113801180117, + 40.22158372797279 + ], + [ + -74.83296334833481, + 40.23879402360235 + ], + [ + -74.83296334833481, + 40.2646094670467 + ], + [ + -74.86887601660165, + 40.2646094670467 + ], + [ + -74.86887601660165, + 40.30763520612061 + ], + [ + -74.9407013531353, + 40.32484550175017 + ], + [ + -74.9407013531353, + 40.38508153645364 + ], + [ + -74.97661402140213, + 40.38508153645364 + ], + [ + -74.97661402140213, + 40.410896979897984 + ], + [ + -75.04843935793578, + 40.4022918320832 + ], + [ + -75.04843935793578, + 40.44531757115711 + ], + [ + -75.0843520262026, + 40.44531757115711 + ], + [ + -75.0843520262026, + 40.471133014601456 + ], + [ + -75.04843935793578, + 40.471133014601456 + ], + [ + -75.04843935793578, + 40.53136904930492 + ], + [ + -75.0843520262026, + 40.53136904930492 + ], + [ + -75.0843520262026, + 40.56578964056405 + ], + [ + -75.12026469446943, + 40.57439478837883 + ], + [ + -75.19209003100308, + 40.56578964056405 + ], + [ + -75.19209003100308, + 40.77231318811881 + ], + [ + -75.15617736273626, + 40.77231318811881 + ] + ] + ], + "type": "Polygon" + }, + "properties": { + "NAME": "New Jersey" + }, + "type": "Feature" + } + ] +} \ No newline at end of file diff --git a/ios/benchmark/MBXBenchAppDelegate.h b/ios/benchmark/MBXBenchAppDelegate.h new file mode 100644 index 000000000..b8f6c2e64 --- /dev/null +++ b/ios/benchmark/MBXBenchAppDelegate.h @@ -0,0 +1,7 @@ +#import + +@interface MBXBenchAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end \ No newline at end of file diff --git a/ios/benchmark/MBXBenchAppDelegate.m b/ios/benchmark/MBXBenchAppDelegate.m new file mode 100644 index 000000000..e8fbd88d2 --- /dev/null +++ b/ios/benchmark/MBXBenchAppDelegate.m @@ -0,0 +1,15 @@ +#import "MBXBenchAppDelegate.h" +#import "MBXBenchViewController.h" + +@implementation MBXBenchAppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.rootViewController = [MBXBenchViewController new]; + [self.window makeKeyAndVisible]; + + return YES; +} + +@end diff --git a/ios/benchmark/MBXBenchViewController.h b/ios/benchmark/MBXBenchViewController.h new file mode 100644 index 000000000..c4439be5e --- /dev/null +++ b/ios/benchmark/MBXBenchViewController.h @@ -0,0 +1,5 @@ +#import + +@interface MBXBenchViewController : UIViewController + +@end diff --git a/ios/benchmark/MBXBenchViewController.mm b/ios/benchmark/MBXBenchViewController.mm new file mode 100644 index 000000000..86b4ec9cb --- /dev/null +++ b/ios/benchmark/MBXBenchViewController.mm @@ -0,0 +1,148 @@ +#import "MBXBenchViewController.h" + +#import + +#include "locations.hpp" + +#include + +@interface MGLMapView (MBXBenchmarkAdditions) + +#pragma mark - Debugging + +/** Triggers another render pass even when it is not necessary. */ +- (void)invalidate; + +/** Returns whether the map view is currently loading or processing any assets required to render the map */ +- (BOOL)isFullyLoaded; + +@end + +@interface MBXBenchViewController () + +@property (nonatomic) MGLMapView *mapView; + +@end + +@implementation MBXBenchViewController + +#pragma mark - Setup + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + NSURL* url = [[NSURL alloc] initWithString:@"asset://styles/mapbox-streets-v7.json"]; + self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds styleURL:url]; + self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.mapView.delegate = self; + self.mapView.zoomEnabled = NO; + self.mapView.scrollEnabled = NO; + self.mapView.rotateEnabled = NO; + self.mapView.userInteractionEnabled = YES; + [self.mapView setDebugActive:NO]; + + [self startBenchmarkIteration]; + + [self.view addSubview:self.mapView]; + +} + +using Clock = std::chrono::steady_clock; +using TimePoint = Clock::time_point; +template +inline int64_t Microseconds(Duration d) { + return std::chrono::duration_cast(d).count(); +} + +size_t idx = 0; +enum class State { None, WaitingForAssets, WarmingUp, Benchmarking } state = State::None; +int frames = 0; +TimePoint started; +std::vector> result; + +static const int warmupDuration = 20; // frames +static const int benchmarkDuration = 200; // frames + +- (void)startBenchmarkIteration +{ + if (mbgl::bench::locations.size() > idx) { + const auto& location = mbgl::bench::locations[idx]; + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(location.latitude, location.longitude) zoomLevel:location.zoom animated:NO]; + self.mapView.direction = location.bearing; + state = State::WaitingForAssets; + NSLog(@"Benchmarking \"%s\"", location.name.c_str()); + NSLog(@"- Loading assets..."); + } else { + // Do nothing. The benchmark is completed. + NSLog(@"Benchmark completed."); + NSLog(@"Result:"); + size_t colWidth = 0; + for (const auto& row : result) { + colWidth = std::max(row.first.size(), colWidth); + } + for (const auto& row : result) { + NSLog(@"| %-*s | %4.1f fps |", int(colWidth), row.first.c_str(), row.second); + } + exit(0); + } +} + +- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(__unused BOOL)fullyRendered +{ + if (state == State::Benchmarking) + { + frames++; + if (frames >= benchmarkDuration) + { + state = State::None; + + // Report FPS + const auto duration = Microseconds(Clock::now() - started); + const auto fps = double(frames * 1e6) / duration; + result.emplace_back(mbgl::bench::locations[idx].name, fps); + NSLog(@"- FPS: %.1f", fps); + + // Start benchmarking the next location. + idx++; + [self startBenchmarkIteration]; + } else { + [mapView invalidate]; + } + return; + } + + else if (state == State::WarmingUp) + { + frames++; + if (frames >= warmupDuration) + { + frames = 0; + state = State::Benchmarking; + started = Clock::now(); + NSLog(@"- Benchmarking for %d frames...", benchmarkDuration); + } + [mapView invalidate]; + return; + } + + else if (state == State::WaitingForAssets) + { + if ([mapView isFullyLoaded]) + { + // Start the benchmarking timer. + state = State::WarmingUp; + [self.mapView emptyMemoryCache]; + NSLog(@"- Warming up for %d frames...", warmupDuration); + [mapView invalidate]; + } + return; + } +} + +- (NSUInteger)supportedInterfaceOrientations +{ + return UIInterfaceOrientationMaskLandscape; +} + +@end diff --git a/ios/benchmark/app-info.plist b/ios/benchmark/app-info.plist new file mode 100644 index 000000000..fe29fce2c --- /dev/null +++ b/ios/benchmark/app-info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.mapbox.GL.benchmark + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.0.2 + CFBundleSignature + MBGL + CFBundleVersion + 0.0.3 + LSRequiresIPhoneOS + + NSHumanReadableCopyright + (c) 2015 Mapbox + UIApplicationExitsOnSuspend + + UILaunchStoryboardName + Default + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ios/benchmark/assets/glyphs/download.sh b/ios/benchmark/assets/glyphs/download.sh new file mode 100755 index 000000000..0ac151382 --- /dev/null +++ b/ios/benchmark/assets/glyphs/download.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +set -u + +LIST=( + "DIN%20Offc%20Pro%20Regular%2c%20Arial%20Unicode%20MS%20Regular/0-255.pbf" + "DIN%20Offc%20Pro%20Medium%2c%20Arial%20Unicode%20MS%20Bold/0-255.pbf" + "DIN%20Offc%20Pro%20Medium%2c%20Arial%20Unicode%20MS%20Regular/0-255.pbf" + "DIN%20Offc%20Pro%20Medium%2c%20Arial%20Unicode%20MS%20Regular/8192-8447.pbf" + "DIN%20Offc%20Pro%20Bold%2c%20Arial%20Unicode%20MS%20Regular/0-255.pbf" + "DIN%20Offc%20Pro%20Regular%2c%20Arial%20Unicode%20MS%20Regular/256-511.pbf" + "DIN%20Offc%20Pro%20Regular%2c%20Arial%20Unicode%20MS%20Regular/8192-8447.pbf" + "DIN%20Offc%20Pro%20Italic%2c%20Arial%20Unicode%20MS%20Regular/0-255.pbf" + "DIN%20Offc%20Pro%20Medium%2c%20Arial%20Unicode%20MS%20Regular/256-511.pbf" +) + +# from https://gist.github.com/cdown/1163649 +urldecode() { + local url_encoded="${1//+/ }" + printf '%b' "${url_encoded//%/\x}" +} + +for i in ${LIST[@]} ; do + OUTPUT=`urldecode "$i"` + if [ ! -f "${OUTPUT}" ] ; then + mkdir -p "`dirname "${OUTPUT}"`" + echo "Downloading glyph '${OUTPUT}'" + curl -# "https://api.tiles.mapbox.com/v4/fontstack/${i}?access_token=${MAPBOX_ACCESS_TOKEN}" | gunzip > "${OUTPUT}" + fi +done diff --git a/ios/benchmark/assets/sprites/mapbox-streets.json b/ios/benchmark/assets/sprites/mapbox-streets.json new file mode 100644 index 000000000..488bf335d --- /dev/null +++ b/ios/benchmark/assets/sprites/mapbox-streets.json @@ -0,0 +1,2034 @@ +{ + "secondary_marker": { + "x": 0, + "y": 0, + "width": 20, + "height": 50, + "pixelRatio": 1, + "sdf": false + }, + "default_marker": { + "x": 22, + "y": 0, + "width": 20, + "height": 50, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-alternate-1-large": { + "x": 44, + "y": 0, + "width": 21, + "height": 37, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-business-1-large": { + "x": 67, + "y": 0, + "width": 27, + "height": 37, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-business-2-large": { + "x": 0, + "y": 52, + "width": 27, + "height": 37, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-alternate-2-large": { + "x": 29, + "y": 52, + "width": 27, + "height": 37, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-truck-1-large": { + "x": 58, + "y": 52, + "width": 23, + "height": 35, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-truck-2-large": { + "x": 96, + "y": 0, + "width": 27, + "height": 35, + "pixelRatio": 1, + "sdf": false + }, + "marsh-32": { + "x": 0, + "y": 91, + "width": 32, + "height": 32, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-alternate-1-small": { + "x": 96, + "y": 37, + "width": 17, + "height": 31, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-business-1-small": { + "x": 34, + "y": 91, + "width": 17, + "height": 31, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-alternate-2-small": { + "x": 53, + "y": 91, + "width": 21, + "height": 31, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-truck-2-small": { + "x": 76, + "y": 91, + "width": 21, + "height": 31, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-business-2-small": { + "x": 99, + "y": 91, + "width": 21, + "height": 31, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-truck-1-small": { + "x": 125, + "y": 0, + "width": 17, + "height": 31, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-duplex-4-large": { + "x": 144, + "y": 0, + "width": 40, + "height": 29, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-duplex-3-large": { + "x": 144, + "y": 31, + "width": 35, + "height": 29, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-2-large": { + "x": 144, + "y": 62, + "width": 29, + "height": 29, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-duplex-5-large": { + "x": 0, + "y": 125, + "width": 43, + "height": 29, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-3-large": { + "x": 144, + "y": 93, + "width": 35, + "height": 29, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-1-large": { + "x": 45, + "y": 125, + "width": 25, + "height": 29, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-business-3-large": { + "x": 72, + "y": 125, + "width": 35, + "height": 28, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-business-2-large": { + "x": 109, + "y": 125, + "width": 29, + "height": 28, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-business-1-large": { + "x": 140, + "y": 125, + "width": 25, + "height": 28, + "pixelRatio": 1, + "sdf": false + }, + "mx-federal-2-large": { + "x": 0, + "y": 156, + "width": 25, + "height": 26, + "pixelRatio": 1, + "sdf": false + }, + "mx-federal-4-large": { + "x": 27, + "y": 156, + "width": 37, + "height": 26, + "pixelRatio": 1, + "sdf": false + }, + "mx-federal-1-large": { + "x": 66, + "y": 156, + "width": 20, + "height": 26, + "pixelRatio": 1, + "sdf": false + }, + "mx-federal-3-large": { + "x": 88, + "y": 156, + "width": 30, + "height": 26, + "pixelRatio": 1, + "sdf": false + }, + "mx-state-3-large": { + "x": 120, + "y": 156, + "width": 31, + "height": 25, + "pixelRatio": 1, + "sdf": false + }, + "mx-state-4-large": { + "x": 186, + "y": 0, + "width": 36, + "height": 25, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-3-small": { + "x": 186, + "y": 27, + "width": 30, + "height": 25, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-2-small": { + "x": 186, + "y": 54, + "width": 25, + "height": 25, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-1-small": { + "x": 186, + "y": 81, + "width": 21, + "height": 25, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-duplex-5-small": { + "x": 186, + "y": 108, + "width": 36, + "height": 25, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-duplex-4-small": { + "x": 186, + "y": 135, + "width": 34, + "height": 25, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-duplex-3-small": { + "x": 153, + "y": 156, + "width": 30, + "height": 25, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-business-2-small": { + "x": 0, + "y": 184, + "width": 25, + "height": 24, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-business-3-small": { + "x": 27, + "y": 184, + "width": 30, + "height": 24, + "pixelRatio": 1, + "sdf": false + }, + "us-interstate-business-1-small": { + "x": 59, + "y": 184, + "width": 21, + "height": 24, + "pixelRatio": 1, + "sdf": false + }, + "mx-state-1-large": { + "x": 82, + "y": 184, + "width": 20, + "height": 24, + "pixelRatio": 1, + "sdf": false + }, + "mx-state-2-large": { + "x": 104, + "y": 184, + "width": 25, + "height": 24, + "pixelRatio": 1, + "sdf": false + }, + "post-15": { + "x": 131, + "y": 184, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "prison-15": { + "x": 156, + "y": 184, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "religious-christian-15": { + "x": 181, + "y": 184, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "religious-jewish-15": { + "x": 224, + "y": 0, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "religious-muslim-15": { + "x": 224, + "y": 25, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "rocket-15": { + "x": 224, + "y": 50, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "shop-15": { + "x": 224, + "y": 75, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "star-15": { + "x": 224, + "y": 100, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "suitcase-15": { + "x": 224, + "y": 125, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "swimming-15": { + "x": 224, + "y": 150, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "theatre-15": { + "x": 224, + "y": 175, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "town-hall-15": { + "x": 0, + "y": 210, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "triangle-15": { + "x": 25, + "y": 210, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "triangle-stroked-15": { + "x": 50, + "y": 210, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "dentist-15": { + "x": 75, + "y": 210, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "hospital-15": { + "x": 100, + "y": 210, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "pharmacy-15": { + "x": 125, + "y": 210, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "america-football-15": { + "x": 150, + "y": 210, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "baseball-15": { + "x": 175, + "y": 210, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "basketball-15": { + "x": 200, + "y": 210, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "campsite-15": { + "x": 249, + "y": 0, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "cemetery-15": { + "x": 249, + "y": 25, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "dog-park-15": { + "x": 249, + "y": 50, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "beer-15": { + "x": 249, + "y": 75, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "park-15": { + "x": 249, + "y": 100, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "bar-15": { + "x": 249, + "y": 125, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "playground-15": { + "x": 249, + "y": 150, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "zoo-15": { + "x": 249, + "y": 175, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "college-15": { + "x": 249, + "y": 200, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "ferry-15": { + "x": 0, + "y": 235, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "school-15": { + "x": 25, + "y": 235, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "rail-metro-15": { + "x": 50, + "y": 235, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "cafe-15": { + "x": 75, + "y": 235, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "bus-15": { + "x": 100, + "y": 235, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "airport-15": { + "x": 125, + "y": 235, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "airfield-15": { + "x": 150, + "y": 235, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "fast-food-15": { + "x": 175, + "y": 235, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "rail-light-15": { + "x": 200, + "y": 235, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "rail-15": { + "x": 225, + "y": 235, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "heliport-15": { + "x": 274, + "y": 0, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "restaurant-15": { + "x": 274, + "y": 25, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "alcohol-shop-15": { + "x": 274, + "y": 50, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "art-gallery-15": { + "x": 274, + "y": 75, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "bakery-15": { + "x": 274, + "y": 100, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "bank-15": { + "x": 274, + "y": 125, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "bicycle-15": { + "x": 274, + "y": 150, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "car-15": { + "x": 274, + "y": 175, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "cinema-15": { + "x": 274, + "y": 200, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "circle-15": { + "x": 274, + "y": 225, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "circle-stroked-15": { + "x": 0, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "clothing-store-15": { + "x": 25, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "embassy-15": { + "x": 50, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "fire-station-15": { + "x": 75, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "fuel-15": { + "x": 100, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "garden-15": { + "x": 125, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "grocery-15": { + "x": 150, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "hairdresser-15": { + "x": 175, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "harbor-15": { + "x": 200, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "ice-cream-15": { + "x": 225, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "laundry-15": { + "x": 250, + "y": 260, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "library-15": { + "x": 299, + "y": 0, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "lodging-15": { + "x": 299, + "y": 25, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "marker-15": { + "x": 299, + "y": 50, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "monument-15": { + "x": 299, + "y": 75, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "museum-15": { + "x": 299, + "y": 100, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "music-15": { + "x": 299, + "y": 125, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "place-of-worship-15": { + "x": 299, + "y": 150, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "police-15": { + "x": 299, + "y": 175, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "golf-15": { + "x": 299, + "y": 200, + "width": 23, + "height": 23, + "pixelRatio": 1, + "sdf": false + }, + "mx-federal-4-small": { + "x": 0, + "y": 285, + "width": 31, + "height": 22, + "pixelRatio": 1, + "sdf": false + }, + "mx-federal-1-small": { + "x": 299, + "y": 225, + "width": 17, + "height": 22, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-duplex-3-large": { + "x": 33, + "y": 285, + "width": 32, + "height": 22, + "pixelRatio": 1, + "sdf": false + }, + "mx-federal-2-small": { + "x": 299, + "y": 249, + "width": 21, + "height": 22, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-duplex-4-large": { + "x": 67, + "y": 285, + "width": 34, + "height": 22, + "pixelRatio": 1, + "sdf": false + }, + "mx-federal-3-small": { + "x": 103, + "y": 285, + "width": 25, + "height": 22, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-duplex-5-large": { + "x": 130, + "y": 285, + "width": 37, + "height": 22, + "pixelRatio": 1, + "sdf": false + }, + "washington-metro-11": { + "x": 225, + "y": 210, + "width": 21, + "height": 21, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-3-large": { + "x": 169, + "y": 285, + "width": 30, + "height": 21, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-2-large": { + "x": 201, + "y": 285, + "width": 27, + "height": 21, + "pixelRatio": 1, + "sdf": false + }, + "light-11": { + "x": 250, + "y": 235, + "width": 21, + "height": 21, + "pixelRatio": 1, + "sdf": false + }, + "subway-11": { + "x": 275, + "y": 260, + "width": 21, + "height": 21, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-1-large": { + "x": 230, + "y": 285, + "width": 20, + "height": 21, + "pixelRatio": 1, + "sdf": false + }, + "u-bahn-11": { + "x": 252, + "y": 285, + "width": 21, + "height": 21, + "pixelRatio": 1, + "sdf": false + }, + "mx-state-1-small": { + "x": 186, + "y": 162, + "width": 17, + "height": 20, + "pixelRatio": 1, + "sdf": false + }, + "mx-state-4-small": { + "x": 275, + "y": 285, + "width": 29, + "height": 20, + "pixelRatio": 1, + "sdf": false + }, + "mx-state-3-small": { + "x": 324, + "y": 0, + "width": 25, + "height": 20, + "pixelRatio": 1, + "sdf": false + }, + "circle.sdf": { + "x": 324, + "y": 22, + "width": 19, + "height": 20, + "pixelRatio": 1, + "sdf": true + }, + "mx-state-2-small": { + "x": 324, + "y": 44, + "width": 21, + "height": 20, + "pixelRatio": 1, + "sdf": false + }, + "zoo-11": { + "x": 324, + "y": 66, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "beer-11": { + "x": 324, + "y": 87, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "dlr-11": { + "x": 324, + "y": 108, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "dlr.london-overground.london-underground.national-rail-11": { + "x": 0, + "y": 309, + "width": 75, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "dlr.london-underground-11": { + "x": 77, + "y": 309, + "width": 39, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "dlr.london-underground.national-rail-11": { + "x": 118, + "y": 309, + "width": 57, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "dlr.national-rail-11": { + "x": 177, + "y": 309, + "width": 39, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "heliport-11": { + "x": 324, + "y": 129, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "museum-11": { + "x": 324, + "y": 150, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "london-overground-11": { + "x": 324, + "y": 171, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "london-overground.london-underground-11": { + "x": 218, + "y": 309, + "width": 39, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "london-overground.london-underground.national-rail-11": { + "x": 259, + "y": 309, + "width": 57, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "london-overground.national-rail-11": { + "x": 0, + "y": 330, + "width": 39, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "london-underground-11": { + "x": 324, + "y": 192, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "london-underground.national-rail-11": { + "x": 41, + "y": 330, + "width": 39, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "circle-11": { + "x": 324, + "y": 213, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "metro.rer-11": { + "x": 82, + "y": 330, + "width": 39, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "moscow-metro-11": { + "x": 324, + "y": 234, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "national-rail-11": { + "x": 324, + "y": 255, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "rail-11": { + "x": 324, + "y": 276, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "rer-11": { + "x": 96, + "y": 70, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "rer.transilien-11": { + "x": 123, + "y": 330, + "width": 39, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "s-bahn-11": { + "x": 318, + "y": 309, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "music-11": { + "x": 164, + "y": 330, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "transilien-11": { + "x": 185, + "y": 330, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "school-11": { + "x": 206, + "y": 330, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "place-of-worship-11": { + "x": 227, + "y": 330, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "weiner-linien-11": { + "x": 248, + "y": 330, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "ferry-11": { + "x": 269, + "y": 330, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "circle-stroked-11": { + "x": 290, + "y": 330, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "bus-11": { + "x": 311, + "y": 330, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "police-11": { + "x": 351, + "y": 0, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "airport-11": { + "x": 351, + "y": 21, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "fast-food-11": { + "x": 351, + "y": 42, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "airfield-11": { + "x": 351, + "y": 63, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "post-11": { + "x": 351, + "y": 84, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "clothing-store-11": { + "x": 351, + "y": 105, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "prison-11": { + "x": 351, + "y": 126, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "alcohol-shop-11": { + "x": 351, + "y": 147, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "religious-christian-11": { + "x": 351, + "y": 168, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "embassy-11": { + "x": 351, + "y": 189, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "religious-jewish-11": { + "x": 351, + "y": 210, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "bar-11": { + "x": 351, + "y": 231, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "religious-muslim-11": { + "x": 351, + "y": 252, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "fire-station-11": { + "x": 351, + "y": 273, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "rocket-11": { + "x": 351, + "y": 294, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "art-gallery-11": { + "x": 351, + "y": 315, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "shop-11": { + "x": 0, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "fuel-11": { + "x": 21, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "star-11": { + "x": 42, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "restaurant-11": { + "x": 63, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "suitcase-11": { + "x": 84, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "garden-11": { + "x": 105, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "swimming-11": { + "x": 126, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "bakery-11": { + "x": 147, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "theatre-11": { + "x": 168, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "grocery-11": { + "x": 189, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "town-hall-11": { + "x": 210, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "rail-metro-11": { + "x": 231, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "triangle-11": { + "x": 252, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "hairdresser-11": { + "x": 273, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "triangle-stroked-11": { + "x": 294, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "bank-11": { + "x": 315, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "dentist-11": { + "x": 336, + "y": 351, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "harbor-11": { + "x": 372, + "y": 0, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "hospital-11": { + "x": 372, + "y": 21, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "cafe-11": { + "x": 372, + "y": 42, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "pharmacy-11": { + "x": 372, + "y": 63, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "ice-cream-11": { + "x": 372, + "y": 84, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "america-football-11": { + "x": 372, + "y": 105, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "bicycle-11": { + "x": 372, + "y": 126, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "baseball-11": { + "x": 372, + "y": 147, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "laundry-11": { + "x": 372, + "y": 168, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "basketball-11": { + "x": 372, + "y": 189, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "college-11": { + "x": 372, + "y": 210, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "campsite-11": { + "x": 372, + "y": 231, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "library-11": { + "x": 372, + "y": 252, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "cemetery-11": { + "x": 372, + "y": 273, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "car-11": { + "x": 372, + "y": 294, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "dog-park-11": { + "x": 372, + "y": 315, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "lodging-11": { + "x": 372, + "y": 336, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "golf-11": { + "x": 0, + "y": 372, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "rail-light-11": { + "x": 21, + "y": 372, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "park-11": { + "x": 42, + "y": 372, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "marker-11": { + "x": 63, + "y": 372, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "cinema-11": { + "x": 84, + "y": 372, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "monument-11": { + "x": 105, + "y": 372, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "playground-11": { + "x": 126, + "y": 372, + "width": 19, + "height": 19, + "pixelRatio": 1, + "sdf": false + }, + "us-state-5-large": { + "x": 147, + "y": 372, + "width": 48, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "default-1-large": { + "x": 197, + "y": 372, + "width": 18, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-3-small": { + "x": 217, + "y": 372, + "width": 25, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-2-small": { + "x": 244, + "y": 372, + "width": 21, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-1-small": { + "x": 205, + "y": 162, + "width": 17, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "default-2-large": { + "x": 267, + "y": 372, + "width": 25, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "default-6-large": { + "x": 294, + "y": 372, + "width": 50, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "default-3-large": { + "x": 346, + "y": 372, + "width": 32, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "default-5-large": { + "x": 393, + "y": 0, + "width": 45, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "default-4-large": { + "x": 393, + "y": 20, + "width": 39, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "us-state-1-large": { + "x": 393, + "y": 40, + "width": 22, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "us-state-6-large": { + "x": 0, + "y": 393, + "width": 54, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "us-state-2-large": { + "x": 393, + "y": 60, + "width": 28, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "us-state-4-large": { + "x": 393, + "y": 80, + "width": 42, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "us-state-3-large": { + "x": 393, + "y": 100, + "width": 35, + "height": 18, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-duplex-5-small": { + "x": 393, + "y": 120, + "width": 29, + "height": 17, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-duplex-4-small": { + "x": 393, + "y": 139, + "width": 28, + "height": 17, + "pixelRatio": 1, + "sdf": false + }, + "us-highway-duplex-3-small": { + "x": 393, + "y": 158, + "width": 27, + "height": 17, + "pixelRatio": 1, + "sdf": false + }, + "entrance-11": { + "x": 417, + "y": 40, + "width": 17, + "height": 17, + "pixelRatio": 1, + "sdf": false + }, + "marsh-16": { + "x": 422, + "y": 158, + "width": 16, + "height": 16, + "pixelRatio": 1, + "sdf": false + }, + "us-state-1-small": { + "x": 393, + "y": 177, + "width": 17, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "us-state-6-small": { + "x": 393, + "y": 194, + "width": 45, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "default-4-small": { + "x": 393, + "y": 211, + "width": 33, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "default-3-small": { + "x": 393, + "y": 228, + "width": 27, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "default-5-small": { + "x": 393, + "y": 245, + "width": 38, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "default-2-small": { + "x": 412, + "y": 177, + "width": 21, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "us-state-2-small": { + "x": 393, + "y": 262, + "width": 23, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "default-1-small": { + "x": 423, + "y": 60, + "width": 15, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "us-state-4-small": { + "x": 393, + "y": 279, + "width": 35, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "metro-11": { + "x": 423, + "y": 139, + "width": 15, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "us-state-3-small": { + "x": 393, + "y": 296, + "width": 29, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "us-state-5-small": { + "x": 393, + "y": 313, + "width": 40, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "default-6-small": { + "x": 393, + "y": 330, + "width": 44, + "height": 15, + "pixelRatio": 1, + "sdf": false + }, + "oneway-spaced-white-large": { + "x": 424, + "y": 120, + "width": 14, + "height": 6, + "pixelRatio": 1, + "sdf": false + }, + "oneway-spaced-large": { + "x": 424, + "y": 128, + "width": 14, + "height": 6, + "pixelRatio": 1, + "sdf": false + }, + "oneway-spaced-small": { + "x": 422, + "y": 228, + "width": 11, + "height": 5, + "pixelRatio": 1, + "sdf": false + }, + "oneway-spaced-white-small": { + "x": 422, + "y": 235, + "width": 11, + "height": 5, + "pixelRatio": 1, + "sdf": false + } +} \ No newline at end of file diff --git a/ios/benchmark/assets/sprites/mapbox-streets.png b/ios/benchmark/assets/sprites/mapbox-streets.png new file mode 100644 index 000000000..00925f91a Binary files /dev/null and b/ios/benchmark/assets/sprites/mapbox-streets.png differ diff --git a/ios/benchmark/assets/sprites/mapbox-streets@2x.json b/ios/benchmark/assets/sprites/mapbox-streets@2x.json new file mode 100644 index 000000000..0a193fb4d --- /dev/null +++ b/ios/benchmark/assets/sprites/mapbox-streets@2x.json @@ -0,0 +1,2034 @@ +{ + "secondary_marker": { + "x": 0, + "y": 0, + "width": 40, + "height": 100, + "pixelRatio": 2, + "sdf": false + }, + "default_marker": { + "x": 42, + "y": 0, + "width": 40, + "height": 100, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-business-1-large": { + "x": 84, + "y": 0, + "width": 54, + "height": 74, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-alternate-1-large": { + "x": 140, + "y": 0, + "width": 42, + "height": 74, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-alternate-2-large": { + "x": 0, + "y": 102, + "width": 54, + "height": 74, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-business-2-large": { + "x": 56, + "y": 102, + "width": 54, + "height": 74, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-truck-1-large": { + "x": 112, + "y": 102, + "width": 46, + "height": 70, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-truck-2-large": { + "x": 184, + "y": 0, + "width": 54, + "height": 70, + "pixelRatio": 2, + "sdf": false + }, + "marsh-32": { + "x": 240, + "y": 0, + "width": 64, + "height": 64, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-truck-1-small": { + "x": 240, + "y": 66, + "width": 34, + "height": 62, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-business-2-small": { + "x": 184, + "y": 72, + "width": 42, + "height": 62, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-alternate-2-small": { + "x": 0, + "y": 178, + "width": 42, + "height": 62, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-alternate-1-small": { + "x": 44, + "y": 178, + "width": 34, + "height": 62, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-truck-2-small": { + "x": 80, + "y": 178, + "width": 42, + "height": 62, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-business-1-small": { + "x": 124, + "y": 178, + "width": 34, + "height": 62, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-duplex-3-large": { + "x": 160, + "y": 178, + "width": 68, + "height": 56, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-3-large": { + "x": 230, + "y": 178, + "width": 68, + "height": 56, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-duplex-4-large": { + "x": 0, + "y": 242, + "width": 78, + "height": 56, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-1-large": { + "x": 80, + "y": 242, + "width": 48, + "height": 56, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-duplex-5-large": { + "x": 130, + "y": 242, + "width": 84, + "height": 56, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-2-large": { + "x": 216, + "y": 242, + "width": 56, + "height": 56, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-business-1-large": { + "x": 306, + "y": 0, + "width": 48, + "height": 54, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-business-2-large": { + "x": 0, + "y": 300, + "width": 56, + "height": 54, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-business-3-large": { + "x": 58, + "y": 300, + "width": 68, + "height": 54, + "pixelRatio": 2, + "sdf": false + }, + "mx-federal-1-large": { + "x": 306, + "y": 56, + "width": 40, + "height": 52, + "pixelRatio": 2, + "sdf": false + }, + "mx-federal-2-large": { + "x": 128, + "y": 300, + "width": 50, + "height": 52, + "pixelRatio": 2, + "sdf": false + }, + "mx-federal-3-large": { + "x": 180, + "y": 300, + "width": 60, + "height": 52, + "pixelRatio": 2, + "sdf": false + }, + "mx-federal-4-large": { + "x": 242, + "y": 300, + "width": 74, + "height": 52, + "pixelRatio": 2, + "sdf": false + }, + "mx-state-4-large": { + "x": 356, + "y": 0, + "width": 72, + "height": 50, + "pixelRatio": 2, + "sdf": false + }, + "mx-state-3-large": { + "x": 356, + "y": 52, + "width": 62, + "height": 50, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-duplex-5-small": { + "x": 356, + "y": 104, + "width": 70, + "height": 48, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-2-small": { + "x": 356, + "y": 154, + "width": 48, + "height": 48, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-duplex-3-small": { + "x": 356, + "y": 204, + "width": 58, + "height": 48, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-duplex-4-small": { + "x": 356, + "y": 254, + "width": 66, + "height": 48, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-1-small": { + "x": 356, + "y": 304, + "width": 40, + "height": 48, + "pixelRatio": 2, + "sdf": false + }, + "mx-state-2-large": { + "x": 0, + "y": 356, + "width": 50, + "height": 48, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-3-small": { + "x": 52, + "y": 356, + "width": 58, + "height": 48, + "pixelRatio": 2, + "sdf": false + }, + "mx-state-1-large": { + "x": 306, + "y": 110, + "width": 40, + "height": 48, + "pixelRatio": 2, + "sdf": false + }, + "music-15": { + "x": 306, + "y": 160, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "place-of-worship-15": { + "x": 306, + "y": 208, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "police-15": { + "x": 240, + "y": 130, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "post-15": { + "x": 112, + "y": 356, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "prison-15": { + "x": 160, + "y": 356, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "religious-christian-15": { + "x": 208, + "y": 356, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "religious-jewish-15": { + "x": 256, + "y": 356, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "religious-muslim-15": { + "x": 304, + "y": 356, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "rocket-15": { + "x": 352, + "y": 356, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "shop-15": { + "x": 430, + "y": 0, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "star-15": { + "x": 430, + "y": 48, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "suitcase-15": { + "x": 430, + "y": 96, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "swimming-15": { + "x": 430, + "y": 144, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "theatre-15": { + "x": 430, + "y": 192, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "town-hall-15": { + "x": 430, + "y": 240, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "triangle-15": { + "x": 430, + "y": 288, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "triangle-stroked-15": { + "x": 430, + "y": 336, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "dentist-15": { + "x": 0, + "y": 406, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "hospital-15": { + "x": 48, + "y": 406, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "pharmacy-15": { + "x": 96, + "y": 406, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "america-football-15": { + "x": 144, + "y": 406, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "baseball-15": { + "x": 192, + "y": 406, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "basketball-15": { + "x": 240, + "y": 406, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "campsite-15": { + "x": 288, + "y": 406, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "cemetery-15": { + "x": 336, + "y": 406, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "dog-park-15": { + "x": 384, + "y": 406, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "beer-15": { + "x": 478, + "y": 0, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "park-15": { + "x": 478, + "y": 48, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "bar-15": { + "x": 478, + "y": 96, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "playground-15": { + "x": 478, + "y": 144, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "zoo-15": { + "x": 478, + "y": 192, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "ferry-15": { + "x": 478, + "y": 240, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "bus-15": { + "x": 478, + "y": 288, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "airport-15": { + "x": 478, + "y": 336, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "college-15": { + "x": 478, + "y": 384, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "airfield-15": { + "x": 0, + "y": 454, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "school-15": { + "x": 48, + "y": 454, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "rail-metro-15": { + "x": 96, + "y": 454, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "cafe-15": { + "x": 144, + "y": 454, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "fast-food-15": { + "x": 192, + "y": 454, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "rail-light-15": { + "x": 240, + "y": 454, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "rail-15": { + "x": 288, + "y": 454, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-business-3-small": { + "x": 336, + "y": 454, + "width": 58, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "heliport-15": { + "x": 396, + "y": 454, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-business-2-small": { + "x": 444, + "y": 454, + "width": 48, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "restaurant-15": { + "x": 526, + "y": 0, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "alcohol-shop-15": { + "x": 526, + "y": 48, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "us-interstate-business-1-small": { + "x": 526, + "y": 96, + "width": 40, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "art-gallery-15": { + "x": 526, + "y": 144, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "bakery-15": { + "x": 526, + "y": 192, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "bank-15": { + "x": 526, + "y": 240, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "bicycle-15": { + "x": 526, + "y": 288, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "car-15": { + "x": 526, + "y": 336, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "cinema-15": { + "x": 526, + "y": 384, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "circle-15": { + "x": 526, + "y": 432, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "circle-stroked-15": { + "x": 0, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "clothing-store-15": { + "x": 48, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "embassy-15": { + "x": 96, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "fire-station-15": { + "x": 144, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "fuel-15": { + "x": 192, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "garden-15": { + "x": 240, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "grocery-15": { + "x": 288, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "hairdresser-15": { + "x": 336, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "harbor-15": { + "x": 384, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "ice-cream-15": { + "x": 432, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "laundry-15": { + "x": 480, + "y": 502, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "library-15": { + "x": 574, + "y": 0, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "lodging-15": { + "x": 574, + "y": 48, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "marker-15": { + "x": 574, + "y": 96, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "monument-15": { + "x": 574, + "y": 144, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "museum-15": { + "x": 574, + "y": 192, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "golf-15": { + "x": 574, + "y": 240, + "width": 46, + "height": 46, + "pixelRatio": 2, + "sdf": false + }, + "mx-federal-4-small": { + "x": 0, + "y": 550, + "width": 62, + "height": 44, + "pixelRatio": 2, + "sdf": false + }, + "mx-federal-3-small": { + "x": 64, + "y": 550, + "width": 50, + "height": 44, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-duplex-5-large": { + "x": 116, + "y": 550, + "width": 74, + "height": 44, + "pixelRatio": 2, + "sdf": false + }, + "mx-federal-2-small": { + "x": 574, + "y": 288, + "width": 42, + "height": 44, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-duplex-4-large": { + "x": 192, + "y": 550, + "width": 68, + "height": 44, + "pixelRatio": 2, + "sdf": false + }, + "mx-federal-1-small": { + "x": 574, + "y": 334, + "width": 34, + "height": 44, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-duplex-3-large": { + "x": 262, + "y": 550, + "width": 64, + "height": 44, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-1-large": { + "x": 574, + "y": 380, + "width": 40, + "height": 42, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-2-large": { + "x": 328, + "y": 550, + "width": 54, + "height": 42, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-3-large": { + "x": 384, + "y": 550, + "width": 60, + "height": 42, + "pixelRatio": 2, + "sdf": false + }, + "mx-state-3-small": { + "x": 184, + "y": 136, + "width": 50, + "height": 40, + "pixelRatio": 2, + "sdf": false + }, + "mx-state-1-small": { + "x": 574, + "y": 424, + "width": 34, + "height": 40, + "pixelRatio": 2, + "sdf": false + }, + "mx-state-2-small": { + "x": 574, + "y": 466, + "width": 42, + "height": 40, + "pixelRatio": 2, + "sdf": false + }, + "mx-state-4-small": { + "x": 446, + "y": 550, + "width": 58, + "height": 40, + "pixelRatio": 2, + "sdf": false + }, + "u-bahn-11": { + "x": 574, + "y": 508, + "width": 40, + "height": 40, + "pixelRatio": 2, + "sdf": false + }, + "subway-11": { + "x": 306, + "y": 256, + "width": 40, + "height": 40, + "pixelRatio": 2, + "sdf": false + }, + "light-11": { + "x": 432, + "y": 406, + "width": 40, + "height": 40, + "pixelRatio": 2, + "sdf": false + }, + "circle.sdf": { + "x": 528, + "y": 502, + "width": 38, + "height": 40, + "pixelRatio": 2, + "sdf": true + }, + "washington-metro-11": { + "x": 506, + "y": 550, + "width": 40, + "height": 40, + "pixelRatio": 2, + "sdf": false + }, + "zoo-11": { + "x": 548, + "y": 550, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "beer-11": { + "x": 622, + "y": 0, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "heliport-11": { + "x": 622, + "y": 40, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "museum-11": { + "x": 622, + "y": 80, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "ferry-11": { + "x": 622, + "y": 120, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "circle-11": { + "x": 622, + "y": 160, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "bus-11": { + "x": 622, + "y": 200, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "music-11": { + "x": 622, + "y": 240, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "school-11": { + "x": 622, + "y": 280, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "airport-11": { + "x": 622, + "y": 320, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "place-of-worship-11": { + "x": 622, + "y": 360, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "airfield-11": { + "x": 622, + "y": 400, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "circle-stroked-11": { + "x": 622, + "y": 440, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "police-11": { + "x": 622, + "y": 480, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "fast-food-11": { + "x": 622, + "y": 520, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "post-11": { + "x": 0, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "clothing-store-11": { + "x": 40, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "prison-11": { + "x": 80, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "alcohol-shop-11": { + "x": 120, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "rail-11": { + "x": 160, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "religious-christian-11": { + "x": 200, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "embassy-11": { + "x": 240, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "religious-jewish-11": { + "x": 280, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "bar-11": { + "x": 320, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "religious-muslim-11": { + "x": 360, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "fire-station-11": { + "x": 400, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "rocket-11": { + "x": 440, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "art-gallery-11": { + "x": 480, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "shop-11": { + "x": 520, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "fuel-11": { + "x": 560, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "star-11": { + "x": 600, + "y": 596, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "restaurant-11": { + "x": 662, + "y": 0, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "suitcase-11": { + "x": 662, + "y": 40, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "garden-11": { + "x": 662, + "y": 80, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "swimming-11": { + "x": 662, + "y": 120, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "bakery-11": { + "x": 662, + "y": 160, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "theatre-11": { + "x": 662, + "y": 200, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "grocery-11": { + "x": 662, + "y": 240, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "town-hall-11": { + "x": 662, + "y": 280, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "rail-metro-11": { + "x": 662, + "y": 320, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "triangle-11": { + "x": 662, + "y": 360, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "hairdresser-11": { + "x": 662, + "y": 400, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "triangle-stroked-11": { + "x": 662, + "y": 440, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "bank-11": { + "x": 662, + "y": 480, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "dentist-11": { + "x": 662, + "y": 520, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "harbor-11": { + "x": 662, + "y": 560, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "hospital-11": { + "x": 0, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "cafe-11": { + "x": 40, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "pharmacy-11": { + "x": 80, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "ice-cream-11": { + "x": 120, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "america-football-11": { + "x": 160, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "bicycle-11": { + "x": 200, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "baseball-11": { + "x": 240, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "laundry-11": { + "x": 280, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "basketball-11": { + "x": 320, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "college-11": { + "x": 360, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "campsite-11": { + "x": 400, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "library-11": { + "x": 440, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "cemetery-11": { + "x": 480, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "car-11": { + "x": 520, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "dog-park-11": { + "x": 560, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "lodging-11": { + "x": 600, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "golf-11": { + "x": 640, + "y": 636, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "rail-light-11": { + "x": 702, + "y": 0, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "park-11": { + "x": 702, + "y": 40, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "marker-11": { + "x": 702, + "y": 80, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "cinema-11": { + "x": 702, + "y": 120, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "monument-11": { + "x": 702, + "y": 160, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "playground-11": { + "x": 702, + "y": 200, + "width": 38, + "height": 38, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-3-small": { + "x": 0, + "y": 676, + "width": 50, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-1-small": { + "x": 702, + "y": 240, + "width": 34, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "dlr-11": { + "x": 702, + "y": 278, + "width": 36, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "dlr.london-overground.london-underground.national-rail-11": { + "x": 52, + "y": 676, + "width": 148, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "dlr.london-underground-11": { + "x": 202, + "y": 676, + "width": 76, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "default-6-large": { + "x": 280, + "y": 676, + "width": 100, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "dlr.london-underground.national-rail-11": { + "x": 382, + "y": 676, + "width": 112, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "dlr.national-rail-11": { + "x": 496, + "y": 676, + "width": 76, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "default-5-large": { + "x": 574, + "y": 676, + "width": 90, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "london-overground-11": { + "x": 702, + "y": 316, + "width": 36, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "default-4-large": { + "x": 742, + "y": 0, + "width": 78, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "london-overground.london-underground-11": { + "x": 742, + "y": 38, + "width": 76, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "default-3-large": { + "x": 742, + "y": 76, + "width": 65, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "london-overground.london-underground.national-rail-11": { + "x": 0, + "y": 714, + "width": 112, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "default-2-large": { + "x": 742, + "y": 114, + "width": 50, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "us-state-6-large": { + "x": 114, + "y": 714, + "width": 108, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "default-1-large": { + "x": 742, + "y": 152, + "width": 36, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "weiner-linien-11": { + "x": 780, + "y": 152, + "width": 36, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "transilien-11": { + "x": 742, + "y": 190, + "width": 36, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "s-bahn-11": { + "x": 780, + "y": 190, + "width": 36, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "rer.transilien-11": { + "x": 742, + "y": 228, + "width": 76, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "rer-11": { + "x": 742, + "y": 266, + "width": 36, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "national-rail-11": { + "x": 780, + "y": 266, + "width": 36, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "moscow-metro-11": { + "x": 742, + "y": 304, + "width": 36, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "metro.rer-11": { + "x": 742, + "y": 342, + "width": 76, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "us-state-5-large": { + "x": 224, + "y": 714, + "width": 96, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "london-underground.national-rail-11": { + "x": 742, + "y": 380, + "width": 76, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-2-small": { + "x": 742, + "y": 418, + "width": 42, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "london-overground.national-rail-11": { + "x": 742, + "y": 456, + "width": 76, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "us-state-1-large": { + "x": 742, + "y": 494, + "width": 44, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "us-state-4-large": { + "x": 322, + "y": 714, + "width": 84, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "us-state-2-large": { + "x": 742, + "y": 532, + "width": 56, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "us-state-3-large": { + "x": 742, + "y": 570, + "width": 70, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "london-underground-11": { + "x": 780, + "y": 304, + "width": 36, + "height": 36, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-duplex-3-small": { + "x": 742, + "y": 608, + "width": 54, + "height": 34, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-duplex-4-small": { + "x": 742, + "y": 644, + "width": 56, + "height": 34, + "pixelRatio": 2, + "sdf": false + }, + "us-highway-duplex-5-small": { + "x": 666, + "y": 676, + "width": 58, + "height": 34, + "pixelRatio": 2, + "sdf": false + }, + "marsh-16": { + "x": 786, + "y": 418, + "width": 32, + "height": 32, + "pixelRatio": 2, + "sdf": false + }, + "entrance-11": { + "x": 788, + "y": 494, + "width": 32, + "height": 32, + "pixelRatio": 2, + "sdf": false + }, + "default-1-small": { + "x": 742, + "y": 680, + "width": 30, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "us-state-2-small": { + "x": 774, + "y": 680, + "width": 46, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "default-2-small": { + "x": 408, + "y": 714, + "width": 42, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "default-3-small": { + "x": 452, + "y": 714, + "width": 54, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "default-4-small": { + "x": 508, + "y": 714, + "width": 66, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "us-state-3-small": { + "x": 576, + "y": 714, + "width": 58, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "default-5-small": { + "x": 636, + "y": 714, + "width": 76, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "us-state-5-small": { + "x": 714, + "y": 714, + "width": 80, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "us-state-6-small": { + "x": 0, + "y": 752, + "width": 90, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "default-6-small": { + "x": 92, + "y": 752, + "width": 88, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "us-state-4-small": { + "x": 182, + "y": 752, + "width": 70, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "us-state-1-small": { + "x": 702, + "y": 354, + "width": 34, + "height": 30, + "pixelRatio": 2, + "sdf": false + }, + "metro-11": { + "x": 702, + "y": 386, + "width": 28, + "height": 28, + "pixelRatio": 2, + "sdf": false + }, + "oneway-spaced-white-large": { + "x": 702, + "y": 416, + "width": 28, + "height": 12, + "pixelRatio": 2, + "sdf": false + }, + "oneway-spaced-large": { + "x": 702, + "y": 430, + "width": 28, + "height": 12, + "pixelRatio": 2, + "sdf": false + }, + "oneway-spaced-small": { + "x": 794, + "y": 114, + "width": 22, + "height": 10, + "pixelRatio": 2, + "sdf": false + }, + "oneway-spaced-white-small": { + "x": 794, + "y": 126, + "width": 22, + "height": 10, + "pixelRatio": 2, + "sdf": false + } +} \ No newline at end of file diff --git a/ios/benchmark/assets/sprites/mapbox-streets@2x.png b/ios/benchmark/assets/sprites/mapbox-streets@2x.png new file mode 100644 index 000000000..0d5bd533f Binary files /dev/null and b/ios/benchmark/assets/sprites/mapbox-streets@2x.png differ diff --git a/ios/benchmark/assets/styles/mapbox-streets-v7.json b/ios/benchmark/assets/styles/mapbox-streets-v7.json new file mode 100644 index 000000000..62e0f6669 --- /dev/null +++ b/ios/benchmark/assets/styles/mapbox-streets-v7.json @@ -0,0 +1,3917 @@ +{ + "version": 7, + "name": "mapbox-streets", + "constants": { + "@poi-scalerank3": { + "base": 1, + "stops": [[16, 11], [20, 13]] + }, + "@label-neighbourhood": "#805540", + "@hillshade-shadow": "#5a5517", + "@road-width-minor": { + "base": 1.5, + "stops": [[14, 0.5], [18, 12]] + }, + "@poi-scalerank4": { + "base": 1, + "stops": [[16, 11], [20, 13]] + }, + "@wetlands": "#9DD3D8", + "@landuse-cemetery": "#dde6c2", + "@admin-2-boundary": { + "base": 1, + "stops": [[3, 0.5], [10, 2]] + }, + "@snow": "#fff", + "@path-opacity": { + "base": 1, + "stops": [[15, 0], [15.25, 1]] + }, + "@label-park": "#4c661f", + "@landuse-school": "#f3ebb4", + "@label-water-dark": "#004087", + "@road-main": "#a2a2a2", + "@road-case-dark": "#d9d3c9", + "@path-bg-width": { + "base": 1.5, + "stops": [[15, 2], [18, 7]] + }, + "@road-trunk": "#f2cf60", + "@road-motorway": "#ffa159", + "@road-minor": "#fff", + "@rail-track-width": { + "base": 1.5, + "stops": [[14, 4], [20, 8]] + }, + "@label-primary": "#000000", + "@street-high-opacity": { + "base": 1, + "stops": [[13.99, 0], [14, 1]] + }, + "@label-city-lg-size": { + "base": 0.9, + "stops": [[4, 12], [10, 22]] + }, + "@landuse-industrial": "#e0dae0", + "@landcover-opacity": { + "base": 1.5, + "stops": [[2, 0.3], [14, 0]] + }, + "@rail-width": { + "base": 1.5, + "stops": [[14, 0.5], [20, 1]] + }, + "@landuse-hospital": "#f4dcdc", + "@land": "#ede9d9", + "@name": "{name_en}", + "@landcover": "#ddecb1", + "@tunnel-case-dark": "#c4beb7", + "@aeroway": "#dbcedb", + "@label-city-md-size": { + "base": 0.9, + "stops": [[5, 12], [12, 22]] + }, + "@tunnel-trunk": "#f2de9e", + "@landuse-pitch": "#c3e194", + "@admin": "#787680", + "@road-case-width-sm": { + "base": 1.5, + "stops": [[12, 0.75], [20, 2]] + }, + "@label-poi": "#65513d", + "@main-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "@road-case-width-lg": { + "base": 1.5, + "stops": [[5, 0.75], [16, 2]] + }, + "@road-high-z-fadein": { + "base": 1.2, + "stops": [[5, 0], [5.5, 1]] + }, + "@rail": "#b3ada6", + "@country-halo": "rgba(255,255,255,0.75)", + "@hillshade-highlight": "#fff", + "@motorway-width": { + "base": 1.5, + "stops": [[5, 0.75], [18, 32]] + }, + "@country-label-color": { + "stops": [[8, "#000000"], [10, "#888888"]], + "base": 1 + }, + "@building": "#e8e0cc", + "@landuse-sand": "#ededcf", + "@road-trunk-case": "#fff", + "@ramp-1": { + "base": 1, + "stops": [[0, [1, 2]], [20, [1, 0.25]]] + }, + "@road-motorway-case": "#fff", + "@street_limited-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 12]] + }, + "@water": "#8ccbf7", + "@ramp-2": { + "base": 1, + "stops": [[14, [0.4, 0.4]], [15, [0.3, 0.3]], [16, [0.2, 0.2]], [18, [0.15, 0.15]], [19, [0.1, 0.1]]] + }, + "@label-state": "#242424", + "@landuse-parks": "#cde8a2", + "@street_limited-case-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 12]] + }, + "@motorway_link-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "@building-shadow": "#cbc6b7", + "@label-road": "#3a3836", + "@rail-low": "#ccc5bd", + "@label-transit": "#000000", + "@rail-lowhigh": { + "stops": [[13, "#d8d5c8"], [16, "#b3b1a6"]] + }, + "@street-case-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + }, + "@halo": "#ffffff", + "@street-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "@main-case-width": { + "base": 1.2, + "stops": [[10, 0.75], [18, 2]] + }, + "@road-street-limited": "#EFEDEB", + "@landuse-glacier": "#dcedf9", + "@label-water": "#c8e5f9", + "@poi-scalerank1": { + "base": 1, + "stops": [[10, 11], [18, 14]] + }, + "@path-width": { + "base": 1.5, + "stops": [[15, 1], [18, 4]] + }, + "@tunnel-motorway": "#ffbe8c", + "@poi-scalerank2": { + "base": 1, + "stops": [[14, 11], [20, 14]] + } + }, + "sources": { + "mapbox://mapbox.mapbox-streets-v6": { + "url": "asset://tiles/mapbox.mapbox-streets-v6.json", + "type": "vector" + }, + "mapbox://mapbox.mapbox-terrain-v2": { + "url": "asset://tiles/mapbox.mapbox-terrain-v2.json", + "type": "vector" + } + }, + "sprite": "asset://sprites/mapbox-streets", + "glyphs": "asset://glyphs/{fontstack}/{range}.pbf", + "layers": [{ + "id": "background", + "type": "background", + "minzoom": 0, + "maxzoom": 22, + "layout": { + "visibility": "visible" + }, + "paint": { + "background-color": "@land" + } + }, { + "id": "landcover_crop", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "landcover", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "crop"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landcover", + "fill-opacity": "@landcover-opacity", + "fill-antialias": false + } + }, { + "id": "landcover_grass", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "landcover", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "grass"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landcover", + "fill-opacity": "@landcover-opacity", + "fill-antialias": false + } + }, { + "id": "landcover_scrub", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "landcover", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "scrub"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landcover", + "fill-opacity": "@landcover-opacity", + "fill-antialias": false + } + }, { + "id": "landcover_wood", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "landcover", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "wood"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landcover", + "fill-opacity": "@landcover-opacity", + "fill-antialias": false + } + }, { + "id": "landcover_snow", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "landcover", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "snow"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@snow", + "fill-opacity": 0.2, + "fill-antialias": false + } + }, { + "id": "parks", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "park"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landuse-parks", + "fill-opacity": { + "base": 1, + "stops": [[5, 0], [6, 1]] + } + } + }, { + "id": "scrub", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 9, + "maxzoom": 22, + "filter": ["all", ["in", "class", "scrub"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landcover", + "fill-opacity": { + "base": 1, + "stops": [[9, 0], [16, 0.2]] + } + } + }, { + "id": "grass", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 9, + "maxzoom": 22, + "filter": ["all", ["in", "class", "grass"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landcover", + "fill-opacity": { + "base": 1, + "stops": [[9, 0], [16, 0.4]] + } + } + }, { + "id": "wood", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 6, + "maxzoom": 22, + "filter": ["all", ["in", "class", "wood"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landcover", + "fill-opacity": { + "base": 1, + "stops": [[6, 0], [16, 0.5]] + } + } + }, { + "id": "hospital", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "hospital"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landuse-hospital" + } + }, { + "id": "glaciers", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 9, + "maxzoom": 22, + "filter": ["all", ["in", "class", "glacier"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landuse-glacier", + "fill-opacity": { + "base": 1, + "stops": [[9, 0], [10, 0.25]] + } + } + }, { + "id": "pitch", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "pitch"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landuse-pitch" + } + }, { + "id": "pitch-line", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["==", "class", "pitch"]], + "layout": {}, + "paint": { + "line-color": "#e1f2c6" + } + }, { + "id": "school", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "school"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landuse-school" + } + }, { + "id": "cemetery", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "cemetery"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landuse-cemetery" + } + }, { + "id": "industrial", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "industrial"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landuse-industrial" + } + }, { + "id": "sand", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "sand"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@landuse-sand" + } + }, { + "id": "hillshade_highlight_bright", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "hillshade", + "filter": ["all", ["==", "level", 94]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@hillshade-highlight", + "fill-opacity": { + "stops": [[15, 0.12], [18, 0]] + }, + "fill-antialias": false + } + }, { + "id": "hillshade_highlight_med", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "hillshade", + "filter": ["all", ["==", "level", 90]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@hillshade-highlight", + "fill-opacity": { + "stops": [[15, 0.12], [18, 0]] + }, + "fill-antialias": false + } + }, { + "id": "hillshade_shadow_faint", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "hillshade", + "filter": ["all", ["==", "level", 89]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@hillshade-shadow", + "fill-opacity": { + "stops": [[15, 0.05], [17, 0]] + }, + "fill-antialias": false + } + }, { + "id": "hillshade_shadow_med", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "hillshade", + "filter": ["all", ["==", "level", 78]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@hillshade-shadow", + "fill-opacity": { + "stops": [[15, 0.05], [17, 0]] + }, + "fill-antialias": false + } + }, { + "id": "hillshade_shadow_dark", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "hillshade", + "filter": ["all", ["==", "level", 67]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@hillshade-shadow", + "fill-opacity": { + "stops": [[15, 0.06], [17, 0]] + }, + "fill-antialias": false + } + }, { + "id": "hillshade_shadow_extreme", + "type": "fill", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "hillshade", + "filter": ["all", ["==", "level", 56]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@hillshade-shadow", + "fill-opacity": { + "stops": [[15, 0.06], [17, 0]] + }, + "fill-antialias": false + } + }, { + "id": "waterway-river", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "waterway", + "minzoom": 8, + "maxzoom": 22, + "filter": ["any", ["==", "class", "river"], ["==", "class", "canal"]], + "layout": { + "visibility": "visible", + "line-cap": { + "base": 1, + "stops": [[0, "butt"], [11, "round"]] + }, + "line-join": "round" + }, + "paint": { + "line-color": "@water", + "line-width": { + "base": 1.3, + "stops": [[8.5, 0.1], [20, 8]] + }, + "line-opacity": { + "base": 1, + "stops": [[8, 0], [8.5, 1]] + } + } + }, { + "id": "waterway-other", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "waterway", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["!=", "class", "river"], ["!=", "class", "canal"]], + "layout": { + "visibility": "visible", + "line-join": "round", + "line-cap": "round" + }, + "paint": { + "line-color": "@water", + "line-width": { + "base": 1.35, + "stops": [[13.5, 0.1], [20, 3]] + }, + "line-opacity": { + "base": 1, + "stops": [[13, 0], [13.5, 1]] + } + } + }, { + "id": "water", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "water", + "minzoom": 0, + "maxzoom": 22, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@water" + } + }, { + "id": "landuse-overlay", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse_overlay", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all"], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@wetlands", + "fill-opacity": { + "base": 1, + "stops": [[10, 0.25], [10.5, 0.15]] + } + } + }, { + "id": "landuse-overlay-pattern", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "landuse_overlay", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all"], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@wetlands", + "fill-opacity": { + "base": 1, + "stops": [[10, 0], [10.5, 1]] + }, + "fill-image": { + "base": 1, + "stops": [[13, "marsh-16"], [14, "marsh-32"]] + } + } + }, { + "id": "barrier_line-land-polygon", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "barrier_line", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "land"], ["==", "$type", "Polygon"]], + "layout": {}, + "paint": { + "fill-color": "@land" + } + }, { + "id": "barrier_line-land-line", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "barrier_line", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "land"], ["==", "$type", "LineString"]], + "layout": { + "line-cap": "round" + }, + "paint": { + "line-width": { + "base": 1.99, + "stops": [[14, 0.75], [20, 40]] + }, + "line-color": "@land" + } + }, { + "id": "building-bottom", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "building", + "minzoom": 15, + "maxzoom": 22, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "@building-shadow", + "fill-opacity": { + "base": 1, + "stops": [[15.5, 0], [16, 1]] + } + } + }, { + "id": "building-top", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "building", + "minzoom": 15, + "maxzoom": 22, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": { + "base": 1, + "stops": [[15, "@land"], [16, "@building"]] + }, + "fill-opacity": { + "base": 1, + "stops": [[15, 0], [15.5, 1]] + }, + "fill-outline-color": "#d0cbbb", + "fill-translate": { + "base": 1, + "stops": [[15, [0, 0]], [20, [-5, -5]]] + } + } + }, { + "id": "aeroway-polygon", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "aeroway", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "$type", "Polygon"], ["!=", "type", "apron"]], + "layout": {}, + "paint": { + "fill-color": "@aeroway", + "fill-opacity": { + "base": 1, + "stops": [[11, 0], [11.5, 1]] + } + } + }, { + "id": "aeroway-runway", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "aeroway", + "minzoom": 9, + "maxzoom": 22, + "filter": ["all", ["==", "type", "runway"], ["==", "$type", "LineString"]], + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": "@aeroway", + "line-width": { + "base": 1.5, + "stops": [[9, 1], [18, 80]] + } + } + }, { + "id": "aeroway-taxiway", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "aeroway", + "minzoom": 9, + "maxzoom": 22, + "filter": ["all", ["==", "type", "taxiway"], ["==", "$type", "LineString"]], + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": "@aeroway", + "line-width": { + "base": 1.5, + "stops": [[10, 0.5], [18, 20]] + } + } + }, { + "id": "admin-3-4-boundaries-bg", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "admin", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", [">=", "admin_level", 3], ["==", "maritime", 0]], + "layout": { + "visibility": "visible", + "line-join": "bevel" + }, + "paint": { + "line-color": { + "base": 1, + "stops": [[8, "@land"], [16, "#f6e8e1"]] + }, + "line-width": { + "base": 1, + "stops": [[3, 3.5], [10, 8]] + }, + "line-opacity": { + "base": 1, + "stops": [[7, 0], [8, 0.75]] + }, + "line-dasharray": [1, 0], + "line-translate": [0, 0], + "line-blur": { + "base": 1, + "stops": [[3, 0], [8, 3]] + } + } + }, { + "id": "tunnel-street_limited-polygon", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "Polygon"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#EEE8E3", + "fill-opacity": 0.75 + } + }, { + "id": "tunnel-path-bg", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "class", "path"]], + "layout": { + "visibility": "none", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@path-bg-width", + "line-dasharray": [1, 0], + "line-color": "@road-case-dark", + "line-blur": 0, + "line-opacity": { + "base": 1, + "stops": [[15, 0], [15.25, 0.5]] + } + } + }, { + "id": "tunnel-path", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "class", "path"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@path-width", + "line-dasharray": { + "base": 1, + "stops": [[15, [0.1, 1.25]], [16, [0.1, 1.6]], [17, [0.1, 1.45]], [18, [0.1, 1.3]]] + }, + "line-color": "#f5f2ee", + "line-opacity": "@path-opacity" + } + }, { + "id": "tunnel-street-low", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["in", "class", "street"], ["==", "$type", "LineString"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street-width", + "line-color": "@road-minor", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, { + "id": "tunnel-street_limited-low", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["in", "class", "street_limited"], ["==", "$type", "LineString"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street-width", + "line-color": "@road-minor", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, { + "id": "tunnel-motorway_link-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "motorway_link"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@road-motorway-case", + "line-gap-width": "@motorway_link-width", + "line-dasharray": [3, 3] + } + }, { + "id": "tunnel-service-driveway-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "class", "service", "driveway"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@tunnel-case-dark", + "line-gap-width": "@road-width-minor", + "line-dasharray": [3, 3] + } + }, { + "id": "tunnel-street_limited-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "LineString"], ["!=", "type", "construction"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@tunnel-case-dark", + "line-gap-width": "@street_limited-case-width", + "line-dasharray": [3, 3], + "line-opacity": "@street-high-opacity" + } + }, { + "id": "tunnel-street-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@tunnel-case-dark", + "line-gap-width": "@street-case-gap-width", + "line-dasharray": [3, 3], + "line-opacity": "@street-high-opacity" + } + }, { + "id": "tunnel-main-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "main"], ["!=", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@main-case-width", + "line-dasharray": [3, 3], + "line-gap-width": "@main-width", + "line-color": "@tunnel-case-dark" + } + }, { + "id": "tunnel-trunk-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "main"], ["==", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-lg", + "line-color": "@road-motorway-case", + "line-gap-width": "@motorway-width", + "line-opacity": 1, + "line-dasharray": [3, 3] + } + }, { + "id": "tunnel-motorway-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "class", "motorway"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-lg", + "line-color": "@road-motorway-case", + "line-gap-width": "@motorway-width", + "line-opacity": 1, + "line-dasharray": [3, 3] + } + }, { + "id": "tunnel-motorway_link", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "motorway_link"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@motorway_link-width", + "line-color": "@tunnel-motorway", + "line-opacity": 1, + "line-dasharray": [1, 0] + } + }, { + "id": "tunnel-service-driveway", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "class", "service", "driveway"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-width-minor", + "line-color": "@road-minor", + "line-dasharray": [1, 0] + } + }, { + "id": "tunnel-construction", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 14, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "LineString"], ["==", "type", "construction"]], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-width": "@street_limited-width", + "line-color": "@road-case-dark", + "line-opacity": "@street-high-opacity", + "line-dasharray": { + "base": 1, + "stops": [[14, [0.4, 0.8]], [15, [0.3, 0.6]], [16, [0.2, 0.3]], [17, [0.2, 0.25]], [18, [0.15, 0.15]]] + } + } + }, { + "id": "tunnel-street_limited", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "LineString"], ["!=", "type", "construction"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street_limited-width", + "line-color": "@road-street-limited", + "line-opacity": "@street-high-opacity" + } + }, { + "id": "tunnel-street", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street-width", + "line-color": "@road-minor", + "line-opacity": "@street-high-opacity" + } + }, { + "id": "tunnel-main", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "main"], ["!=", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@main-width", + "line-color": "@road-minor", + "line-opacity": 1, + "line-dasharray": [1, 0], + "line-blur": 0 + } + }, { + "id": "tunnel-trunk", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "main"], ["==", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@motorway-width", + "line-color": "@tunnel-trunk" + } + }, { + "id": "tunnel-motorway", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "motorway"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@motorway-width", + "line-dasharray": [1, 0], + "line-opacity": 1, + "line-color": "@tunnel-motorway", + "line-blur": 0 + } + }, { + "id": "tunnel-oneway-arrows-white", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "oneway", 1], ["any", ["in", "class", "motorway", "motorway_link"], ["in", "type", "trunk"]]], + "layout": { + "symbol-min-distance": 250, + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-spaced-white-small"], [17, "oneway-spaced-white-large"]] + }, + "icon-ignore-placement": true + }, + "paint": {} + }, { + "id": "tunnel-oneway-arrows-color", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "oneway", 1], ["in", "class", "main", "street", "street_limited"], ["!=", "type", "trunk"]], + "layout": { + "symbol-min-distance": 250, + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-spaced-small"], [17, "oneway-spaced-large"]] + }, + "icon-ignore-placement": true + }, + "paint": {} + }, { + "id": "tunnel-rail", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["in", "class", "major_rail", "minor_rail"]], + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": { + "stops": [[13, "#d8d5c8"], [16, "#c0beb2"]] + }, + "line-width": "@rail-width" + } + }, { + "id": "tunnel-rail-tracks", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "tunnel", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["in", "class", "major_rail", "minor_rail"]], + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": { + "stops": [[13, "#d8d5c8"], [16, "#c0beb2"]] + }, + "line-width": "@rail-track-width", + "line-dasharray": [0.1, 15], + "line-opacity": { + "base": 1, + "stops": [[13.75, 0], [20, 1]] + } + } + }, { + "id": "road-path-bg", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "class", "path"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@path-bg-width", + "line-dasharray": [1, 0], + "line-color": "@road-case-dark", + "line-blur": 0, + "line-opacity": { + "base": 1, + "stops": [[15, 0], [15.25, 0.5]] + } + } + }, { + "id": "road-path", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "class", "path"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@path-width", + "line-color": "@road-minor", + "line-dasharray": { + "base": 1, + "stops": [[15, [0.1, 1.25]], [16, [0.1, 1.6]], [17, [0.1, 1.45]], [18, [0.1, 1.3]]] + }, + "line-opacity": "@path-opacity" + } + }, { + "id": "road-street_limited-polygon-outline", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 12, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "Polygon"]], + "layout": { + "visibility": "none" + }, + "paint": { + "line-color": "@road-case-dark", + "line-width": { + "base": 1.5, + "stops": [[12, 1.5], [20, 4]] + }, + "line-opacity": 1 + } + }, { + "id": "road-street-low", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["in", "class", "street"], ["==", "$type", "LineString"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street-width", + "line-color": "@road-minor", + "line-opacity": { + "stops": [[11, 0], [11.25, 1], [14, 1], [14.01, 0]] + } + } + }, { + "id": "road-street_limited-low", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["in", "class", "street_limited"], ["==", "$type", "LineString"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street-width", + "line-color": "@road-minor", + "line-opacity": { + "stops": [[11, 0], [11.25, 1], [14, 1], [14.01, 0]] + } + } + }, { + "id": "road-motorway_link-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 10, + "maxzoom": 22, + "filter": ["all", ["==", "class", "motorway_link"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@road-motorway-case", + "line-gap-width": "@motorway_link-width", + "line-opacity": { + "base": 1, + "stops": [[10.99, 0], [11, 1]] + } + } + }, { + "id": "road-service-driveway-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "class", "service", "driveway"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@road-case-dark", + "line-gap-width": "@road-width-minor" + } + }, { + "id": "road-street_limited-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "LineString"], ["!=", "type", "construction"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@road-case-dark", + "line-gap-width": "@street_limited-case-width", + "line-opacity": "@street-high-opacity" + } + }, { + "id": "road-street-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@road-case-dark", + "line-gap-width": "@street-case-gap-width", + "line-opacity": "@street-high-opacity" + } + }, { + "id": "road-main-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "main"], ["!=", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@main-case-width", + "line-color": "@road-case-dark", + "line-gap-width": "@main-width", + "line-opacity": { + "base": 1, + "stops": [[9.99, 0], [10, 1]] + } + } + }, { + "id": "road-trunk-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 5, + "maxzoom": 22, + "filter": ["all", ["in", "class", "main"], ["in", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-lg", + "line-color": "@road-trunk-case", + "line-gap-width": "@motorway-width", + "line-opacity": { + "base": 1, + "stops": [[5.9, 0], [6, 1]] + } + } + }, { + "id": "road-motorway-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "class", "motorway"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-lg", + "line-color": "@road-motorway-case", + "line-gap-width": "@motorway-width", + "line-opacity": { + "base": 1.2, + "stops": [[5.9, 0], [6, 1]] + } + } + }, { + "id": "road-street_limited-polygon", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 12, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "Polygon"]], + "layout": { + "visibility": "none" + }, + "paint": { + "fill-color": "@road-street-limited", + "fill-opacity": 1 + } + }, { + "id": "road-service-driveway", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "class", "service", "driveway"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-width-minor", + "line-color": "@road-minor" + } + }, { + "id": "road-motorway_link", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 10, + "maxzoom": 22, + "filter": ["all", ["==", "class", "motorway_link"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@motorway_link-width", + "line-color": "@road-motorway", + "line-opacity": 1 + } + }, { + "id": "road-construction", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 14, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "LineString"], ["==", "type", "construction"]], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-width": "@street_limited-width", + "line-color": "@road-case-dark", + "line-opacity": "@street-high-opacity", + "line-dasharray": { + "base": 1, + "stops": [[14, [0.4, 0.8]], [15, [0.3, 0.6]], [16, [0.2, 0.3]], [17, [0.2, 0.25]], [18, [0.15, 0.15]]] + } + } + }, { + "id": "road-street_limited", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "LineString"], ["!=", "type", "construction"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street_limited-width", + "line-color": "@road-street-limited", + "line-opacity": "@street-high-opacity" + } + }, { + "id": "road-street", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street-width", + "line-color": "@road-minor", + "line-opacity": "@street-high-opacity" + } + }, { + "id": "road-main", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "main"], ["!=", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@main-width", + "line-color": { + "base": 1, + "stops": [[5, "@land"], [8, "@road-minor"]] + }, + "line-opacity": "@road-high-z-fadein" + } + }, { + "id": "road-trunk", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 5, + "maxzoom": 22, + "filter": ["all", ["==", "class", "main"], ["==", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@motorway-width", + "line-color": "@road-trunk" + } + }, { + "id": "road-motorway", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "motorway"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@motorway-width", + "line-color": { + "base": 1, + "stops": [[5.9, "#fff"], [6, "#ffa159"]] + }, + "line-opacity": "@road-high-z-fadein" + } + }, { + "id": "road-oneway-arrows-white", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "oneway", 1], ["any", ["in", "class", "motorway", "motorway_link"], ["in", "type", "trunk"]]], + "layout": { + "symbol-min-distance": 250, + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-spaced-white-small"], [17, "oneway-spaced-white-large"]] + }, + "icon-ignore-placement": true + }, + "paint": {} + }, { + "id": "road-oneway-arrows-color", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "oneway", 1], ["in", "class", "main", "street", "street_limited"], ["!=", "type", "trunk"]], + "layout": { + "symbol-min-distance": 250, + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-spaced-small"], [17, "oneway-spaced-large"]] + }, + "icon-ignore-placement": true, + "icon-rotation-alignment": "map" + }, + "paint": {} + }, { + "id": "road-rail", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["in", "class", "major_rail", "minor_rail"]], + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": "@rail-lowhigh", + "line-width": "@rail-width" + } + }, { + "id": "road-rail-tracks", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["in", "class", "major_rail", "minor_rail"]], + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": "@rail-lowhigh", + "line-width": "@rail-track-width", + "line-dasharray": [0.1, 15], + "line-opacity": { + "base": 1, + "stops": [[13.75, 0], [14, 1]] + } + } + }, { + "id": "bridge-street_limited-polygon", + "type": "fill", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "Polygon"]], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#EEE8E3", + "fill-opacity": 0.75 + } + }, { + "id": "bridge-path-bg", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "class", "path"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@path-bg-width", + "line-dasharray": [1, 0], + "line-color": "@road-case-dark", + "line-blur": 0, + "line-opacity": { + "base": 1, + "stops": [[15, 0], [15.25, 0.75]] + } + } + }, { + "id": "bridge-path", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "class", "path"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@path-width", + "line-color": "@road-minor", + "line-dasharray": { + "base": 1, + "stops": [[14, [0.1, 1.25]], [16, [0.1, 1.6]], [17, [0.1, 1.45]], [18, [0.1, 1.3]]] + }, + "line-opacity": "@path-opacity" + } + }, { + "id": "bridge-street-low", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["in", "class", "street"], ["==", "$type", "LineString"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street-width", + "line-color": "@road-minor", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, { + "id": "bridge-street_limited-low", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["in", "class", "street_limited"], ["==", "$type", "LineString"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street-width", + "line-color": "@road-minor", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, { + "id": "bridge-motorway_link-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 12, + "maxzoom": 22, + "filter": ["all", ["==", "class", "motorway_link"]], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@road-motorway-case", + "line-gap-width": "@motorway_link-width", + "line-opacity": 1 + } + }, { + "id": "bridge-service-driveway-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "class", "service", "driveway"]], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@road-case-dark", + "line-gap-width": "@road-width-minor" + } + }, { + "id": "bridge-street_limited-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 14, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "LineString"], ["!=", "type", "construction"]], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@road-case-dark", + "line-gap-width": "@street_limited-case-width" + } + }, { + "id": "bridge-street-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 14, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street"]], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-sm", + "line-color": "@road-case-dark", + "line-gap-width": "@street-case-gap-width" + } + }, { + "id": "bridge-main-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 8, + "maxzoom": 22, + "filter": ["all", ["==", "class", "main"], ["!=", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": "@main-case-width", + "line-color": "@road-case-dark", + "line-gap-width": "@main-width", + "line-translate": [0, 0] + } + }, { + "id": "bridge-motorway-trunk-case", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 0, + "maxzoom": 22, + "filter": ["any", ["in", "class", "motorway"], ["==", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": "@road-case-width-lg", + "line-color": "@road-motorway-case", + "line-gap-width": "@motorway-width" + } + }, { + "id": "bridge-motorway_link", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 10, + "maxzoom": 22, + "filter": ["all", ["==", "class", "motorway_link"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@motorway_link-width", + "line-color": "@road-motorway" + } + }, { + "id": "bridge-service-driveway", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "class", "service", "driveway"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@road-width-minor", + "line-color": "@road-minor" + } + }, { + "id": "bridge-construction", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 14, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "LineString"], ["==", "type", "construction"]], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-width": "@street_limited-width", + "line-color": "@road-case-dark", + "line-opacity": "@street-high-opacity", + "line-dasharray": { + "base": 1, + "stops": [[14, [0.4, 0.8]], [15, [0.3, 0.6]], [16, [0.2, 0.3]], [17, [0.2, 0.25]], [18, [0.15, 0.15]]] + } + } + }, { + "id": "bridge-street_limited", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street_limited"], ["==", "$type", "LineString"], ["!=", "type", "construction"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street_limited-width", + "line-color": "@road-street-limited", + "line-opacity": "@street-high-opacity" + } + }, { + "id": "bridge-street", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["==", "class", "street"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@street-width", + "line-color": "@road-minor", + "line-opacity": "@street-high-opacity" + } + }, { + "id": "bridge-main", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "main"], ["!=", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@main-width", + "line-color": "@road-minor", + "line-opacity": "@road-high-z-fadein" + } + }, { + "id": "bridge-trunk", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "main"], ["==", "type", "trunk"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@motorway-width", + "line-color": "@road-trunk" + } + }, { + "id": "bridge-motorway", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["==", "class", "motorway"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": "@motorway-width", + "line-color": "@road-motorway" + } + }, { + "id": "bridge-oneway-arrows-white", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "oneway", 1], ["any", ["in", "class", "motorway", "motorway_link"], ["in", "type", "trunk"]]], + "layout": { + "symbol-min-distance": 250, + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-spaced-white-small"], [17, "oneway-spaced-white-large"]] + }, + "icon-ignore-placement": true + }, + "paint": {} + }, { + "id": "bridge-oneway-arrows-color", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "oneway", 1], ["in", "class", "main", "street", "street_limited"], ["!=", "type", "trunk"]], + "layout": { + "symbol-min-distance": 250, + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-spaced-small"], [17, "oneway-spaced-large"]] + }, + "icon-ignore-placement": true + }, + "paint": {} + }, { + "id": "bridge-rail", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["in", "class", "major_rail", "minor_rail"]], + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": "@rail-lowhigh", + "line-width": "@rail-width" + } + }, { + "id": "bridge-rail-tracks", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["in", "class", "major_rail", "minor_rail"]], + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": "@rail-lowhigh", + "line-width": "@rail-track-width", + "line-dasharray": [0.1, 15], + "line-opacity": { + "base": 1, + "stops": [[13.75, 0], [20, 1]] + } + } + }, { + "id": "bridge-aerialway", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "bridge", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["in", "class", "aerialway"]], + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": "@rail", + "line-width": "@rail-width" + } + }, { + "id": "hedges", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "barrier_line", + "minzoom": 16, + "maxzoom": 22, + "filter": ["all", ["==", "class", "hedge"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#e2f4c2", + "line-width": { + "base": 1, + "stops": [[16, 1], [20, 3]] + }, + "line-opacity": 1, + "line-dasharray": [1, 2, 5, 2, 1, 2] + } + }, { + "id": "fences", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "barrier_line", + "minzoom": 16, + "maxzoom": 22, + "filter": ["all", ["==", "class", "fence"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "@building-shadow", + "line-width": { + "base": 1, + "stops": [[16, 1], [20, 3]] + }, + "line-opacity": 1, + "line-dasharray": [1, 2, 5, 2, 1, 2] + } + }, { + "id": "gates", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "barrier_line", + "minzoom": 17, + "maxzoom": 22, + "filter": ["all", ["==", "class", "gate"]], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "@building-shadow", + "line-width": { + "base": 1, + "stops": [[16, 1], [20, 3]] + }, + "line-opacity": 0.5, + "line-dasharray": [1, 2, 5, 2, 1, 2] + } + }, { + "id": "admin-2-boundaries-bg", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "admin", + "minzoom": 1, + "maxzoom": 22, + "filter": ["all", ["==", "admin_level", 2], ["==", "maritime", 0]], + "layout": { + "visibility": "visible", + "line-join": "miter", + "line-cap": "butt" + }, + "paint": { + "line-width": { + "base": 1, + "stops": [[3, 3.5], [10, 10]] + }, + "line-color": { + "base": 1, + "stops": [[6, "@land"], [8, "#f6e8e1"]] + }, + "line-opacity": { + "base": 1, + "stops": [[3, 0], [4, 0.5]] + }, + "line-translate": [0, 0], + "line-blur": { + "base": 1, + "stops": [[3, 0], [10, 2]] + } + } + }, { + "id": "admin-3-4-boundaries", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "admin", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", [">=", "admin_level", 3], ["==", "maritime", 0]], + "layout": { + "visibility": "visible", + "line-join": "round", + "line-cap": "round" + }, + "paint": { + "line-dasharray": { + "base": 1, + "stops": [[6, [2, 0]], [7, [2, 2, 6, 2]]] + }, + "line-width": { + "base": 1, + "stops": [[7, 0.75], [12, 1.5]] + }, + "line-opacity": { + "base": 1, + "stops": [[2, 0], [3, 1]] + }, + "line-color": { + "base": 1, + "stops": [[3, "#c3bfcc"], [7, "#aba8b3"]] + } + } + }, { + "id": "admin-2-boundaries", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "admin", + "minzoom": 1, + "maxzoom": 22, + "filter": ["all", ["==", "admin_level", 2], ["==", "maritime", 0], ["==", "disputed", 0]], + "layout": { + "visibility": "visible", + "line-join": "round", + "line-cap": "round" + }, + "paint": { + "line-color": "@admin", + "line-width": "@admin-2-boundary" + } + }, { + "id": "admin-2-boundaries-dispute", + "type": "line", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "admin", + "minzoom": 1, + "maxzoom": 22, + "filter": ["all", ["==", "admin_level", 2], ["==", "maritime", 0], ["==", "disputed", 1]], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-dasharray": [1.5, 1.5], + "line-color": "@admin", + "line-width": "@admin-2-boundary" + } + }, { + "id": "contour", + "type": "line", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "contour", + "minzoom": 14, + "maxzoom": 22, + "filter": ["all", ["!=", "index", 5]], + "layout": { + "visibility": "visible" + }, + "paint": { + "line-opacity": 0.07, + "line-color": "#66601a" + } + }, { + "id": "contour-index", + "type": "line", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "contour", + "minzoom": 14, + "maxzoom": 22, + "filter": ["all", ["==", "index", 5]], + "layout": { + "visibility": "visible" + }, + "paint": { + "line-opacity": 0.12, + "line-color": "#66601a" + } + }, { + "id": "country-label-lg", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 7, + "filter": ["all", ["in", "scalerank", 1, 2]], + "layout": { + "text-field": "{name_en}", + "visibility": "visible", + "text-max-size": 24, + "text-max-width": { + "base": 1, + "stops": [[0, 5], [3, 6]] + }, + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Bold" + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[1, 10], [6, 24]] + }, + "text-color": "@label-primary", + "text-halo-color": { + "base": 1, + "stops": [[2, "@country-halo"], [3, "@halo"]] + }, + "text-halo-width": 1.25 + } + }, { + "id": "country-label-md", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 8, + "filter": ["all", ["in", "scalerank", 3, 4]], + "layout": { + "text-field": { + "base": 1, + "stops": [[0, "{code}"], [2, "{name_en}"]] + }, + "visibility": "visible", + "text-max-size": 24, + "text-max-width": 6, + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular" + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[3, 10], [8, 24]] + }, + "text-color": "@label-primary", + "text-halo-color": { + "base": 1, + "stops": [[2, "@country-halo"], [3, "@halo"]] + }, + "text-halo-width": 1.25 + } + }, { + "id": "country-label-sm", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 10, + "filter": ["all", [">=", "scalerank", 5]], + "layout": { + "text-field": "{name_en}", + "visibility": "visible", + "text-max-size": 22, + "text-max-width": 6, + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular" + }, + "paint": { + "text-size": { + "base": 0.9, + "stops": [[5, 14], [9, 22]] + }, + "text-color": "@label-primary", + "text-halo-color": { + "base": 1, + "stops": [[2, "@country-halo"], [3, "@halo"]] + }, + "text-halo-width": 1.25 + } + }, { + "id": "state-label-lg", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 7, + "filter": ["all", [">=", "area", 80000]], + "layout": { + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-max-size": { + "base": 1, + "stops": [[4, 10], [7, 18]] + }, + "text-transform": "uppercase", + "text-font": "DIN Offc Pro Bold, Arial Unicode MS Regular", + "text-padding": 1, + "visibility": "visible", + "text-field": { + "base": 1, + "stops": [[0, "{abbr}"], [4, "{name_en}"]] + }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[4, 10], [7, 18]] + }, + "text-opacity": 1, + "text-color": "@label-state", + "text-halo-color": "@halo", + "text-halo-width": 1 + } + }, { + "id": "state-label-md", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 8, + "filter": ["all", ["<", "area", 80000], [">=", "area", 20000]], + "layout": { + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-max-size": { + "base": 1, + "stops": [[5, 10], [8, 16]] + }, + "text-transform": "uppercase", + "text-font": "DIN Offc Pro Bold, Arial Unicode MS Regular", + "visibility": "visible", + "text-field": { + "base": 1, + "stops": [[0, "{abbr}"], [5, "{name_en}"]] + }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[5, 10], [8, 16]] + }, + "text-opacity": 1, + "text-color": "@label-state", + "text-halo-color": "@halo", + "text-halo-width": 1 + } + }, { + "id": "state-label-sm", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 9, + "filter": ["all", ["<", "area", 20000]], + "layout": { + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-max-size": { + "base": 1, + "stops": [[6, 10], [9, 14]] + }, + "text-transform": "uppercase", + "text-font": "DIN Offc Pro Bold, Arial Unicode MS Regular", + "visibility": "visible", + "text-field": { + "base": 1, + "stops": [[0, "{abbr}"], [6, "{name_en}"]] + }, + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[6, 10], [9, 14]] + }, + "text-opacity": 1, + "text-color": "@label-state", + "text-halo-color": "@halo", + "text-halo-width": 1 + } + }, { + "id": "marine-label-lg-pt", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "marine_label", + "minzoom": 1, + "maxzoom": 4, + "filter": ["all", ["in", "labelrank", 1], ["==", "$type", "Point"]], + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.5, + "text-max-size": { + "base": 1, + "stops": [[1, 14], [4, 30]] + }, + "text-font": "DIN Offc Pro Italic, Arial Unicode MS Regular" + }, + "paint": { + "text-color": "@label-water", + "text-size": { + "base": 1, + "stops": [[1, 14], [4, 30]] + } + } + }, { + "id": "marine-label-lg-ln", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "marine_label", + "minzoom": 1, + "maxzoom": 4, + "filter": ["all", ["in", "labelrank", 1], ["==", "$type", "LineString"]], + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.1, + "text-max-size": { + "base": 1, + "stops": [[1, 14], [4, 30]] + }, + "symbol-placement": "line", + "text-font": "DIN Offc Pro Italic, Arial Unicode MS Regular" + }, + "paint": { + "text-color": "@label-water", + "text-size": { + "base": 1, + "stops": [[1, 14], [4, 30]] + } + } + }, { + "id": "marine-label-md-pt", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "marine_label", + "minzoom": 2, + "maxzoom": 8, + "filter": ["all", ["in", "labelrank", 2, 3], ["==", "$type", "Point"]], + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.15, + "text-line-height": 1.5, + "text-max-size": { + "base": 1.1, + "stops": [[2, 14], [5, 20]] + }, + "text-font": "DIN Offc Pro Italic, Arial Unicode MS Regular" + }, + "paint": { + "text-color": "@label-water", + "text-size": { + "base": 1.1, + "stops": [[2, 14], [5, 20]] + } + } + }, { + "id": "marine-label-md-ln", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "marine_label", + "minzoom": 2, + "maxzoom": 8, + "filter": ["all", ["in", "labelrank", 2, 3], ["==", "$type", "LineString"]], + "layout": { + "text-line-height": 1.1, + "symbol-min-distance": 250, + "text-max-size": 20, + "text-font": "DIN Offc Pro Italic, Arial Unicode MS Regular", + "symbol-placement": "line", + "visibility": "visible", + "text-field": "{name_en}", + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": { + "text-color": "@label-water", + "text-size": { + "base": 1.1, + "stops": [[2, 12], [5, 20]] + } + } + }, { + "id": "marine-label-sm-pt", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "marine_label", + "minzoom": 3, + "maxzoom": 10, + "filter": ["all", [">=", "labelrank", 4], ["==", "$type", "Point"]], + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.1, + "text-line-height": 1.5, + "text-max-size": 20, + "symbol-placement": "point", + "text-font": "DIN Offc Pro Italic, Arial Unicode MS Regular" + }, + "paint": { + "text-color": "@label-water", + "text-size": { + "base": 1, + "stops": [[3, 12], [6, 16]] + } + } + }, { + "id": "marine-label-sm-ln", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "marine_label", + "minzoom": 3, + "maxzoom": 10, + "filter": ["all", [">=", "labelrank", 4], ["==", "$type", "LineString"]], + "layout": { + "text-line-height": 1.1, + "symbol-min-distance": { + "base": 1, + "stops": [[4, 100], [6, 400]] + }, + "text-max-size": 16, + "text-font": "DIN Offc Pro Italic, Arial Unicode MS Regular", + "symbol-placement": "line", + "visibility": "visible", + "text-field": "{name_en}", + "text-letter-spacing": 0.1, + "text-max-width": 5 + }, + "paint": { + "text-color": "@label-water", + "text-size": { + "base": 1, + "stops": [[3, 12], [6, 16]] + } + } + }, { + "id": "place-city-lg-n", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "place_label", + "minzoom": 1, + "maxzoom": 14, + "filter": ["all", ["<=", "scalerank", 2], ["==", "type", "city"], ["in", "ldir", "N", "NE", "NW", "W"]], + "layout": { + "icon-image": "circle.sdf", + "text-max-size": "@label-city-lg-size", + "text-font": { + "base": 1, + "stops": [[7, "DIN Offc Pro Regular, Arial Unicode MS Regular"], [8, "DIN Offc Pro Medium, Arial Unicode MS Bold"]] + }, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [[7.99, [0, -0.25]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "icon-max-size": 0.4 + }, + "paint": { + "text-size": "@label-city-lg-size", + "text-color": "@label-primary", + "icon-halo-blur": 1, + "icon-halo-color": "@halo", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "@label-primary", + "text-halo-color": "@halo", + "icon-size": 0.4, + "text-halo-width": 1, + "icon-opacity": { + "base": 1, + "stops": [[7.99, 1], [8, 0]] + }, + "text-halo-blur": 1 + } + }, { + "id": "place-city-lg-s", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "place_label", + "minzoom": 1, + "maxzoom": 14, + "filter": ["all", ["<=", "scalerank", 2], ["==", "type", "city"], ["in", "ldir", "S", "SE", "SW", "E"]], + "layout": { + "icon-image": "circle.sdf", + "text-max-size": "@label-city-lg-size", + "text-font": { + "base": 1, + "stops": [[7, "DIN Offc Pro Regular, Arial Unicode MS Regular"], [8, "DIN Offc Pro Medium, Arial Unicode MS Bold"]] + }, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [[7.99, [0, 0.15]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "top"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "icon-max-size": 0.4 + }, + "paint": { + "text-size": "@label-city-lg-size", + "text-color": "@label-primary", + "icon-halo-blur": 1, + "icon-halo-color": "@halo", + "icon-halo-width": 1, + "icon-color": "@label-primary", + "text-halo-color": "@halo", + "icon-size": 0.4, + "text-halo-width": 1, + "icon-opacity": { + "base": 1, + "stops": [[7.99, 1], [8, 0]] + }, + "text-halo-blur": 1 + } + }, { + "id": "place-city-md-n", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "place_label", + "minzoom": 0, + "maxzoom": 14, + "filter": ["all", ["in", "scalerank", 3, 4, 5], ["==", "type", "city"], ["in", "ldir", "N", "NE", "NW", "W"]], + "layout": { + "icon-image": "circle.sdf", + "text-max-size": "@label-city-md-size", + "text-font": { + "base": 1, + "stops": [[7, "DIN Offc Pro Regular, Arial Unicode MS Regular"], [8, "DIN Offc Pro Medium, Arial Unicode MS Bold"]] + }, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [[7.99, [0, -0.25]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "icon-max-size": 0.35 + }, + "paint": { + "text-size": "@label-city-md-size", + "text-color": "@label-primary", + "icon-halo-blur": 1, + "icon-halo-color": "@halo", + "icon-halo-width": 1, + "icon-color": "@label-primary", + "text-halo-color": "@halo", + "icon-size": 0.35, + "text-halo-width": 1, + "icon-opacity": { + "base": 1, + "stops": [[7.99, 1], [8, 0]] + }, + "text-halo-blur": 1 + } + }, { + "id": "place-city-md-s", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "place_label", + "minzoom": 0, + "maxzoom": 14, + "filter": ["all", ["in", "scalerank", 3, 4, 5], ["==", "type", "city"], ["in", "ldir", "S", "SE", "WW", "E"]], + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "icon-image": "circle.sdf", + "text-anchor": { + "base": 1, + "stops": [[7, "top"], [8, "center"]] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, 0.1]], [8, [0, 0]]] + }, + "icon-max-size": 0.35, + "text-max-size": "@label-city-md-size", + "text-font": { + "base": 1, + "stops": [[7, "DIN Offc Pro Regular, Arial Unicode MS Regular"], [8, "DIN Offc Pro Medium, Arial Unicode MS Bold"]] + } + }, + "paint": { + "icon-size": 0.35, + "text-size": "@label-city-md-size", + "text-halo-width": 1, + "text-halo-color": "@halo", + "text-color": "@label-primary", + "text-halo-blur": 1, + "icon-color": "@label-primary", + "icon-opacity": { + "base": 1, + "stops": [[7.99, 1], [8, 0]] + } + } + }, { + "id": "place-city-sm", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "place_label", + "minzoom": 0, + "maxzoom": 14, + "filter": ["all", ["!in", "scalerank", 0, 1, 2, 3, 4, 5], ["==", "type", "city"]], + "layout": { + "icon-image": "circle.sdf", + "text-max-size": { + "base": 1, + "stops": [[6, 12], [14, 22]] + }, + "text-transform": "none", + "text-font": { + "base": 1, + "stops": [[7, "DIN Offc Pro Regular, Arial Unicode MS Regular"], [8, "DIN Offc Pro Medium, Arial Unicode MS Bold"]] + }, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [[7.99, [0, -0.2]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "icon-max-size": 0.3 + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[6, 12], [14, 22]] + }, + "text-color": "@label-primary", + "icon-halo-blur": 1, + "icon-halo-color": "@halo", + "icon-halo-width": 1, + "icon-color": "@label-primary", + "text-halo-color": "@halo", + "icon-size": 0.3, + "text-halo-width": 1.25, + "icon-opacity": { + "base": 1, + "stops": [[7.99, 1], [8, 0]] + } + } + }, { + "id": "poi-islands", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "type", "Island"]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": 14, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 0], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "center", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 7 + }, + "paint": { + "text-color": "@label-poi", + "text-halo-color": "@halo", + "text-halo-width": 1, + "text-size": { + "base": 1, + "stops": [[10, 11], [18, 16]] + } + } + }, { + "id": "place-town", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "place_label", + "minzoom": 6, + "maxzoom": 14, + "filter": ["all", ["in", "type", "town"]], + "layout": { + "icon-image": "circle.sdf", + "text-max-size": { + "base": 1, + "stops": [[7, 11.5], [15, 20]] + }, + "text-font": { + "base": 1, + "stops": [[11, "DIN Offc Pro Regular, Arial Unicode MS Regular"], [12, "DIN Offc Pro Medium, Arial Unicode MS Bold"]] + }, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [[7, [0, -0.15]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "icon-max-size": 0.3 + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[7, 11.5], [15, 20]] + }, + "text-color": "@label-primary", + "icon-halo-blur": 1, + "icon-halo-color": "@halo", + "icon-halo-width": 1, + "icon-color": "@label-primary", + "text-halo-color": "@halo", + "icon-size": 0.3, + "text-halo-width": 1.25, + "icon-opacity": { + "base": 1, + "stops": [[7.99, 1], [8, 0]] + } + } + }, { + "id": "place-village", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "place_label", + "minzoom": 8, + "maxzoom": 15, + "filter": ["all", ["in", "type", "village"]], + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-size": { + "base": 1, + "stops": [[10, 11.5], [16, 18]] + }, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular", + "text-max-width": 7 + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[10, 11.5], [16, 18]] + }, + "text-halo-color": "@halo", + "text-halo-width": 1.25, + "text-color": "@label-primary" + } + }, { + "id": "place-hamlet", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": ["all", ["in", "type", "hamlet"]], + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-size": { + "base": 1, + "stops": [[12, 11.5], [15, 16]] + }, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular" + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[12, 11.5], [15, 16]] + }, + "text-halo-color": "@halo", + "text-halo-width": 1.25, + "text-color": "@label-primary" + } + }, { + "id": "place-suburb", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": ["all", ["==", "type", "suburb"]], + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-max-size": { + "base": 1, + "stops": [[11, 11], [15, 18]] + }, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular", + "text-letter-spacing": 0.15, + "text-max-width": 7, + "text-padding": 3 + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[11, 11], [15, 18]] + }, + "text-halo-color": "rgba(255,255,255, 0.5)", + "text-halo-width": 1.75, + "text-color": "@label-neighbourhood" + } + }, { + "id": "place-neighbourhood", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": ["all", ["in", "type", "neighbourhood"]], + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-size": { + "base": 1, + "stops": [[12, 11], [16, 16]] + }, + "text-transform": "uppercase", + "text-letter-spacing": 0.1, + "text-max-width": 7, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular", + "text-padding": 3 + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[12, 11], [16, 16]] + }, + "text-halo-color": "rgba(255,255,255, 0.5)", + "text-halo-width": 1.75, + "text-color": "@label-neighbourhood", + "text-halo-blur": 0 + } + }, { + "id": "poi-islets", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "type", "Islet"]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": { + "base": 1, + "stops": [[10, 11], [14, 16]] + }, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 0], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "center", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "@label-poi", + "text-halo-color": "@halo", + "text-halo-width": 1, + "text-size": { + "base": 1, + "stops": [[10, 11], [14, 16]] + } + } + }, { + "id": "water-label", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "water_label", + "minzoom": 5, + "maxzoom": 22, + "filter": ["all"], + "layout": { + "text-field": "{name_en}", + "visibility": "visible", + "text-font": "DIN Offc Pro Italic, Arial Unicode MS Regular", + "text-max-width": 7, + "text-max-size": { + "base": 1, + "stops": [[13, 13], [18, 18]] + } + }, + "paint": { + "text-halo-width": 0, + "text-size": { + "base": 1, + "stops": [[13, 13], [18, 18]] + }, + "text-halo-color": "@halo", + "text-color": "@label-water-dark", + "text-halo-blur": 1.5 + } + }, { + "id": "airport-label", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 9, + "maxzoom": 22, + "filter": ["all", ["in", "maki", "airport", "heliport", "rocket"], ["<=", "scalerank", 2]], + "layout": { + "text-allow-overlap": false, + "symbol-min-distance": 250, + "icon-image": { + "stops": [[12, "{maki}-11"], [13, "{maki}-15"]] + }, + "text-ignore-placement": false, + "text-max-size": { + "base": 1, + "stops": [[10, 12], [18, 18]] + }, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [[12, [0, 1]], [13, [0, 1.25]]] + }, + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": { + "stops": [[12, "{ref}"], [13, "{name_en}"]] + }, + "text-letter-spacing": 0.02, + "text-max-width": 9 + }, + "paint": { + "text-color": "@label-transit", + "text-halo-color": "@halo", + "text-halo-width": 1.25, + "text-size": { + "base": 1, + "stops": [[10, 12], [18, 18]] + } + } + }, { + "id": "poi-scalerank1", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["!in", "maki", "rail-light", "rail-metro", "rail", "airport", "airfield", "heliport", "rocket", "park", "golf", "cemetery", "zoo", "campsite", "swimming", "dog-park"], ["<=", "scalerank", 1], ["!=", "type", "Island"]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "icon-image": { + "stops": [[13, "{maki}-11"], [14, "{maki}-15"]] + }, + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": "@poi-scalerank1", + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "@label-poi", + "text-halo-color": "@halo", + "text-halo-width": 1, + "text-size": "@poi-scalerank1" + } + }, { + "id": "poi-parks-scalerank1", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "maki", "park", "golf", "cemetery", "zoo", "campsite", "swimming", "dog-park"], ["<=", "scalerank", 1]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "icon-image": { + "stops": [[13, "{maki}-11"], [14, "{maki}-15"]] + }, + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": "@poi-scalerank1", + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "@label-park", + "text-halo-color": "@halo", + "text-halo-width": 1, + "text-halo-blur": 0, + "text-size": "@poi-scalerank1" + } + }, { + "id": "rail-label", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 12, + "maxzoom": 22, + "filter": ["all", ["in", "type", "Rail Station"]], + "layout": { + "symbol-min-distance": 250, + "icon-image": "{network}-11", + "symbol-avoid-edges": true, + "text-max-size": { + "base": 1, + "stops": [[13, 6], [14, 11], [16, 11], [20, 13]] + }, + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "icon-allow-overlap": false, + "symbol-placement": "point", + "text-justify": "center", + "visibility": "visible", + "text-offset": [0, 1], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": { + "base": 1, + "stops": [[0, ""], [13, "{name_en}"]] + }, + "text-letter-spacing": 0.02, + "icon-padding": 0, + "text-max-width": 7 + }, + "paint": { + "text-color": "@label-poi", + "text-halo-color": "@halo", + "text-halo-width": 1.5, + "text-size": "@poi-scalerank3", + "icon-halo-width": 4, + "icon-halo-color": "#fff", + "text-opacity": { + "base": 1, + "stops": [[13.99, 0], [14, 1]] + } + } + }, { + "id": "poi-parks-scalerank2", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["in", "maki", "park", "golf", "cemetery", "zoo", "campsite", "swimming", "dog-park"], ["==", "scalerank", 2]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "icon-image": { + "stops": [[14, "{maki}-11"], [15, "{maki}-15"]] + }, + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": "@poi-scalerank2", + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 1.25], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "@label-park", + "text-halo-color": "@halo", + "text-halo-width": 1.25, + "text-size": "@poi-scalerank2" + } + }, { + "id": "poi-scalerank2", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 13, + "maxzoom": 22, + "filter": ["all", ["!in", "maki", "rail-light", "rail-metro", "rail", "airport", "airfield", "heliport", "rocket", "park", "golf", "cemetery", "zoo", "campsite", "swimming", "dog-park"], ["==", "scalerank", 2]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "icon-image": { + "stops": [[14, "{maki}-11"], [15, "{maki}-15"]] + }, + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": "@poi-scalerank2", + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 1.25], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "@label-poi", + "text-halo-color": "@halo", + "text-halo-width": 1.25, + "text-size": "@poi-scalerank2" + } + }, { + "id": "interstate_motorway_shields", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road_label", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "shield", "us-interstate", "us-interstate-business", "us-interstate-duplex"], ["<=", "reflen", 6]], + "layout": { + "text-allow-overlap": false, + "symbol-min-distance": 1000, + "icon-image": { + "base": 1, + "stops": [[15, "{shield}-{reflen}-small"], [16, "{shield}-{reflen}-large"]] + }, + "icon-rotation-alignment": "viewport", + "symbol-avoid-edges": false, + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": 11, + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [11, "line"]] + }, + "text-padding": 20, + "visibility": "visible", + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 20 + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[16, 9], [16.01, 11]] + }, + "text-color": "#fff", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "@halo", + "text-halo-width": 0 + } + }, { + "id": "other-motorway-shields", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road_label", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["!in", "shield", "us-interstate", "us-interstate-business", "us-interstate-duplex"], ["<=", "reflen", 6]], + "layout": { + "text-allow-overlap": false, + "symbol-min-distance": 1000, + "icon-image": { + "base": 1, + "stops": [[15, "{shield}-{reflen}-small"], [16, "{shield}-{reflen}-large"]] + }, + "icon-rotation-alignment": "viewport", + "symbol-avoid-edges": false, + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": 11, + "text-font": "DIN Offc Pro Bold, Arial Unicode MS Regular", + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [11, "line"]] + }, + "text-padding": 20, + "visibility": "visible", + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 20 + }, + "paint": { + "text-size": { + "base": 1, + "stops": [[16, 9], [16.01, 11]] + }, + "text-color": "@label-road", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "@halo", + "text-halo-width": 0 + } + }, { + "id": "road-label-large", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road_label", + "minzoom": 0, + "maxzoom": 22, + "filter": ["all", ["in", "class", "main", "motorway"]], + "layout": { + "text-allow-overlap": false, + "symbol-min-distance": 500, + "text-ignore-placement": false, + "text-max-angle": 30, + "text-max-size": { + "base": 1, + "stops": [[9, 10], [20, 16]] + }, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular", + "symbol-placement": "line", + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "map", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "@label-road", + "text-halo-color": "rgba(255,255,255, 0.75)", + "text-halo-width": 1, + "text-size": { + "base": 1, + "stops": [[9, 10], [20, 16]] + }, + "text-halo-blur": 1 + } + }, { + "id": "road-label-medium", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road_label", + "minzoom": 11, + "maxzoom": 22, + "filter": ["all", ["in", "class", "street", "street_limited"], ["==", "$type", "LineString"]], + "layout": { + "symbol-min-distance": 500, + "text-max-angle": 30, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular", + "symbol-placement": "line", + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "map", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "@label-road", + "text-halo-color": "@halo", + "text-halo-width": 1, + "text-size": { + "base": 1, + "stops": [[11, 10], [20, 14]] + } + } + }, { + "id": "road-label-small", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "road_label", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["!in", "class", "motorway", "main", "street_limited", "street"], ["==", "$type", "LineString"]], + "layout": { + "symbol-min-distance": 500, + "text-ignore-placement": false, + "text-max-angle": 30, + "text-max-size": 12, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular", + "symbol-placement": "line", + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "map", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "@label-road", + "text-halo-color": "@halo", + "text-halo-width": 1.25, + "text-size": { + "base": 1, + "stops": [[15, 10], [20, 13]] + }, + "text-halo-blur": 1 + } + }, { + "id": "poi-parks-scalerank3", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["in", "maki", "park", "cemetery", "golf", "zoo"], ["==", "scalerank", 3]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "icon-image": "{maki}-11", + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": "@poi-scalerank3", + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "@label-park", + "text-halo-color": "@halo", + "text-halo-width": 1, + "text-size": "@poi-scalerank3" + } + }, { + "id": "poi-scalerank3", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 15, + "maxzoom": 22, + "filter": ["all", ["!in", "maki", "rail-light", "rail-metro", "rail", "airport", "airfield", "heliport", "rocket", "park", "golf", "cemetery", "zoo", "campsite", "swimming", "dog-park"], ["==", "scalerank", 3]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "icon-image": "{maki}-11", + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": "@poi-scalerank3", + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "@label-poi", + "text-halo-color": "@halo", + "text-halo-width": 1, + "text-size": "@poi-scalerank3" + } + }, { + "id": "poi-parks_scalerank4", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 16, + "maxzoom": 22, + "filter": ["all", ["in", "maki", "park", "cemetery", "golf", "zoo", "playground", ""], ["==", "scalerank", 4]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "icon-image": "{maki}-11", + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": "@poi-scalerank4", + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "@label-park", + "text-halo-color": "@halo", + "text-halo-width": 1, + "text-size": "@poi-scalerank4" + } + }, { + "id": "poi-scalerank4-l1", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 16, + "maxzoom": 22, + "filter": ["all", ["!in", "maki", "rail-light", "rail-metro", "rail", "airport", "airfield", "heliport", "rocket", "park", "golf", "cemetery", "zoo", "campsite", "swimming", "dog-park"], ["==", "scalerank", 4], ["<=", "localrank", 14]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "icon-image": "{maki}-11", + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": "@poi-scalerank4", + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 1, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "@label-poi", + "text-halo-color": "@halo", + "text-halo-width": 1, + "text-size": "@poi-scalerank4" + } + }, { + "id": "poi-scalerank4-l15", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "poi_label", + "minzoom": 17, + "maxzoom": 22, + "filter": ["all", ["!in", "maki", "rail-light", "rail-metro", "rail", "airport", "airfield", "heliport", "rocket", "park", "golf", "cemetery", "zoo", "campsite", "swimming", "dog-park"], ["==", "scalerank", 4], [">=", "localrank", 15]], + "layout": { + "text-line-height": 1.2, + "text-allow-overlap": false, + "symbol-min-distance": 250, + "icon-image": "{maki}-11", + "text-ignore-placement": false, + "text-max-angle": 38, + "text-max-size": "@poi-scalerank4", + "text-font": "DIN Offc Pro Medium, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [0, 1], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "@label-poi", + "text-halo-color": "@halo", + "text-halo-width": 1, + "text-size": "@poi-scalerank4" + } + }, { + "id": "waterway-label", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "waterway_label", + "minzoom": 12, + "maxzoom": 22, + "filter": ["all", ["==", "class", "river"]], + "layout": { + "text-field": "{name_en}", + "visibility": "visible", + "text-font": "DIN Offc Pro Italic, Arial Unicode MS Regular", + "symbol-placement": "line", + "text-max-angle": 30 + }, + "paint": { + "text-halo-width": 0.5, + "text-size": { + "base": 1, + "stops": [[13, 12], [18, 16]] + }, + "text-halo-color": "@halo", + "text-color": "@label-water-dark", + "text-halo-blur": 0.5 + } + }, { + "id": "contour-index-label", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-terrain-v2", + "source-layer": "contour", + "minzoom": 14, + "maxzoom": 22, + "filter": ["all", ["==", "index", 5]], + "layout": { + "text-field": "{ele} m", + "symbol-placement": "line", + "text-max-size": 9.5, + "text-max-angle": 25, + "visibility": "visible", + "text-padding": 5, + "text-font": "DIN Offc Pro Regular, Arial Unicode MS Regular" + }, + "paint": { + "text-size": 9.5, + "text-color": "#a7a696", + "text-halo-width": 1, + "text-halo-blur": 1, + "text-halo-color": "rgba(237,233,217, 0.25)" + } + }, { + "id": "housenum-label", + "type": "symbol", + "source": "mapbox://mapbox.mapbox-streets-v6", + "source-layer": "housenum_label", + "minzoom": 17, + "maxzoom": 22, + "layout": { + "visibility": "visible", + "text-field": "{house_num}", + "text-font": "DIN Offc Pro Italic, Arial Unicode MS Regular", + "symbol-placement": "point", + "text-max-size": 9.5, + "text-padding": 4, + "text-max-width": 7 + }, + "paint": { + "text-size": 9.5, + "text-color": "#b2aca5", + "text-halo-color": "@building", + "text-halo-width": 1.5, + "text-halo-blur": 0 + } + }], + "owner": "nicki", + "modified": "2015-04-22T21:56:16.821Z", + "created": "2015-04-20T17:11:47.261Z", + "id": "nicki.be444c8f" +} \ No newline at end of file diff --git a/ios/benchmark/assets/tiles/download.sh b/ios/benchmark/assets/tiles/download.sh new file mode 100755 index 000000000..23b00f924 --- /dev/null +++ b/ios/benchmark/assets/tiles/download.sh @@ -0,0 +1,175 @@ +#!/usr/bin/env bash + +set -u + +LIST=( + # paris + "mapbox.mapbox-streets-v6/11/1037/704.vector.pbf" + "mapbox.mapbox-streets-v6/11/1037/705.vector.pbf" + "mapbox.mapbox-streets-v6/11/1038/704.vector.pbf" + "mapbox.mapbox-streets-v6/11/1038/705.vector.pbf" + "mapbox.mapbox-streets-v6/11/1036/704.vector.pbf" + "mapbox.mapbox-streets-v6/11/1037/703.vector.pbf" + "mapbox.mapbox-streets-v6/11/1036/705.vector.pbf" + "mapbox.mapbox-streets-v6/11/1038/703.vector.pbf" + "mapbox.mapbox-streets-v6/11/1036/703.vector.pbf" + "mapbox.mapbox-terrain-v2/11/1037/704.vector.pbf" + "mapbox.mapbox-terrain-v2/11/1037/705.vector.pbf" + "mapbox.mapbox-terrain-v2/11/1038/704.vector.pbf" + "mapbox.mapbox-terrain-v2/11/1038/705.vector.pbf" + "mapbox.mapbox-terrain-v2/11/1036/704.vector.pbf" + "mapbox.mapbox-terrain-v2/11/1037/703.vector.pbf" + "mapbox.mapbox-terrain-v2/11/1036/705.vector.pbf" + "mapbox.mapbox-terrain-v2/11/1038/703.vector.pbf" + "mapbox.mapbox-terrain-v2/11/1036/703.vector.pbf" + + # paris2 + "mapbox.mapbox-streets-v6/13/4150/2819.vector.pbf" + "mapbox.mapbox-streets-v6/13/4149/2819.vector.pbf" + "mapbox.mapbox-streets-v6/13/4150/2818.vector.pbf" + "mapbox.mapbox-streets-v6/13/4149/2820.vector.pbf" + "mapbox.mapbox-streets-v6/13/4148/2819.vector.pbf" + "mapbox.mapbox-streets-v6/13/4149/2818.vector.pbf" + "mapbox.mapbox-streets-v6/13/4150/2817.vector.pbf" + "mapbox.mapbox-streets-v6/13/4148/2820.vector.pbf" + "mapbox.mapbox-streets-v6/13/4148/2818.vector.pbf" + "mapbox.mapbox-streets-v6/13/4149/2817.vector.pbf" + "mapbox.mapbox-terrain-v2/13/4150/2819.vector.pbf" + "mapbox.mapbox-terrain-v2/13/4149/2819.vector.pbf" + "mapbox.mapbox-terrain-v2/13/4150/2818.vector.pbf" + "mapbox.mapbox-terrain-v2/13/4149/2820.vector.pbf" + "mapbox.mapbox-terrain-v2/13/4148/2819.vector.pbf" + "mapbox.mapbox-terrain-v2/13/4149/2818.vector.pbf" + "mapbox.mapbox-terrain-v2/13/4150/2817.vector.pbf" + "mapbox.mapbox-terrain-v2/13/4148/2820.vector.pbf" + "mapbox.mapbox-terrain-v2/13/4148/2818.vector.pbf" + "mapbox.mapbox-terrain-v2/13/4149/2817.vector.pbf" + + # alps + "mapbox.mapbox-streets-v6/6/34/23.vector.pbf" + "mapbox.mapbox-streets-v6/6/34/22.vector.pbf" + "mapbox.mapbox-streets-v6/6/33/23.vector.pbf" + "mapbox.mapbox-streets-v6/6/33/22.vector.pbf" + "mapbox.mapbox-streets-v6/6/34/21.vector.pbf" + "mapbox.mapbox-streets-v6/6/32/23.vector.pbf" + "mapbox.mapbox-streets-v6/6/32/22.vector.pbf" + "mapbox.mapbox-streets-v6/6/33/21.vector.pbf" + "mapbox.mapbox-streets-v6/6/32/21.vector.pbf" + "mapbox.mapbox-terrain-v2/6/34/23.vector.pbf" + "mapbox.mapbox-terrain-v2/6/34/22.vector.pbf" + "mapbox.mapbox-terrain-v2/6/33/23.vector.pbf" + "mapbox.mapbox-terrain-v2/6/33/22.vector.pbf" + "mapbox.mapbox-terrain-v2/6/34/21.vector.pbf" + "mapbox.mapbox-terrain-v2/6/32/23.vector.pbf" + "mapbox.mapbox-terrain-v2/6/32/22.vector.pbf" + "mapbox.mapbox-terrain-v2/6/33/21.vector.pbf" + "mapbox.mapbox-terrain-v2/6/32/21.vector.pbf" + + # us east + "mapbox.mapbox-streets-v6/5/9/12.vector.pbf" + "mapbox.mapbox-streets-v6/5/8/12.vector.pbf" + "mapbox.mapbox-streets-v6/5/9/13.vector.pbf" + "mapbox.mapbox-streets-v6/5/8/13.vector.pbf" + "mapbox.mapbox-streets-v6/5/9/11.vector.pbf" + "mapbox.mapbox-streets-v6/5/7/12.vector.pbf" + "mapbox.mapbox-streets-v6/5/8/11.vector.pbf" + "mapbox.mapbox-streets-v6/5/7/13.vector.pbf" + "mapbox.mapbox-streets-v6/5/7/11.vector.pbf" + "mapbox.mapbox-terrain-v2/5/9/12.vector.pbf" + "mapbox.mapbox-terrain-v2/5/8/12.vector.pbf" + "mapbox.mapbox-terrain-v2/5/9/13.vector.pbf" + "mapbox.mapbox-terrain-v2/5/8/13.vector.pbf" + "mapbox.mapbox-terrain-v2/5/9/11.vector.pbf" + "mapbox.mapbox-terrain-v2/5/7/12.vector.pbf" + "mapbox.mapbox-terrain-v2/5/8/11.vector.pbf" + "mapbox.mapbox-terrain-v2/5/7/13.vector.pbf" + "mapbox.mapbox-terrain-v2/5/7/11.vector.pbf" + + # greater la + "mapbox.mapbox-streets-v6/9/88/204.vector.pbf" + "mapbox.mapbox-streets-v6/9/88/205.vector.pbf" + "mapbox.mapbox-streets-v6/9/89/204.vector.pbf" + "mapbox.mapbox-streets-v6/9/89/205.vector.pbf" + "mapbox.mapbox-streets-v6/9/87/204.vector.pbf" + "mapbox.mapbox-streets-v6/9/88/203.vector.pbf" + "mapbox.mapbox-streets-v6/9/87/205.vector.pbf" + "mapbox.mapbox-streets-v6/9/89/203.vector.pbf" + "mapbox.mapbox-streets-v6/9/87/203.vector.pbf" + "mapbox.mapbox-terrain-v2/9/88/204.vector.pbf" + "mapbox.mapbox-terrain-v2/9/88/205.vector.pbf" + "mapbox.mapbox-terrain-v2/9/89/204.vector.pbf" + "mapbox.mapbox-terrain-v2/9/89/205.vector.pbf" + "mapbox.mapbox-terrain-v2/9/87/204.vector.pbf" + "mapbox.mapbox-terrain-v2/9/88/203.vector.pbf" + "mapbox.mapbox-terrain-v2/9/87/205.vector.pbf" + "mapbox.mapbox-terrain-v2/9/89/203.vector.pbf" + "mapbox.mapbox-terrain-v2/9/87/203.vector.pbf" + + # sf + "mapbox.mapbox-streets-v6/14/2621/6333.vector.pbf" + "mapbox.mapbox-streets-v6/14/2620/6333.vector.pbf" + "mapbox.mapbox-streets-v6/14/2621/6334.vector.pbf" + "mapbox.mapbox-streets-v6/14/2620/6334.vector.pbf" + "mapbox.mapbox-streets-v6/14/2621/6332.vector.pbf" + "mapbox.mapbox-streets-v6/14/2619/6333.vector.pbf" + "mapbox.mapbox-streets-v6/14/2620/6332.vector.pbf" + "mapbox.mapbox-streets-v6/14/2619/6334.vector.pbf" + "mapbox.mapbox-streets-v6/14/2619/6332.vector.pbf" + "mapbox.mapbox-terrain-v2/14/2621/6333.vector.pbf" + "mapbox.mapbox-terrain-v2/14/2620/6333.vector.pbf" + "mapbox.mapbox-terrain-v2/14/2621/6334.vector.pbf" + "mapbox.mapbox-terrain-v2/14/2620/6334.vector.pbf" + "mapbox.mapbox-terrain-v2/14/2621/6332.vector.pbf" + "mapbox.mapbox-terrain-v2/14/2619/6333.vector.pbf" + "mapbox.mapbox-terrain-v2/14/2620/6332.vector.pbf" + "mapbox.mapbox-terrain-v2/14/2619/6334.vector.pbf" + "mapbox.mapbox-terrain-v2/14/2619/6332.vector.pbf" + + # oakland + "mapbox.mapbox-streets-v6/12/657/1582.vector.pbf" + "mapbox.mapbox-streets-v6/12/657/1583.vector.pbf" + "mapbox.mapbox-streets-v6/12/658/1582.vector.pbf" + "mapbox.mapbox-streets-v6/12/658/1583.vector.pbf" + "mapbox.mapbox-streets-v6/12/656/1582.vector.pbf" + "mapbox.mapbox-streets-v6/12/657/1581.vector.pbf" + "mapbox.mapbox-streets-v6/12/656/1583.vector.pbf" + "mapbox.mapbox-streets-v6/12/658/1581.vector.pbf" + "mapbox.mapbox-streets-v6/12/656/1581.vector.pbf" + "mapbox.mapbox-terrain-v2/12/657/1582.vector.pbf" + "mapbox.mapbox-terrain-v2/12/657/1583.vector.pbf" + "mapbox.mapbox-terrain-v2/12/658/1582.vector.pbf" + "mapbox.mapbox-terrain-v2/12/658/1583.vector.pbf" + "mapbox.mapbox-terrain-v2/12/656/1582.vector.pbf" + "mapbox.mapbox-terrain-v2/12/657/1581.vector.pbf" + "mapbox.mapbox-terrain-v2/12/656/1583.vector.pbf" + "mapbox.mapbox-terrain-v2/12/658/1581.vector.pbf" + "mapbox.mapbox-terrain-v2/12/656/1581.vector.pbf" + + # germany + "mapbox.mapbox-streets-v6/6/34/21.vector.pbf" + "mapbox.mapbox-streets-v6/6/34/22.vector.pbf" + "mapbox.mapbox-streets-v6/6/33/21.vector.pbf" + "mapbox.mapbox-streets-v6/6/33/22.vector.pbf" + "mapbox.mapbox-streets-v6/6/34/20.vector.pbf" + "mapbox.mapbox-streets-v6/6/32/21.vector.pbf" + "mapbox.mapbox-streets-v6/6/33/20.vector.pbf" + "mapbox.mapbox-streets-v6/6/32/22.vector.pbf" + "mapbox.mapbox-streets-v6/6/32/20.vector.pbf" + "mapbox.mapbox-terrain-v2/6/34/21.vector.pbf" + "mapbox.mapbox-terrain-v2/6/34/22.vector.pbf" + "mapbox.mapbox-terrain-v2/6/33/21.vector.pbf" + "mapbox.mapbox-terrain-v2/6/33/22.vector.pbf" + "mapbox.mapbox-terrain-v2/6/34/20.vector.pbf" + "mapbox.mapbox-terrain-v2/6/32/21.vector.pbf" + "mapbox.mapbox-terrain-v2/6/33/20.vector.pbf" + "mapbox.mapbox-terrain-v2/6/32/22.vector.pbf" + "mapbox.mapbox-terrain-v2/6/32/20.vector.pbf" +) + +for OUTPUT in ${LIST[@]} ; do + if [ ! -f "${OUTPUT}" ] ; then + mkdir -p "`dirname "${OUTPUT}"`" + echo "Downloading tile '${OUTPUT}'" + curl -# "https://a.tiles.mapbox.com/v4/${OUTPUT}?access_token=${MAPBOX_ACCESS_TOKEN}" | gunzip > "${OUTPUT}" + fi +done diff --git a/ios/benchmark/assets/tiles/mapbox.mapbox-streets-v6.json b/ios/benchmark/assets/tiles/mapbox.mapbox-streets-v6.json new file mode 100644 index 000000000..1d556bf6a --- /dev/null +++ b/ios/benchmark/assets/tiles/mapbox.mapbox-streets-v6.json @@ -0,0 +1 @@ +{"attribution":"© Mapbox © OpenStreetMap Improve this map","bounds":[-180,-85.0511,180,85.0511],"center":[0,0,0],"description":"","filesize":0,"format":"pbf","id":"mapbox.mapbox-streets-v6","maskLevel":8,"maxzoom":15,"minzoom":0,"name":"Mapbox Streets V6","private":true,"scheme":"xyz","tilejson":"2.0.0","tiles":["asset://tiles/mapbox.mapbox-streets-v6/{z}/{x}/{y}.vector.pbf"],"vector_layers":[{"description":"","fields":{"class":"One of: cemetery, hospital, industrial, park, parking, pitch, sand, school, wood","osm_id":"Unique OSM ID number","type":"OSM tag, more specific than class"},"id":"landuse"},{"description":"","fields":{"class":"One of: river, canal, stream, stream_intermittent, ditch, drain","osm_id":"Unique OSM ID number","type":"One of: river, canal, stream, ditch, drain"},"id":"waterway"},{"description":"","fields":{"osm_id":"Unique OSM ID number"},"id":"water"},{"description":"","fields":{"osm_id":"Unique OSM ID number","type":"One of: runway, taxiway, apron"},"id":"aeroway"},{"description":"","fields":{"class":"One of: fence, hedge, cliff, gate","osm_id":"Unique OSM ID number"},"id":"barrier_line"},{"description":"","fields":{"osm_id":"Unique OSM ID number"},"id":"building"},{"description":"","fields":{"class":"One of: wetland, wetland_noveg","osm_id":"Unique OSM ID number"},"id":"landuse_overlay"},{"description":"","fields":{"class":"One of: motorway, motorway_link, main, street, street_limited, service, driveway, path, major_rail, minor_rail, aerialway","layer":"Number used for ordering overlapping tunnels","oneway":"Number. Oneway roads are 1, all others are 0.","osm_id":"Unique OSM ID number","type":"The value of the tunnel's highway tag"},"id":"tunnel"},{"description":"","fields":{"class":"One of: motorway, motorway_link, main, street, street_limited, service, driveway, path, major_rail, minor_rail, aerialway","oneway":"Number. Oneway roads are 1, all others are 0.","osm_id":"Unique OSM ID number","type":"The value of the road's highway tag"},"id":"road"},{"description":"","fields":{"class":"One of: motorway, motorway_link, main, street, street_limited, service, driveway, path, major_rail, minor_rail, aerialway","layer":"Number used for ordering overlapping bridges","oneway":"Number. Oneway bridges are 1, all others are 0.","osm_id":"Unique OSM ID number","type":"The value of the bridge's highway tag"},"id":"bridge"},{"description":"","fields":{"admin_level":"The OSM administrative level of the boundary","disputed":"Number. Disputed boundaries are 1, all others are 0.","maritime":"Number. Maritime boundaries are 1, all others are 0."},"id":"admin"},{"description":"","fields":{"code":"ISO 3166-1 Alpha-2 code","name":"Local name of the country","name_de":"German name of the country","name_en":"English name of the country","name_es":"Spanish name of the country","name_fr":"French name of the country","name_ru":"Russian name of the country","name_zh":"Chinese name of the country","osm_id":"Unique OSM ID number","parent":"ISO 3166-1 Alpha-2 code of the administering/parent state, if any","scalerank":"Number, 1-6. Useful for styling text sizes.","type":"One of: country, territory, disputed territory, sar"},"id":"country_label"},{"description":"","fields":{"labelrank":"Number, 1-6. Useful for styling text sizes.","name":"Local or international name of the water body","name_de":"German name of the water body","name_en":"English name of the water body","name_es":"Spanish name of the water body","name_fr":"French name of the water body","name_ru":"Russian name of the water body","name_zh":"Chinese name of the water body","placement":"One of: point, line"},"id":"marine_label"},{"description":"","fields":{"abbr":"Abbreviated state name","area":"The area of the state in kilometers²","name":"Local name of the state","name_de":"German name of the state","name_en":"English name of the state","name_es":"Spanish name of the state","name_fr":"French name of the state","name_ru":"Russian name of the state","name_zh":"Chinese name of the state","osm_id":"Unique OSM ID number"},"id":"state_label"},{"description":"","fields":{"capital":"Admin level the city is a capital of, if any. One of: 2, 3, 4, null","ldir":"A hint for label placement at low zoom levels. One of: N, E, S, W, NE, SE, SW, NW, null","localrank":"Number. Priority relative to nearby places. Useful for limiting label density.","name":"Local name of the place","name_de":"German name of the place","name_en":"English name of the place","name_es":"Spanish name of the place","name_fr":"French name of the place","name_ru":"Russian name of the place","name_zh":"Chinese name of the place","osm_id":"Unique OSM ID number","scalerank":"Number, 0-9 or null. Useful for styling text & marker sizes.","type":"One of: city, town, village, hamlet, suburb, neighbourhood"},"id":"place_label"},{"description":"","fields":{"area":"The area of the water polygon in Mercator meters²","name":"Local name of the water body","name_de":"German name of the water body","name_en":"English name of the water body","name_es":"Spanish name of the water body","name_fr":"French name of the water body","name_ru":"Russian name of the water body","name_zh":"Chinese name of the water body","osm_id":"Unique OSM ID number"},"id":"water_label"},{"description":"","fields":{"address":"Street address of the POI","localrank":"Number. Priority relative to nearby POIs. Useful for limiting label density.","maki":"The name of the Maki icon that should be used for the POI","name":"Local name of the POI","name_de":"German name of the POI","name_en":"English name of the POI","name_es":"Spanish name of the POI","name_fr":"French name of the POI","name_ru":"Russian name of the POI","name_zh":"Chinese name of the POI","network":"For rail stations, the network(s) that the station serves. Useful for icon styling.","osm_id":"Unique OSM ID number","ref":"Short reference code, if any","scalerank":"Number. 1-4. Useful for styling icon sizes and minimum zoom levels.","type":"The original OSM tag value","website":"URL of the POI"},"id":"poi_label"},{"description":"","fields":{"class":"One of: motorway, motorway_link, main, street, street_limited, service, driveway, path","len":"Number. Length of the road segment in Mercator meters.","localrank":"Number. Used for shield points only. Priority relative to nearby shields. Useful for limiting shield density.","name":"Local name of the road","name_de":"German name of the road","name_en":"English name of the road","name_es":"Spanish name of the road","name_fr":"French name of the road","name_ru":"Russian name of the road","name_zh":"Chinese name of the road","osm_id":"Unique OSM ID number","ref":"Route number of the road","reflen":"Number. How many characters long the ref tag is. Useful for shield styling.","shield":"The shield style to use. One of: default, mx-federal, mx-state, us-highway, us-highway-alternate, us-highway-business, us-highway-duplex, us-interstate, us-interstate-business, us-interstate-duplex, us-interstate-truck, us-state"},"id":"road_label"},{"description":"","fields":{"class":"One of: river, canal, stream, stream_intermittent","name":"Local name of the waterway","name_de":"German name of the waterway","name_en":"English name of the waterway","name_es":"Spanish name of the waterway","name_fr":"French name of the waterway","name_ru":"Russian name of the waterway","name_zh":"Chinese name of the waterway","osm_id":"Unique OSM ID number","type":"One of: river, canal, stream"},"id":"waterway_label"},{"description":"","fields":{"house_num":"House number","osm_id":"Unique OSM ID number"},"id":"housenum_label"}]} \ No newline at end of file diff --git a/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2.json b/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2.json new file mode 100644 index 000000000..4ee001abd --- /dev/null +++ b/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2.json @@ -0,0 +1 @@ +{"attribution":"© Mapbox © OpenStreetMap Improve this map","bounds":[-180,-85.0511,180,85.0511],"center":[0,0,3],"description":"","filesize":0,"format":"pbf","id":"mapbox.mapbox-terrain-v2","maskLevel":9,"maxzoom":14,"minzoom":0,"name":"Mapbox Terrain V2","private":true,"scheme":"xyz","tilejson":"2.0.0","tiles":["asset://tiles/mapbox.mapbox-terrain-v2/{z}/{x}/{y}.vector.pbf"],"vector_layers":[{"description":"Generalized landcover classification","fields":{"class":"One of: wood, scrub, grass, crop, snow"},"id":"landcover","maxzoom":22,"minzoom":0},{"description":"","fields":{"class":"One of: shadow, highlight","level":"Brightness %. One of: 94, 90, 89, 78, 67, 56"},"id":"hillshade","maxzoom":22,"minzoom":0},{"description":"Elevation contour polygons","fields":{"ele":"Integer. The elevation of the contour in meters.","index":"Indicator for every 2nd, 5th, or 10th contour. Coastlines are given -1. One of: 2, 5, 10, -1, null"},"id":"contour","maxzoom":22,"minzoom":0}]} \ No newline at end of file diff --git a/ios/benchmark/benchmark-ios.gypi b/ios/benchmark/benchmark-ios.gypi new file mode 100644 index 000000000..0a3440d5c --- /dev/null +++ b/ios/benchmark/benchmark-ios.gypi @@ -0,0 +1,63 @@ +{ + 'includes': [ + '../../gyp/common.gypi', + ], + 'targets': [ + { 'target_name': 'ios-bench', + 'product_name': 'Bench GL', + 'type': 'executable', + 'product_extension': 'app', + 'mac_bundle': 1, + 'mac_bundle_resources': [ + ' +#import + +#include "locations.hpp" + +#include + +@interface MBXBenchViewController () + +@property (nonatomic) MGLMapView *mapView; + +@end + +@implementation MBXBenchViewController + +#pragma mark - Setup + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + NSURL* url = [[NSURL alloc] initWithString:@"asset://styles/mapbox-streets-v7.json"]; + self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds accessToken:nil styleURL:url]; + self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.mapView.delegate = self; + self.mapView.zoomEnabled = NO; + self.mapView.scrollEnabled = NO; + self.mapView.rotateEnabled = NO; + self.mapView.userInteractionEnabled = YES; + [self.mapView setDebugActive:NO]; + + [self startBenchmarkIteration]; + + [self.view addSubview:self.mapView]; + +} + +using Clock = std::chrono::steady_clock; +using TimePoint = Clock::time_point; +template +inline int64_t Microseconds(Duration d) { + return std::chrono::duration_cast(d).count(); +} + +size_t idx = 0; +enum class State { None, WaitingForAssets, WarmingUp, Benchmarking } state = State::None; +int frames = 0; +TimePoint started; +std::vector> result; + +static const int warmupDuration = 20; // frames +static const int benchmarkDuration = 200; // frames + +- (void)startBenchmarkIteration +{ + if (mbgl::bench::locations.size() > idx) { + const auto& location = mbgl::bench::locations[idx]; + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(location.latitude, location.longitude) zoomLevel:location.zoom animated:NO]; + self.mapView.direction = location.bearing; + state = State::WaitingForAssets; + NSLog(@"Benchmarking \"%s\"", location.name.c_str()); + NSLog(@"- Loading assets..."); + } else { + // Do nothing. The benchmark is completed. + NSLog(@"Benchmark completed."); + NSLog(@"Result:"); + size_t colWidth = 0; + for (const auto& row : result) { + colWidth = std::max(row.first.size(), colWidth); + } + for (const auto& row : result) { + NSLog(@"| %-*s | %4.1f fps |", int(colWidth), row.first.c_str(), row.second); + } + exit(0); + } +} + +- (void)mapViewDidFinishRenderingMap:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered +{ + (void)mapView; + (void)fullyRendered; + + if (state == State::Benchmarking) + { + frames++; + if (frames >= benchmarkDuration) + { + state = State::None; + + // Report FPS + const auto duration = Microseconds(Clock::now() - started); + const auto fps = double(frames * 1e6) / duration; + result.emplace_back(mbgl::bench::locations[idx].name, fps); + NSLog(@"- FPS: %.1f", fps); + + // Start benchmarking the next location. + idx++; + [self startBenchmarkIteration]; + } else { + [mapView invalidate]; + } + return; + } + + else if (state == State::WarmingUp) + { + frames++; + if (frames >= warmupDuration) + { + frames = 0; + state = State::Benchmarking; + started = Clock::now(); + NSLog(@"- Benchmarking for %d frames...", benchmarkDuration); + } + [mapView invalidate]; + return; + } + + else if (state == State::WaitingForAssets) + { + if ([mapView isFullyLoaded]) + { + // Start the benchmarking timer. + state = State::WarmingUp; + [self.mapView emptyMemoryCache]; + NSLog(@"- Warming up for %d frames...", warmupDuration); + [mapView invalidate]; + } + return; + } +} + +- (NSUInteger)supportedInterfaceOrientations +{ + return UIInterfaceOrientationMaskLandscape; +} + +@end diff --git a/ios/benchmark/fo/benchmark-ios.gypi b/ios/benchmark/fo/benchmark-ios.gypi new file mode 100644 index 000000000..0a3440d5c --- /dev/null +++ b/ios/benchmark/fo/benchmark-ios.gypi @@ -0,0 +1,63 @@ +{ + 'includes': [ + '../../gyp/common.gypi', + ], + 'targets': [ + { 'target_name': 'ios-bench', + 'product_name': 'Bench GL', + 'type': 'executable', + 'product_extension': 'app', + 'mac_bundle': 1, + 'mac_bundle_resources': [ + ' + + + + + diff --git a/ios/benchmark/img/Icon@2x.png b/ios/benchmark/img/Icon@2x.png new file mode 100644 index 000000000..ff5ea0c07 Binary files /dev/null and b/ios/benchmark/img/Icon@2x.png differ diff --git a/ios/benchmark/img/iTunesArtwork.png b/ios/benchmark/img/iTunesArtwork.png new file mode 100644 index 000000000..f87c8734b Binary files /dev/null and b/ios/benchmark/img/iTunesArtwork.png differ diff --git a/ios/benchmark/img/iTunesArtwork@2x.png b/ios/benchmark/img/iTunesArtwork@2x.png new file mode 100644 index 000000000..8d456a126 Binary files /dev/null and b/ios/benchmark/img/iTunesArtwork@2x.png differ diff --git a/ios/benchmark/locations.cpp b/ios/benchmark/locations.cpp new file mode 100644 index 000000000..9f53877e4 --- /dev/null +++ b/ios/benchmark/locations.cpp @@ -0,0 +1,18 @@ +#include "locations.hpp" + +namespace mbgl { +namespace bench { + +const std::vector locations = { + { "paris", 2.3411, 48.8664, 11, 0.0 }, + { "paris2", 2.3516, 48.8356, 13, 273.8 }, + { "alps", 10.6107, 46.9599, 6, 0.0 }, + { "us east", -84.3395, 36.9400, 5, 0.0 }, + { "greater la", -117.9529, 34.0259, 9, 0.0 }, + { "sf", -122.4202, 37.7625, 14, 0.0 }, + { "oakland", -122.2328, 37.8267, 12, 0.0 }, + { "germany", 9.2280, 50.9262, 6, 0.0 }, +}; + +} +} diff --git a/ios/benchmark/locations.hpp b/ios/benchmark/locations.hpp new file mode 100644 index 000000000..96f9c6025 --- /dev/null +++ b/ios/benchmark/locations.hpp @@ -0,0 +1,23 @@ +#ifndef MBGL_BENCH_LOCATIONS +#define MBGL_BENCH_LOCATIONS + +#include +#include + +namespace mbgl { +namespace bench { + +struct Location { + const std::string name; + const double longitude; + const double latitude; + const double zoom; + const double bearing; +}; + +extern const std::vector locations; + +} +} + +#endif \ No newline at end of file diff --git a/ios/benchmark/main.m b/ios/benchmark/main.m new file mode 100644 index 000000000..52bb44555 --- /dev/null +++ b/ios/benchmark/main.m @@ -0,0 +1,10 @@ +#import + +#import "MBXBenchAppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([MBXBenchAppDelegate class])); + } +} diff --git a/ios/docs/install_docs.sh b/ios/docs/install_docs.sh new file mode 100755 index 000000000..9af3368c1 --- /dev/null +++ b/ios/docs/install_docs.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +if [ -z `which appledoc` ]; then + echo "Unable to find appledoc. See https://github.com/mapbox/mapbox-gl-native#manually" + exit 1 +fi + +OUTPUT="/tmp/`uuidgen`" + +VERSION=$( git tag --sort -v:refname | grep -v '\-rc.' | sed -n '1p' | sed 's/^v//' ) +echo "Creating new docs for ${VERSION}..." +echo + +rm -rf /tmp/mbgl +mkdir -p /tmp/mbgl/ +README=/tmp/mbgl/GL-README.md +cat ../README.md > ${README} +echo >> ${README} +echo -n "#" >> ${README} +cat ../../CHANGELOG.md >> ${README} +# Copy headers to a temporary location where we can substitute macros that appledoc doesn't understand. +cp -r ../../include/mbgl/ios /tmp/mbgl +perl \ + -pi \ + -e 's/NS_(?:(MUTABLE)_)?(ARRAY|SET|DICTIONARY)_OF\(\s*(.+?)\s*\)/NS\L\u$1\u$2\E <$3>/g' \ + /tmp/mbgl/ios/*.h +appledoc \ + --output ${OUTPUT} \ + --project-name "Mapbox iOS SDK ${VERSION}" \ + --project-company Mapbox \ + --create-docset \ + --company-id com.mapbox \ + --index-desc ${README} \ + /tmp/mbgl/ios diff --git a/ios/docs/pod-README.md b/ios/docs/pod-README.md new file mode 100644 index 000000000..7ffbf3b2c --- /dev/null +++ b/ios/docs/pod-README.md @@ -0,0 +1,7 @@ +# Mapbox iOS SDK + +An open source OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa bindings. + +For more information, check out [our online overview](https://www.mapbox.com/mapbox-gl-ios/). + +[![](https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/ios/screenshot.png)]() diff --git a/ios/docs/remove_docs.sh b/ios/docs/remove_docs.sh new file mode 100755 index 000000000..747ca0a3a --- /dev/null +++ b/ios/docs/remove_docs.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +echo +echo "Removing docs from ~/Library/Developer/Shared/Documentation/DocSets..." +echo + +rm -rfv ~/Library/Developer/Shared/Documentation/DocSets/com.mapbox.Mapbox-GL-* diff --git a/ios/screenshot.png b/ios/screenshot.png new file mode 100644 index 000000000..5bea3095a Binary files /dev/null and b/ios/screenshot.png differ diff --git a/linux/main.cpp b/linux/main.cpp new file mode 100644 index 000000000..6bd2f7c43 --- /dev/null +++ b/linux/main.cpp @@ -0,0 +1,171 @@ +#include +#include "../platform/default/default_styles.hpp" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace { + +std::unique_ptr view; + +} + +void quit_handler(int) { + if (view) { + mbgl::Log::Info(mbgl::Event::Setup, "waiting for quit..."); + view->setShouldClose(); + } else { + exit(0); + } +} + +int main(int argc, char *argv[]) { + bool fullscreen = false; + bool benchmark = false; + std::string style; + double latitude = 0, longitude = 0; + double bearing = 0, zoom = 1; + bool skipConfig = false; + + const struct option long_options[] = { + {"fullscreen", no_argument, 0, 'f'}, + {"benchmark", no_argument, 0, 'b'}, + {"style", required_argument, 0, 's'}, + {"lon", required_argument, 0, 'x'}, + {"lat", required_argument, 0, 'y'}, + {"zoom", required_argument, 0, 'z'}, + {"bearing", required_argument, 0, 'r'}, + {0, 0, 0, 0} + }; + + while (true) { + int option_index = 0; + int opt = getopt_long(argc, argv, "fbs:", long_options, &option_index); + if (opt == -1) break; + switch (opt) + { + case 0: + if (long_options[option_index].flag != 0) + break; + case 'f': + fullscreen = true; + break; + case 'b': + benchmark = true; + break; + case 's': + style = std::string("asset://") + std::string(optarg); + break; + case 'x': + longitude = atof(optarg); + skipConfig = true; + break; + case 'y': + latitude = atof(optarg); + skipConfig = true; + break; + case 'z': + zoom = atof(optarg); + skipConfig = true; + break; + case 'r': + bearing = atof(optarg); + skipConfig = true; + break; + default: + break; + } + + } + + // sigint handling + struct sigaction sigIntHandler; + sigIntHandler.sa_handler = quit_handler; + sigemptyset(&sigIntHandler.sa_mask); + sigIntHandler.sa_flags = 0; + sigaction(SIGINT, &sigIntHandler, NULL); + + if (benchmark) { + mbgl::Log::Info(mbgl::Event::General, "BENCHMARK MODE: Some optimizations are disabled."); + } + + view = std::make_unique(fullscreen, benchmark); + + mbgl::SQLiteCache cache("/tmp/mbgl-cache.db"); + mbgl::DefaultFileSource fileSource(&cache); + + // Set access token if present + const char *token = getenv("MAPBOX_ACCESS_TOKEN"); + if (token == nullptr) { + mbgl::Log::Warning(mbgl::Event::Setup, "no access token set. mapbox.com tiles won't work."); + } else { + fileSource.setAccessToken(std::string(token)); + } + + mbgl::Map map(*view, fileSource); + + // Load settings + mbgl::Settings_JSON settings; + + if (skipConfig) { + map.setLatLngZoom(mbgl::LatLng(latitude, longitude), zoom); + map.setBearing(bearing); + mbgl::Log::Info(mbgl::Event::General, "Location: %f/%f (z%.2f, %.2f deg)", latitude, longitude, zoom, bearing); + } else { + map.setLatLngZoom(mbgl::LatLng(settings.latitude, settings.longitude), settings.zoom); + map.setBearing(settings.bearing); + map.setDebug(settings.debug); + } + + view->setChangeStyleCallback([&map] () { + static uint8_t currentStyleIndex; + + if (++currentStyleIndex == mbgl::util::defaultStyles.size()) { + currentStyleIndex = 0; + } + + const auto& newStyle = mbgl::util::defaultStyles[currentStyleIndex]; + map.setStyleURL(newStyle.first); + view->setWindowTitle(newStyle.second); + + mbgl::Log::Info(mbgl::Event::Setup, std::string("Changed style to: ") + newStyle.first); + }); + + // Load style + if (style.empty()) { + const auto& newStyle = mbgl::util::defaultStyles.front(); + style = newStyle.first; + view->setWindowTitle(newStyle.second); + } + + map.setStyleURL(style); + + view->run(); + + // Save settings + mbgl::LatLng latLng = map.getLatLng(); + settings.latitude = latLng.latitude; + settings.longitude = latLng.longitude; + settings.zoom = map.getZoom(); + settings.bearing = map.getBearing(); + settings.debug = map.getDebug(); + if (!skipConfig) { + settings.save(); + } + mbgl::Log::Info(mbgl::Event::General, + "Exit location: --lat=\"%f\" --lon=\"%f\" --zoom=\"%f\" --bearing \"%f\"", + settings.latitude, settings.longitude, settings.zoom, settings.bearing); + + return 0; +} diff --git a/linux/mapboxgl-app.gypi b/linux/mapboxgl-app.gypi new file mode 100644 index 000000000..8457c2ce7 --- /dev/null +++ b/linux/mapboxgl-app.gypi @@ -0,0 +1,62 @@ +{ + 'includes': [ + '../gyp/common.gypi', + ], + 'targets': [ + { 'target_name': 'linuxapp', + 'product_name': 'mapbox-gl', + 'type': 'executable', + + 'dependencies': [ + '../mbgl.gyp:core', + '../mbgl.gyp:platform-<(platform_lib)', + '../mbgl.gyp:http-<(http_lib)', + '../mbgl.gyp:asset-<(asset_lib)', + '../mbgl.gyp:cache-<(cache_lib)', + '../mbgl.gyp:copy_styles', + '../mbgl.gyp:copy_certificate_bundle', + ], + + 'sources': [ + 'main.cpp', + '../platform/default/settings_json.cpp', + '../platform/default/glfw_view.hpp', + '../platform/default/glfw_view.cpp', + '../platform/default/log_stderr.cpp', + '../platform/default/default_styles.hpp', + '../platform/default/default_styles.cpp', + ], + + 'variables' : { + 'cflags_cc': [ + '<@(opengl_cflags)', + '<@(boost_cflags)', + '<@(glfw_cflags)', + ], + 'ldflags': [ + '<@(glfw_ldflags)', + ], + 'libraries': [ + '<@(glfw_static_libs)', + ], + }, + + 'conditions': [ + ['OS == "mac"', { + 'libraries': [ '<@(libraries)' ], + 'xcode_settings': { + 'SDKROOT': 'macosx', + 'SUPPORTED_PLATFORMS':'macosx', + 'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ], + 'OTHER_LDFLAGS': [ '<@(ldflags)' ], + 'SDKROOT': 'macosx', + 'MACOSX_DEPLOYMENT_TARGET': '10.9', + } + }, { + 'cflags_cc': [ '<@(cflags_cc)' ], + 'libraries': [ '<@(libraries)', '<@(ldflags)' ], + }] + ], + }, + ], +} diff --git a/macosx/Icon.icns b/macosx/Icon.icns new file mode 100644 index 000000000..64a5e57cf Binary files /dev/null and b/macosx/Icon.icns differ diff --git a/macosx/Info.plist b/macosx/Info.plist new file mode 100644 index 000000000..514db118e --- /dev/null +++ b/macosx/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleGetInfoString + 0.0.1 + CFBundleIconFile + Icon.icns + CFBundleIdentifier + com.mapbox.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + 0.0.1 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.0.1 + CFBundleSignature + MBGL + CFBundleVersion + 0.0.1 + CSResourcesFileMapped + + NSHumanReadableCopyright + 0.0.1 + NSHighResolutionCapable + + CFBundleURLTypes + + + CFBundleURLName + ${PRODUCT_NAME} + CFBundleURLSchemes + + mapboxgl + + + + + \ No newline at end of file diff --git a/macosx/main.mm b/macosx/main.mm new file mode 100644 index 000000000..24251e6d4 --- /dev/null +++ b/macosx/main.mm @@ -0,0 +1,211 @@ +#include +#include "../platform/default/default_styles.hpp" +#include +#include +#include +#include +#include +#include +#include + +#include + +#import + +#pragma GCC diagnostic push +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#pragma GCC diagnostic ignored "-Wshadow" +#endif +#include +#pragma GCC diagnostic pop + +#include + +namespace po = boost::program_options; + + +@interface URLHandler : NSObject +@property (nonatomic) mbgl::Map *map; + +- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event + withReplyEvent:(NSAppleEventDescriptor *)replyEvent; +@end + +@implementation URLHandler + +- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event + withReplyEvent:(NSAppleEventDescriptor *)replyEvent { + (void)replyEvent; + + NSString* urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + NSURL *url = [NSURL URLWithString:urlString]; + NSMutableDictionary *params = [[NSMutableDictionary alloc] init]; + for (NSString *param in [[url query] componentsSeparatedByString:@"&"]) { + NSArray *parts = [param componentsSeparatedByString:@"="]; + if([parts count] < 2) continue; + [params setObject:[parts objectAtIndex:1] forKey:[parts objectAtIndex:0]]; + } + + mbgl::LatLng latLng = mbgl::LatLng(0, 0); + double zoom = 0, bearing = 0; + bool hasCenter = false, hasZoom = false, hasBearing = false; + + NSString *centerString = [params objectForKey:@"center"]; + if (centerString) { + NSArray *latLngValues = [centerString componentsSeparatedByString:@","]; + if ([latLngValues count] == 2) { + latLng.latitude = [latLngValues[0] doubleValue]; + latLng.longitude = [latLngValues[1] doubleValue]; + hasCenter = true; + } + } + + NSString *zoomString = [params objectForKey:@"zoom"]; + if (zoomString) { + zoom = [zoomString doubleValue]; + hasZoom = true; + } + + NSString *bearingString = [params objectForKey:@"bearing"]; + if (bearingString) { + bearing = [bearingString doubleValue]; + hasBearing = true; + } + + if ([self map]) { + if (hasCenter && hasZoom) { + [self map]->setLatLngZoom(latLng, zoom); + } else if (hasCenter) { + [self map]->setLatLng(latLng); + } else if (hasZoom) { + [self map]->setZoom(zoom); + } + + if (hasBearing) { + [self map]->setBearing(bearing); + } + } +} +@end + +// Returns the path to the default cache database on this system. +const std::string &defaultCacheDatabase() { + static const std::string path = []() -> std::string { + NSArray *paths = NSSearchPathForDirectoriesInDomains( + NSApplicationSupportDirectory, NSUserDomainMask, YES); + if ([paths count] == 0) { + // Disable the cache if we don't have a location to write. + return ""; + } + + NSString *p = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Mapbox GL"]; + + if (![[NSFileManager defaultManager] createDirectoryAtPath:p + withIntermediateDirectories:YES + attributes:nil + error:nil]) { + // Disable the cache if we couldn't create the directory. + return ""; + } + + return [[p stringByAppendingPathComponent:@"cache.db"] UTF8String]; + }(); + return path; +} + +int main(int argc, char* argv[]) { + bool fullscreen = false; + bool benchmark = false; + std::string style; + + po::options_description desc("Allowed options"); + desc.add_options() + ("fullscreen,f", po::bool_switch(&fullscreen)->default_value(fullscreen), "Fullscreen mode") + ("style,s", po::value(&style)->value_name("json"), "Map stylesheet") + ("benchmark,b", po::bool_switch(&benchmark)->default_value(benchmark), "Benchmark mode") + ; + + try { + auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); + po::variables_map vm; + po::store(parsed, vm); + po::notify(vm); + } catch(std::exception& e) { + std::cout << "Error: " << e.what() << std::endl << desc; + exit(1); + } + + if (benchmark) { + mbgl::Log::Info(mbgl::Event::General, "BENCHMARK MODE: Some optimizations are disabled."); + } + + GLFWView view(fullscreen, benchmark); + + mbgl::SQLiteCache cache(defaultCacheDatabase()); + mbgl::DefaultFileSource fileSource(&cache); + + // Set access token if present + NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"]; + if (!accessToken) mbgl::Log::Warning(mbgl::Event::Setup, "No access token set. Mapbox vector tiles won't work."); + if (accessToken) fileSource.setAccessToken([accessToken cStringUsingEncoding:[NSString defaultCStringEncoding]]); + + mbgl::Map map(view, fileSource); + + URLHandler *handler = [[URLHandler alloc] init]; + [handler setMap:&map]; + NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager]; + [appleEventManager setEventHandler:handler andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; + + // Notify map object when network reachability status changes. + MGLReachability* reachability = [MGLReachability reachabilityForInternetConnection]; + reachability.reachableBlock = ^(MGLReachability *) { + mbgl::NetworkStatus::Reachable(); + }; + [reachability startNotifier]; + + // Load settings + mbgl::Settings_NSUserDefaults settings; + map.setLatLngZoom(mbgl::LatLng(settings.latitude, settings.longitude), settings.zoom); + map.setBearing(settings.bearing); + map.setDebug(settings.debug); + + view.setChangeStyleCallback([&map, &view] () { + static uint8_t currentStyleIndex; + + if (++currentStyleIndex == mbgl::util::defaultStyles.size()) { + currentStyleIndex = 0; + } + + const auto& newStyle = mbgl::util::defaultStyles[currentStyleIndex]; + map.setStyleURL(newStyle.first); + view.setWindowTitle(newStyle.second); + + mbgl::Log::Info(mbgl::Event::Setup, std::string("Changed style to: ") + newStyle.first); + }); + + + // Load style + if (style.empty()) { + const auto& newStyle = mbgl::util::defaultStyles.front(); + style = newStyle.first; + view.setWindowTitle(newStyle.second); + } + + map.setStyleURL(style); + + view.run(); + + [reachability stopNotifier]; + + // Save settings + mbgl::LatLng latLng = map.getLatLng(); + settings.latitude = latLng.latitude; + settings.longitude = latLng.longitude; + settings.zoom = map.getZoom(); + settings.bearing = map.getBearing(); + settings.debug = map.getDebug(); + settings.save(); + + return 0; +} diff --git a/macosx/mapboxgl-app.gypi b/macosx/mapboxgl-app.gypi new file mode 100644 index 000000000..e1d9476e1 --- /dev/null +++ b/macosx/mapboxgl-app.gypi @@ -0,0 +1,65 @@ +{ + 'includes': [ + '../gyp/common.gypi', + ], + 'targets': [ + { 'target_name': 'osxapp', + 'product_name': 'Mapbox GL', + 'type': 'executable', + 'product_extension': 'app', + 'mac_bundle': 1, + 'mac_bundle_resources': [ + 'Icon.icns' + ], + + 'dependencies': [ + '../mbgl.gyp:bundle_styles', + '../mbgl.gyp:core', + '../mbgl.gyp:platform-<(platform_lib)', + '../mbgl.gyp:http-<(http_lib)', + '../mbgl.gyp:asset-<(asset_lib)', + '../mbgl.gyp:cache-<(cache_lib)', + ], + + 'sources': [ + './main.mm', + '../platform/darwin/settings_nsuserdefaults.hpp', + '../platform/darwin/settings_nsuserdefaults.mm', + '../platform/darwin/reachability.m', + '../platform/default/glfw_view.hpp', + '../platform/default/glfw_view.cpp', + '../platform/default/default_styles.hpp', + '../platform/default/default_styles.cpp', + ], + + 'variables' : { + 'cflags_cc': [ + '<@(boost_cflags)', + '<@(glfw_cflags)', + ], + 'ldflags': [ + '-framework SystemConfiguration', # For NSUserDefaults and Reachability + '<@(glfw_ldflags)', + ], + 'libraries': [ + '<@(glfw_static_libs)', + '<@(boost_libprogram_options_static_libs)' + ], + }, + + 'libraries': [ + '<@(libraries)', + ], + + 'xcode_settings': { + 'SDKROOT': 'macosx', + 'SUPPORTED_PLATFORMS':'macosx', + 'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ], + 'OTHER_LDFLAGS': [ '<@(ldflags)' ], + 'SDKROOT': 'macosx', + 'INFOPLIST_FILE': '../macosx/Info.plist', + 'CLANG_ENABLE_OBJC_ARC': 'YES' + }, + } + ] +} diff --git a/mbgl.gyp b/mbgl.gyp new file mode 100644 index 000000000..959a9729d --- /dev/null +++ b/mbgl.gyp @@ -0,0 +1,28 @@ +{ + 'includes': [ + './gyp/common.gypi', + './gyp/shaders.gypi', + './gyp/version.gypi', + './gyp/styles.gypi', + './gyp/certificates.gypi', + './gyp/standalone.gypi', + './gyp/core.gypi', + './gyp/none.gypi', + ], + 'conditions': [ + ['headless_lib == "cgl" and host == "osx"', { 'includes': [ './gyp/headless-cgl.gypi' ] } ], + ['headless_lib == "glx" and host == "linux"', { 'includes': [ './gyp/headless-glx.gypi' ] } ], + ['platform_lib == "osx" and host == "osx"', { 'includes': [ './gyp/platform-osx.gypi' ] } ], + ['platform_lib == "ios" and host == "ios"', { 'includes': [ './gyp/platform-ios.gypi' ] } ], + ['platform_lib == "linux"', { 'includes': [ './gyp/platform-linux.gypi' ] } ], + ['platform_lib == "android" and host == "android"', { 'includes': [ './gyp/platform-android.gypi' ] } ], + ['http_lib == "curl"', { 'includes': [ './gyp/http-curl.gypi' ] } ], + ['http_lib == "nsurl" and (host == "osx" or host == "ios")', { 'includes': [ './gyp/http-nsurl.gypi' ] } ], + ['http_lib == "android" and host == "android"', { 'includes': [ './gyp/http-android.gypi' ] } ], + ['asset_lib == "fs"', { 'includes': [ './gyp/asset-fs.gypi' ] } ], + ['asset_lib == "zip"', { 'includes': [ './gyp/asset-zip.gypi' ] } ], + ['cache_lib == "sqlite"', { 'includes': [ './gyp/cache-sqlite.gypi' ] } ], + + ['install_prefix != ""', { 'includes': ['./gyp/install.gypi' ] } ], + ], +} diff --git a/platform/android/asset_root.cpp b/platform/android/asset_root.cpp new file mode 100644 index 000000000..4069211f6 --- /dev/null +++ b/platform/android/asset_root.cpp @@ -0,0 +1,16 @@ +#include +#include + +#include +#include + +namespace mbgl { +namespace platform { + +// Returns the path to the root folder of the application. +const std::string &assetRoot() { + return mbgl::android::apkPath; +} + +} +} diff --git a/platform/android/http_request_android.cpp b/platform/android/http_request_android.cpp new file mode 100644 index 000000000..249cb731e --- /dev/null +++ b/platform/android/http_request_android.cpp @@ -0,0 +1,370 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace mbgl { + +void JNICALL nativeOnFailure(JNIEnv *env, jobject obj, jlong nativePtr, jint type, jstring message); +void JNICALL nativeOnResponse(JNIEnv *env, jobject obj, jlong nativePtr, jint code, jstring message, jstring etag, jstring modified, jstring cacheControl, jstring expires, jbyteArray body); + +class HTTPAndroidRequest; + +class HTTPAndroidContext : public HTTPContextBase { +public: + explicit HTTPAndroidContext(uv_loop_t *loop); + ~HTTPAndroidContext(); + + HTTPRequestBase* createRequest(const Resource&, + RequestBase::Callback, + uv_loop_t*, + std::shared_ptr) final; + + uv_loop_t *loop = nullptr; + + JavaVM *vm = nullptr; + jobject obj = nullptr; +}; + +class HTTPAndroidRequest : public HTTPRequestBase { +public: + HTTPAndroidRequest(HTTPAndroidContext*, + const Resource&, + Callback, + uv_loop_t*, + std::shared_ptr); + ~HTTPAndroidRequest(); + + void cancel() final; + void retry() final; + + void onFailure(int type, std::string message); + void onResponse(int code, std::string message, std::string etag, std::string modified, std::string cacheControl, std::string expires, std::string body); + +private: + void retry(uint64_t timeout) final; + void finish(); + void start(); + + HTTPAndroidContext *context = nullptr; + + bool cancelled = false; + + std::unique_ptr response; + const std::shared_ptr existingResponse; + ResponseStatus status = ResponseStatus::PermanentError; + + jobject obj = nullptr; + + uv::async async; + uv::timer timer; + enum : bool { PreemptImmediately, ExponentialBackoff } strategy = PreemptImmediately; + int attempts = 0; + + static const int maxAttempts = 4; + + static const int connectionError = 0; + static const int temporaryError = 1; + static const int permanentError = 1; +}; + +// ------------------------------------------------------------------------------------------------- + +HTTPAndroidContext::HTTPAndroidContext(uv_loop_t *loop_) + : HTTPContextBase(loop_), + loop(loop_), + vm(mbgl::android::theJVM) { + + JNIEnv *env = nullptr; + bool detach = mbgl::android::attach_jni_thread(vm, &env, "HTTPAndroidContext::HTTPAndroidContext()"); + + const std::vector methods = { + {"nativeOnFailure", "(JILjava/lang/String;)V", reinterpret_cast(&nativeOnFailure)}, + {"nativeOnResponse", + "(JILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[B)V", + reinterpret_cast(&nativeOnResponse)} + }; + + if (env->RegisterNatives(mbgl::android::httpRequestClass, methods.data(), methods.size()) < 0) { + env->ExceptionDescribe(); + } + + obj = env->CallStaticObjectMethod(mbgl::android::httpContextClass, mbgl::android::httpContextGetInstanceId); + if (env->ExceptionCheck() || (obj == nullptr)) { + env->ExceptionDescribe(); + } + + obj = env->NewGlobalRef(obj); + if (obj == nullptr) { + env->ExceptionDescribe(); + } + + mbgl::android::detach_jni_thread(vm, &env, detach); +} + +HTTPAndroidContext::~HTTPAndroidContext() { + JNIEnv *env = nullptr; + bool detach = mbgl::android::attach_jni_thread(vm, &env, "HTTPAndroidContext::~HTTPAndroidContext()"); + + env->DeleteGlobalRef(obj); + obj = nullptr; + + mbgl::android::detach_jni_thread(vm, &env, detach); + + vm = nullptr; +} + +HTTPRequestBase* HTTPAndroidContext::createRequest(const Resource& resource, + RequestBase::Callback callback, + uv_loop_t* loop_, + std::shared_ptr response) { + return new HTTPAndroidRequest(this, resource, callback, loop_, response); +} + +HTTPAndroidRequest::HTTPAndroidRequest(HTTPAndroidContext* context_, const Resource& resource_, Callback callback_, uv_loop_t* loop, std::shared_ptr response_) + : HTTPRequestBase(resource_, callback_), + context(context_), + existingResponse(response_), + async(loop, [this] { finish(); }), + timer(loop) { + + std::string etagStr; + std::string modifiedStr; + if (existingResponse) { + if (!existingResponse->etag.empty()) { + etagStr = existingResponse->etag; + } else if (existingResponse->modified) { + modifiedStr = util::rfc1123(existingResponse->modified); + } + } + + JNIEnv *env = nullptr; + bool detach = mbgl::android::attach_jni_thread(context->vm, &env, "HTTPAndroidContext::HTTPAndroidRequest()"); + + jstring resourceUrl = mbgl::android::std_string_to_jstring(env, resource.url); + jstring userAgent = mbgl::android::std_string_to_jstring(env, "MapboxGL/1.0"); + jstring etag = mbgl::android::std_string_to_jstring(env, etagStr); + jstring modified = mbgl::android::std_string_to_jstring(env, modifiedStr); + obj = env->CallObjectMethod(context->obj, mbgl::android::httpContextCreateRequestId, reinterpret_cast(this), resourceUrl, userAgent, etag, modified); + if (env->ExceptionCheck() || (obj == nullptr)) { + env->ExceptionDescribe(); + } + + obj = env->NewGlobalRef(obj); + if (obj == nullptr) { + env->ExceptionDescribe(); + } + + mbgl::android::detach_jni_thread(context->vm, &env, detach); + + context->addRequest(this); + start(); +} + +HTTPAndroidRequest::~HTTPAndroidRequest() { + context->removeRequest(this); + + JNIEnv *env = nullptr; + bool detach = mbgl::android::attach_jni_thread(context->vm, &env, "HTTPAndroidContext::~HTTPAndroidRequest()"); + + env->DeleteGlobalRef(obj); + obj = nullptr; + + mbgl::android::detach_jni_thread(context->vm, &env, detach); + + timer.stop(); +} + +void HTTPAndroidRequest::cancel() { + cancelled = true; + + JNIEnv *env = nullptr; + bool detach = mbgl::android::attach_jni_thread(context->vm, &env, "HTTPAndroidContext::cancel()"); + + env->CallVoidMethod(obj, mbgl::android::httpRequestCancelId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + } + + mbgl::android::detach_jni_thread(context->vm, &env, detach); +} + +void HTTPAndroidRequest::start() { + attempts++; + + JNIEnv *env = nullptr; + bool detach = mbgl::android::attach_jni_thread(context->vm, &env, "HTTPAndroidContext::start()"); + + env->CallVoidMethod(obj, mbgl::android::httpRequestStartId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + } + + mbgl::android::detach_jni_thread(context->vm, &env, detach); +} + +void HTTPAndroidRequest::retry(uint64_t timeout) { + response.reset(); + + timer.stop(); + timer.start(timeout, 0, [this] { start(); }); +} + +void HTTPAndroidRequest::retry() { + if (strategy == PreemptImmediately) { + timer.stop(); + timer.start(0, 0, [this] { start(); }); + } +} + +void HTTPAndroidRequest::finish() { + if (!cancelled) { + if (status == ResponseStatus::TemporaryError && attempts < maxAttempts) { + strategy = ExponentialBackoff; + return retry((1 << (attempts - 1)) * 1000); + } else if (status == ResponseStatus::ConnectionError && attempts < maxAttempts) { + strategy = PreemptImmediately; + return retry(30000); + } + + if (status == ResponseStatus::NotModified) { + notify(std::move(response), FileCache::Hint::Refresh); + } else { + notify(std::move(response), FileCache::Hint::Full); + } + } + + delete this; +} + +int64_t parseCacheControl(const char *value) { + if (value) { + unsigned long long seconds = 0; + // TODO: cache-control may contain other information as well: + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 + if (std::sscanf(value, "max-age=%llu", &seconds) == 1) { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count() + + seconds; + } + } + + return 0; +} + +void HTTPAndroidRequest::onResponse(int code, std::string message, std::string etag, std::string modified, std::string cacheControl, std::string expires, std::string body) { + if (!response) { + response = std::make_unique(); + } + + response->message = message; + response->modified = parse_date(modified.c_str()); + response->etag = etag; + response->expires = parseCacheControl(cacheControl.c_str()); + if (!expires.empty()) { + response->expires = parse_date(expires.c_str()); + } + response->data = body; + + if (code == 304) { + if (existingResponse) { + response->status = existingResponse->status; + response->message = existingResponse->message; + response->modified = existingResponse->modified; + response->etag = existingResponse->etag; + response->data = existingResponse->data; + status = ResponseStatus::NotModified; + } else { + response->status = Response::Successful; + status = ResponseStatus::Successful; + } + } else if (code == 200) { + response->status = Response::Successful; + status = ResponseStatus::Successful; + } else if (code >= 500 && code < 600) { + response->status = Response::Error; + response->message = "HTTP status code " + util::toString(code); + status = ResponseStatus::TemporaryError; + } else { + response->status = Response::Error; + response->message = "HTTP status code " + util::toString(code); + status = ResponseStatus::PermanentError; + } + + async.send(); +} + +void HTTPAndroidRequest::onFailure(int type, std::string message) { + if (!response) { + response = std::make_unique(); + } + + response->status = Response::Error; + response->message = message; + + switch (type) { + case connectionError: + status = ResponseStatus::ConnectionError; + + case temporaryError: + status = ResponseStatus::TemporaryError; + + default: + status = ResponseStatus::PermanentError; + } + + async.send(); +} + +std::unique_ptr HTTPContextBase::createContext(uv_loop_t* loop) { + return std::make_unique(loop); +} + +#pragma clang diagnostic ignored "-Wunused-parameter" + +void JNICALL nativeOnFailure(JNIEnv *env, jobject obj, jlong nativePtr, jint type, jstring message) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeOnFailure"); + assert(nativePtr != 0); + HTTPAndroidRequest *request = reinterpret_cast(nativePtr); + std::string messageStr = mbgl::android::std_string_from_jstring(env, message); + return request->onFailure(type, messageStr); +} + +void JNICALL nativeOnResponse(JNIEnv *env, jobject obj, jlong nativePtr, jint code, jstring message, jstring etag, jstring modified, jstring cacheControl, jstring expires, jbyteArray body) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeOnResponse"); + assert(nativePtr != 0); + HTTPAndroidRequest *request = reinterpret_cast(nativePtr); + std::string messageStr = mbgl::android::std_string_from_jstring(env, message); + std::string etagStr; + if (etag != nullptr) { + etagStr = mbgl::android::std_string_from_jstring(env, etag); + } + std::string modifiedStr; + if (modified != nullptr) { + modifiedStr = mbgl::android::std_string_from_jstring(env, modified); + } + std::string cacheControlStr; + if (cacheControl != nullptr) { + cacheControlStr = mbgl::android::std_string_from_jstring(env, cacheControl); + } + std::string expiresStr; + if (expires != nullptr) { + expiresStr = mbgl::android::std_string_from_jstring(env, expires); + } + jbyte* bodyData = env->GetByteArrayElements(body, nullptr); + std::string bodyStr(reinterpret_cast(bodyData), env->GetArrayLength(body)); + env->ReleaseByteArrayElements(body, bodyData, JNI_ABORT); + return request->onResponse(code, messageStr, etagStr, modifiedStr, cacheControlStr, expiresStr, bodyStr); +} + +} diff --git a/platform/android/log_android.cpp b/platform/android/log_android.cpp new file mode 100644 index 000000000..e5c8cfd81 --- /dev/null +++ b/platform/android/log_android.cpp @@ -0,0 +1,34 @@ +#include + +#include + +namespace mbgl { + +namespace { + +int severityToPriority(EventSeverity severity) { + switch(severity) { + case EventSeverity::Debug: + return ANDROID_LOG_DEBUG; + + case EventSeverity::Info: + return ANDROID_LOG_INFO; + + case EventSeverity::Warning: + return ANDROID_LOG_WARN; + + case EventSeverity::Error: + return ANDROID_LOG_ERROR; + + default: + return ANDROID_LOG_VERBOSE; + } +} + +} // namespace + +void Log::platformRecord(EventSeverity severity, const std::string &msg) { + __android_log_print(severityToPriority(severity), "mbgl", "%s", msg.c_str()); +} + +} diff --git a/platform/darwin/application_root.mm b/platform/darwin/application_root.mm new file mode 100644 index 000000000..d4702c7ec --- /dev/null +++ b/platform/darwin/application_root.mm @@ -0,0 +1,18 @@ +#import + +#include + +namespace mbgl { +namespace platform { + +// Returns the path to the root folder of the application. +const std::string &applicationRoot() { + static const std::string root = []() -> std::string { + NSString *path = [[[NSBundle mainBundle] resourceURL] path]; + return {[path cStringUsingEncoding : NSUTF8StringEncoding], + [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding]}; + }(); + return root; +} +} +} diff --git a/platform/darwin/asset_root.mm b/platform/darwin/asset_root.mm new file mode 100644 index 000000000..f47f5d36d --- /dev/null +++ b/platform/darwin/asset_root.mm @@ -0,0 +1,27 @@ +#import + +#include + +@interface MGLApplicationRootBundleCanary : NSObject +@end + +@implementation MGLApplicationRootBundleCanary +@end + +namespace mbgl { +namespace platform { + +// Returns the path to the root folder of the application. +const std::string &assetRoot() { + static const std::string root = []() -> std::string { + NSString *path = [[NSBundle bundleForClass:[MGLApplicationRootBundleCanary class]] pathForResource:@"Mapbox" ofType:@"bundle"]; + if (!path) { + path = [[[NSBundle mainBundle] resourceURL] path]; + } + return {[path cStringUsingEncoding : NSUTF8StringEncoding], + [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding]}; + }(); + return root; +} +} +} diff --git a/platform/darwin/http_request_nsurl.mm b/platform/darwin/http_request_nsurl.mm new file mode 100644 index 000000000..33f5f043e --- /dev/null +++ b/platform/darwin/http_request_nsurl.mm @@ -0,0 +1,340 @@ +#include +#include +#include +#include + +#include +#include + +#import + +#include +#include + +namespace mbgl { + +class HTTPNSURLContext; + +class HTTPNSURLRequest : public HTTPRequestBase { +public: + HTTPNSURLRequest(HTTPNSURLContext*, + const Resource&, + Callback, + uv_loop_t*, + std::shared_ptr); + ~HTTPNSURLRequest(); + + void cancel() final; + void retry() final; + +private: + void start(); + void handleResult(NSData *data, NSURLResponse *res, NSError *error); + void handleResponse(); + void retry(uint64_t timeout) final; + + HTTPNSURLContext *context = nullptr; + bool cancelled = false; + NSURLSessionDataTask *task = nullptr; + std::unique_ptr response; + const std::shared_ptr existingResponse; + ResponseStatus status = ResponseStatus::PermanentError; + uv::async async; + uv::timer timer; + int attempts = 0; + enum : bool { PreemptImmediately, ExponentialBackoff } strategy = PreemptImmediately; + + static const int maxAttempts = 4; +}; + +// ------------------------------------------------------------------------------------------------- + +class HTTPNSURLContext : public HTTPContextBase { +public: + HTTPNSURLContext(uv_loop_t *loop); + ~HTTPNSURLContext(); + + HTTPRequestBase* createRequest(const Resource&, + RequestBase::Callback, + uv_loop_t*, + std::shared_ptr) final; + + NSURLSession *session = nil; + NSString *userAgent = nil; + NSInteger accountType = 0; +}; + +HTTPNSURLContext::HTTPNSURLContext(uv_loop_t *loop_) : HTTPContextBase(loop_) { + @autoreleasepool { + NSURLSessionConfiguration *sessionConfig = + [NSURLSessionConfiguration defaultSessionConfiguration]; + sessionConfig.timeoutIntervalForResource = 30; + sessionConfig.HTTPMaximumConnectionsPerHost = 8; + sessionConfig.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData; + sessionConfig.URLCache = nil; + + session = [NSURLSession sessionWithConfiguration:sessionConfig]; + [session retain]; + + // Write user agent string + userAgent = @"MapboxGL"; + + accountType = [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"]; + } +} + +HTTPNSURLContext::~HTTPNSURLContext() { + [session release]; + session = nullptr; + + [userAgent release]; + userAgent = nullptr; +} + +HTTPRequestBase* HTTPNSURLContext::createRequest(const Resource& resource, + RequestBase::Callback callback, + uv_loop_t* loop, + std::shared_ptr response) { + return new HTTPNSURLRequest(this, resource, callback, loop, response); +} + +// ------------------------------------------------------------------------------------------------- + +HTTPNSURLRequest::HTTPNSURLRequest(HTTPNSURLContext* context_, const Resource& resource_, Callback callback_, uv_loop_t *loop, std::shared_ptr existingResponse_) + : HTTPRequestBase(resource_, callback_), + context(context_), + existingResponse(existingResponse_), + async(loop, [this] { handleResponse(); }), + timer(loop) { + context->addRequest(this); + start(); +} + +HTTPNSURLRequest::~HTTPNSURLRequest() { + assert(!task); + + // Stop the backoff timer to avoid re-triggering this request. + timer.stop(); + + context->removeRequest(this); +} + +void HTTPNSURLRequest::start() { + assert(!task); + + attempts++; + + @autoreleasepool { + + NSURL *url = [NSURL URLWithString:@(resource.url.c_str())]; + if (context->accountType == 0 && + ([url.host isEqualToString:@"mapbox.com"] || [url.host hasSuffix:@".mapbox.com"])) { + NSString *absoluteString = [url.absoluteString stringByAppendingFormat: + (url.query ? @"&%@" : @"?%@"), @"events=true"]; + url = [NSURL URLWithString:absoluteString]; + } + + NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; + if (existingResponse) { + if (!existingResponse->etag.empty()) { + [req addValue:@(existingResponse->etag.c_str()) forHTTPHeaderField:@"If-None-Match"]; + } else if (existingResponse->modified) { + const std::string time = util::rfc1123(existingResponse->modified); + [req addValue:@(time.c_str()) forHTTPHeaderField:@"If-Modified-Since"]; + } + } + + [req addValue:context->userAgent forHTTPHeaderField:@"User-Agent"]; + + task = [context->session dataTaskWithRequest:req + completionHandler:^(NSData *data, NSURLResponse *res, + NSError *error) { handleResult(data, res, error); }]; + [task retain]; + [task resume]; + } +} + +void HTTPNSURLRequest::handleResponse() { + if (task) { + [task release]; + task = nullptr; + } + + if (!cancelled) { + if (status == ResponseStatus::TemporaryError && attempts < maxAttempts) { + strategy = ExponentialBackoff; + return retry((1 << (attempts - 1)) * 1000); + } else if (status == ResponseStatus::ConnectionError && attempts < maxAttempts) { + // By default, we will retry every 30 seconds (network change notification will + // preempt the timeout). + strategy = PreemptImmediately; + return retry(30000); + } + + // Actually return the response. + if (status == ResponseStatus::NotModified) { + notify(std::move(response), FileCache::Hint::Refresh); + } else { + notify(std::move(response), FileCache::Hint::Full); + } + } + + delete this; +} + +void HTTPNSURLRequest::cancel() { + context->removeRequest(this); + cancelled = true; + + // Stop the backoff timer to avoid re-triggering this request. + timer.stop(); + + if (task) { + [task cancel]; + [task release]; + task = nullptr; + } else { + delete this; + } +} + +int64_t parseCacheControl(const char *value) { + if (value) { + unsigned long long seconds = 0; + // TODO: cache-control may contain other information as well: + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 + if (std::sscanf(value, "max-age=%llu", &seconds) == 1) { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count() + + seconds; + } + } + + return 0; +} + +void HTTPNSURLRequest::handleResult(NSData *data, NSURLResponse *res, NSError *error) { + if (error) { + if ([error code] == NSURLErrorCancelled) { + status = ResponseStatus::Canceled; + } else { + // TODO: Use different codes for host not found, timeout, invalid URL etc. + // These can be categorized in temporary and permanent errors. + response = std::make_unique(); + response->status = Response::Error; + response->message = [[error localizedDescription] UTF8String]; + + switch ([error code]) { + case NSURLErrorBadServerResponse: // 5xx errors + status = ResponseStatus::TemporaryError; + break; + + case NSURLErrorTimedOut: + case NSURLErrorUserCancelledAuthentication: + status = ResponseStatus::SingularError; // retry immediately + break; + + case NSURLErrorNetworkConnectionLost: + case NSURLErrorCannotFindHost: + case NSURLErrorCannotConnectToHost: + case NSURLErrorDNSLookupFailed: + case NSURLErrorNotConnectedToInternet: + case NSURLErrorInternationalRoamingOff: + case NSURLErrorCallIsActive: + case NSURLErrorDataNotAllowed: + status = ResponseStatus::ConnectionError; + break; + + default: + status = ResponseStatus::PermanentError; + } + } + } else if ([res isKindOfClass:[NSHTTPURLResponse class]]) { + const long responseCode = [(NSHTTPURLResponse *)res statusCode]; + + response = std::make_unique(); + response->data = {(const char *)[data bytes], [data length]}; + + NSDictionary *headers = [(NSHTTPURLResponse *)res allHeaderFields]; + NSString *cache_control = [headers objectForKey:@"Cache-Control"]; + if (cache_control) { + response->expires = parseCacheControl([cache_control UTF8String]); + } + + NSString *expires = [headers objectForKey:@"Expires"]; + if (expires) { + response->expires = parse_date([expires UTF8String]); + } + + NSString *last_modified = [headers objectForKey:@"Last-Modified"]; + if (last_modified) { + response->modified = parse_date([last_modified UTF8String]); + } + + NSString *etag = [headers objectForKey:@"ETag"]; + if (etag) { + response->etag = [etag UTF8String]; + } + + if (responseCode == 304) { + if (existingResponse) { + // We're going to copy over the existing response's data. + response->status = existingResponse->status; + response->message = existingResponse->message; + response->modified = existingResponse->modified; + response->etag = existingResponse->etag; + response->data = existingResponse->data; + status = ResponseStatus::NotModified; + } else { + // This is an unsolicited 304 response and should only happen on malfunctioning + // HTTP servers. It likely doesn't include any data, but we don't have much options. + response->status = Response::Successful; + status = ResponseStatus::Successful; + } + } else if (responseCode == 200) { + response->status = Response::Successful; + status = ResponseStatus::Successful; + } else if (responseCode >= 500 && responseCode < 600) { + // Server errors may be temporary, so back off exponentially. + response->status = Response::Error; + response->message = "HTTP status code " + std::to_string(responseCode); + status = ResponseStatus::TemporaryError; + } else { + // We don't know how to handle any other errors, so declare them as permanently failing. + response->status = Response::Error; + response->message = "HTTP status code " + std::to_string(responseCode); + status = ResponseStatus::PermanentError; + } + } else { + // This should never happen. + status = ResponseStatus::PermanentError; + response = std::make_unique(); + response->status = Response::Error; + response->message = "response class is not NSHTTPURLResponse"; + } + + async.send(); +} + +void HTTPNSURLRequest::retry(uint64_t timeout) { + response.reset(); + + timer.stop(); + timer.start(timeout, 0, [this] { start(); }); +} + +void HTTPNSURLRequest::retry() { + // All batons get notified when the network status changed, but some of them + // might not actually wait for the network to become available again. + if (strategy == PreemptImmediately) { + // Triggers the timer upon the next event loop iteration. + timer.stop(); + timer.start(0, 0, [this] { start(); }); + } +} + +std::unique_ptr HTTPContextBase::createContext(uv_loop_t* loop) { + return std::make_unique(loop); +} + +} diff --git a/platform/darwin/image.mm b/platform/darwin/image.mm new file mode 100644 index 000000000..31373e9d1 --- /dev/null +++ b/platform/darwin/image.mm @@ -0,0 +1,124 @@ +#include + +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +namespace mbgl { +namespace util { + +std::string compress_png(int width, int height, const void *rgba) { + CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, rgba, width * height * 4, NULL); + if (!provider) { + return ""; + } + + CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB(); + if (!color_space) { + CGDataProviderRelease(provider); + return ""; + } + + CGImageRef image = CGImageCreate(width, height, 8, 32, 4 * width, color_space, + kCGBitmapByteOrderDefault | kCGImageAlphaLast, provider, NULL, false, + kCGRenderingIntentDefault); + if (!image) { + CGColorSpaceRelease(color_space); + CGDataProviderRelease(provider); + return ""; + } + + CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0); + if (!data) { + CGImageRelease(image); + CGColorSpaceRelease(color_space); + CGDataProviderRelease(provider); + return ""; + } + + CGImageDestinationRef image_destination = CGImageDestinationCreateWithData(data, kUTTypePNG, 1, NULL); + if (!image_destination) { + CFRelease(data); + CGImageRelease(image); + CGColorSpaceRelease(color_space); + CGDataProviderRelease(provider); + return ""; + } + + CGImageDestinationAddImage(image_destination, image, NULL); + CGImageDestinationFinalize(image_destination); + + const std::string result { + reinterpret_cast(CFDataGetBytePtr(data)), + static_cast(CFDataGetLength(data)) + }; + + CFRelease(image_destination); + CFRelease(data); + CGImageRelease(image); + CGColorSpaceRelease(color_space); + CGDataProviderRelease(provider); + + return result; +} + +Image::Image(const std::string &source_data) { + CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast(source_data.data()), source_data.size(), kCFAllocatorNull); + if (!data) { + return; + } + + CGImageSourceRef image_source = CGImageSourceCreateWithData(data, NULL); + if (!image_source) { + CFRelease(data); + return; + } + + CGImageRef image = CGImageSourceCreateImageAtIndex(image_source, 0, NULL); + if (!image) { + CFRelease(image_source); + CFRelease(data); + return; + } + + CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB(); + if (!color_space) { + CGImageRelease(image); + CFRelease(image_source); + CFRelease(data); + return; + } + + width = uint32_t(CGImageGetWidth(image)); + height = uint32_t(CGImageGetHeight(image)); + CGRect rect = {{ 0, 0 }, { static_cast(width), static_cast(height) }}; + + img = std::make_unique(width * height * 4); + CGContextRef context = CGBitmapContextCreate(img.get(), width, height, 8, width * 4, + color_space, kCGImageAlphaPremultipliedLast); + if (!context) { + CGColorSpaceRelease(color_space); + CGImageRelease(image); + CFRelease(image_source); + CFRelease(data); + width = 0; + height = 0; + return; + } + + CGContextSetBlendMode(context, kCGBlendModeCopy); + CGContextDrawImage(context, rect, image); + + CGContextRelease(context); + CGColorSpaceRelease(color_space); + CGImageRelease(image); + CFRelease(image_source); + CFRelease(data); +} + +} +} \ No newline at end of file diff --git a/platform/darwin/log_nslog.mm b/platform/darwin/log_nslog.mm new file mode 100644 index 000000000..a2e31968a --- /dev/null +++ b/platform/darwin/log_nslog.mm @@ -0,0 +1,13 @@ +#include + +#import + +namespace mbgl { + +void Log::platformRecord(EventSeverity severity, const std::string &msg) { + NSString *message = + [[NSString alloc] initWithBytes:msg.data() length:msg.size() encoding:NSUTF8StringEncoding]; + NSLog(@"[%s] %@", EventSeverityClass(severity).c_str(), message); +} + +} diff --git a/platform/darwin/nsthread.mm b/platform/darwin/nsthread.mm new file mode 100644 index 000000000..9ac1d2caa --- /dev/null +++ b/platform/darwin/nsthread.mm @@ -0,0 +1,13 @@ +#import + +#include + +namespace mbgl { +namespace platform { + +void makeThreadLowPriority() { + [[NSThread currentThread] setThreadPriority:0.0]; +} + +} +} diff --git a/platform/darwin/reachability.m b/platform/darwin/reachability.m new file mode 100644 index 000000000..8abcf5ae6 --- /dev/null +++ b/platform/darwin/reachability.m @@ -0,0 +1,469 @@ +/* + Copyright (c) 2011, Tony Million. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +#import +#import +#import +#import +#import +#import + + +NSString *const kMGLReachabilityChangedNotification = @"kMGLReachabilityChangedNotification"; + + +@interface MGLReachability () + +@property (nonatomic, assign) SCNetworkReachabilityRef reachabilityRef; +@property (nonatomic, strong) dispatch_queue_t reachabilitySerialQueue; +@property (nonatomic, strong) id reachabilityObject; + +-(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags; +-(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags; + +@end + + +static NSString *reachabilityFlags(SCNetworkReachabilityFlags flags) +{ + return [NSString stringWithFormat:@"%c%c %c%c%c%c%c%c%c", +#if TARGET_OS_IPHONE + (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', +#else + 'X', +#endif + (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', + (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', + (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', + (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', + (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-']; +} + +// Start listening for reachability notifications on the current run loop +static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) +{ +#pragma unused (target) + + MGLReachability *reachability = ((__bridge MGLReachability*)info); + + // We probably don't need an autoreleasepool here, as GCD docs state each queue has its own autorelease pool, + // but what the heck eh? + @autoreleasepool + { + [reachability reachabilityChanged:flags]; + } +} + + +@implementation MGLReachability + +#pragma mark - Class Constructor Methods + ++(instancetype)reachabilityWithHostName:(NSString*)hostname +{ + return [MGLReachability reachabilityWithHostname:hostname]; +} + ++(instancetype)reachabilityWithHostname:(NSString*)hostname +{ + SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]); + if (ref) + { + id reachability = [[self alloc] initWithReachabilityRef:ref]; + + return reachability; + } + + return nil; +} + ++(instancetype)reachabilityWithAddress:(void *)hostAddress +{ + SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); + if (ref) + { + id reachability = [[self alloc] initWithReachabilityRef:ref]; + + return reachability; + } + + return nil; +} + ++(instancetype)reachabilityForInternetConnection +{ + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + + return [self reachabilityWithAddress:&zeroAddress]; +} + ++(instancetype)reachabilityForLocalWiFi +{ + struct sockaddr_in localWifiAddress; + bzero(&localWifiAddress, sizeof(localWifiAddress)); + localWifiAddress.sin_len = sizeof(localWifiAddress); + localWifiAddress.sin_family = AF_INET; + // IN_LINKLOCALNETNUM is defined in as 169.254.0.0 + localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); + + return [self reachabilityWithAddress:&localWifiAddress]; +} + + +// Initialization methods + +-(instancetype)initWithReachabilityRef:(SCNetworkReachabilityRef)ref +{ + self = [super init]; + if (self != nil) + { + self.reachableOnWWAN = YES; + self.reachabilityRef = ref; + + // We need to create a serial queue. + // We allocate this once for the lifetime of the notifier. + + self.reachabilitySerialQueue = dispatch_queue_create("com.tonymillion.reachability", NULL); + } + + return self; +} + +-(void)dealloc +{ + [self stopNotifier]; + + if(self.reachabilityRef) + { + CFRelease(self.reachabilityRef); + self.reachabilityRef = nil; + } + + self.reachableBlock = nil; + self.unreachableBlock = nil; + self.reachabilitySerialQueue = nil; +} + +#pragma mark - Notifier Methods + +// Notifier +// NOTE: This uses GCD to trigger the blocks - they *WILL NOT* be called on THE MAIN THREAD +// - In other words DO NOT DO ANY UI UPDATES IN THE BLOCKS. +// INSTEAD USE dispatch_async(dispatch_get_main_queue(), ^{UISTUFF}) (or dispatch_sync if you want) + +-(BOOL)startNotifier +{ + // allow start notifier to be called multiple times + if(self.reachabilityObject && (self.reachabilityObject == self)) + { + return YES; + } + + + SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL }; + context.info = (__bridge void *)self; + + if(SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context)) + { + // Set it as our reachability queue, which will retain the queue + if(SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue)) + { + // this should do a retain on ourself, so as long as we're in notifier mode we shouldn't disappear out from under ourselves + // woah + self.reachabilityObject = self; + return YES; + } + else + { +#ifdef DEBUG + NSLog(@"SCNetworkReachabilitySetDispatchQueue() failed: %s", SCErrorString(SCError())); +#endif + + // UH OH - FAILURE - stop any callbacks! + SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); + } + } + else + { +#ifdef DEBUG + NSLog(@"SCNetworkReachabilitySetCallback() failed: %s", SCErrorString(SCError())); +#endif + } + + // if we get here we fail at the internet + self.reachabilityObject = nil; + return NO; +} + +-(void)stopNotifier +{ + // First stop, any callbacks! + SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); + + // Unregister target from the GCD serial dispatch queue. + SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, NULL); + + self.reachabilityObject = nil; +} + +#pragma mark - reachability tests + +// This is for the case where you flick the airplane mode; +// you end up getting something like this: +//Reachability: WR ct----- +//Reachability: -- ------- +//Reachability: WR ct----- +//Reachability: -- ------- +// We treat this as 4 UNREACHABLE triggers - really apple should do better than this + +#define testcase (kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection) + +-(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags +{ + BOOL connectionUP = YES; + + if(!(flags & kSCNetworkReachabilityFlagsReachable)) + connectionUP = NO; + + if( (flags & testcase) == testcase ) + connectionUP = NO; + +#if TARGET_OS_IPHONE + if(flags & kSCNetworkReachabilityFlagsIsWWAN) + { + // We're on 3G. + if(!self.reachableOnWWAN) + { + // We don't want to connect when on 3G. + connectionUP = NO; + } + } +#endif + + return connectionUP; +} + +-(BOOL)isReachable +{ + SCNetworkReachabilityFlags flags; + + if(!SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + return NO; + + return [self isReachableWithFlags:flags]; +} + +-(BOOL)isReachableViaWWAN +{ +#if TARGET_OS_IPHONE + + SCNetworkReachabilityFlags flags = 0; + + if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + // Check we're REACHABLE + if(flags & kSCNetworkReachabilityFlagsReachable) + { + // Now, check we're on WWAN + if(flags & kSCNetworkReachabilityFlagsIsWWAN) + { + return YES; + } + } + } +#endif + + return NO; +} + +-(BOOL)isReachableViaWiFi +{ + SCNetworkReachabilityFlags flags = 0; + + if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + // Check we're reachable + if((flags & kSCNetworkReachabilityFlagsReachable)) + { +#if TARGET_OS_IPHONE + // Check we're NOT on WWAN + if((flags & kSCNetworkReachabilityFlagsIsWWAN)) + { + return NO; + } +#endif + return YES; + } + } + + return NO; +} + + +// WWAN may be available, but not active until a connection has been established. +// WiFi may require a connection for VPN on Demand. +-(BOOL)isConnectionRequired +{ + return [self connectionRequired]; +} + +-(BOOL)connectionRequired +{ + SCNetworkReachabilityFlags flags; + + if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + return (flags & kSCNetworkReachabilityFlagsConnectionRequired); + } + + return NO; +} + +// Dynamic, on demand connection? +-(BOOL)isConnectionOnDemand +{ + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && + (flags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand))); + } + + return NO; +} + +// Is user intervention required? +-(BOOL)isInterventionRequired +{ + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && + (flags & kSCNetworkReachabilityFlagsInterventionRequired)); + } + + return NO; +} + + +#pragma mark - reachability status stuff + +-(NetworkStatus)currentReachabilityStatus +{ + if([self isReachable]) + { + if([self isReachableViaWiFi]) + return ReachableViaWiFi; + +#if TARGET_OS_IPHONE + return ReachableViaWWAN; +#endif + } + + return NotReachable; +} + +-(SCNetworkReachabilityFlags)reachabilityFlags +{ + SCNetworkReachabilityFlags flags = 0; + + if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + return flags; + } + + return 0; +} + +-(NSString*)currentReachabilityString +{ + NetworkStatus temp = [self currentReachabilityStatus]; + + if(temp == ReachableViaWWAN) + { + // Updated for the fact that we have CDMA phones now! + return NSLocalizedString(@"Cellular", @""); + } + if (temp == ReachableViaWiFi) + { + return NSLocalizedString(@"WiFi", @""); + } + + return NSLocalizedString(@"No Connection", @""); +} + +-(NSString*)currentReachabilityFlags +{ + return reachabilityFlags([self reachabilityFlags]); +} + +#pragma mark - Callback function calls this method + +-(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags +{ + if([self isReachableWithFlags:flags]) + { + if(self.reachableBlock) + { + self.reachableBlock(self); + } + } + else + { + if(self.unreachableBlock) + { + self.unreachableBlock(self); + } + } + + // this makes sure the change notification happens on the MAIN THREAD + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:kMGLReachabilityChangedNotification + object:self]; + }); +} + +#pragma mark - Debug Description + +- (NSString *) description +{ + NSString *description = [NSString stringWithFormat:@"<%@: %#x (%@)>", + NSStringFromClass([self class]), (unsigned int) self, [self currentReachabilityFlags]]; + return description; +} + +@end diff --git a/platform/darwin/settings_nsuserdefaults.mm b/platform/darwin/settings_nsuserdefaults.mm new file mode 100644 index 000000000..f6f9bbeed --- /dev/null +++ b/platform/darwin/settings_nsuserdefaults.mm @@ -0,0 +1,57 @@ +#import + +#include + +using namespace mbgl; + +Settings_NSUserDefaults::Settings_NSUserDefaults() +{ + [[NSUserDefaults standardUserDefaults] registerDefaults:@{ + @"longitude" : @(longitude), + @"latitude" : @(latitude), + @"zoom" : @(zoom), + @"bearing" : @(bearing), + @"userTrackingMode" : @(userTrackingMode), + @"showsUserLocation" : @(showsUserLocation), + @"debug" : @(debug), + }]; + load(); +} + +void Settings_NSUserDefaults::load() +{ + NSDictionary *settings = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]; + + longitude = [settings[@"longitude"] doubleValue]; + latitude = [settings[@"latitude"] doubleValue]; + zoom = [settings[@"zoom"] doubleValue]; + bearing = [settings[@"bearing"] doubleValue]; + debug = [settings[@"debug"] boolValue]; + + unsigned uncheckedTrackingMode = [settings[@"trackingMode"] unsignedIntValue]; + if (uncheckedTrackingMode > MGLUserTrackingModeNone && + uncheckedTrackingMode <= MGLUserTrackingModeFollowWithCourse) + { + userTrackingMode = (MGLUserTrackingMode)uncheckedTrackingMode; + } + showsUserLocation = [settings[@"showsUserLocation"] boolValue]; +} + +void Settings_NSUserDefaults::save() +{ + [[NSUserDefaults standardUserDefaults] setValuesForKeysWithDictionary:@{ + @"longitude" : @(longitude), + @"latitude" : @(latitude), + @"zoom" : @(zoom), + @"bearing" : @(bearing), + @"userTrackingMode" : @(userTrackingMode), + @"showsUserLocation" : @(showsUserLocation), + @"debug" : @(debug), + }]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +void Settings_NSUserDefaults::clear() +{ + [NSUserDefaults resetStandardUserDefaults]; +} \ No newline at end of file diff --git a/platform/darwin/string_nsstring.mm b/platform/darwin/string_nsstring.mm new file mode 100644 index 000000000..9bf199afc --- /dev/null +++ b/platform/darwin/string_nsstring.mm @@ -0,0 +1,31 @@ +#import + +#include + +namespace mbgl { +namespace platform { + +std::string uppercase(const std::string &string) { + NSString *original = [[NSString alloc] initWithBytesNoCopy:const_cast(string.data()) + length:string.size() + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + NSString *uppercase = [original uppercaseString]; + const std::string result{[uppercase cStringUsingEncoding : NSUTF8StringEncoding], + [uppercase lengthOfBytesUsingEncoding:NSUTF8StringEncoding]}; + return result; +} + +std::string lowercase(const std::string &string) { + NSString *original = [[NSString alloc] initWithBytesNoCopy:const_cast(string.data()) + length:string.size() + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + NSString *lowercase = [original lowercaseString]; + const std::string result{[lowercase cStringUsingEncoding : NSUTF8StringEncoding], + [lowercase lengthOfBytesUsingEncoding:NSUTF8StringEncoding]}; + return result; +} + +} +} diff --git a/platform/default/application_root.cpp b/platform/default/application_root.cpp new file mode 100644 index 000000000..6669a049a --- /dev/null +++ b/platform/default/application_root.cpp @@ -0,0 +1,28 @@ +#include + +#include +#include + +namespace mbgl { +namespace platform { + +// Returns the path to the root folder of the application. +const std::string &applicationRoot() { + static const std::string root = []() -> std::string { + size_t max = 0; + std::string dir; + do { + // Gradually increase the length of the string in case the path was truncated. + max += 256; + dir.resize(max); + uv_exepath(const_cast(dir.data()), &max); + } while (max == dir.size()); + dir.resize(max - 1); + dir = dirname(const_cast(dir.c_str())); + return dir; + }(); + return root; +} + +} +} diff --git a/platform/default/asset_request_fs.cpp b/platform/default/asset_request_fs.cpp new file mode 100644 index 000000000..733e240fb --- /dev/null +++ b/platform/default/asset_request_fs.cpp @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace mbgl { + +class AssetRequest : public RequestBase { + MBGL_STORE_THREAD(tid) + +public: + AssetRequest(const Resource&, Callback, uv_loop_t*, const std::string& assetRoot); + ~AssetRequest(); + + void cancel() final; + + static void fileOpened(uv_fs_t *req); + static void fileStated(uv_fs_t *req); + static void fileRead(uv_fs_t *req); + static void fileClosed(uv_fs_t *req); + static void notifyError(uv_fs_t *req); + static void cleanup(uv_fs_t *req); + + std::string assetRoot; + bool canceled = false; + uv_fs_t req; + uv_file fd = -1; + uv_buf_t buffer; + std::unique_ptr response; +}; + +class AssetFSContext : public AssetContextBase { + RequestBase* createRequest(const Resource& resource, + RequestBase::Callback callback, + uv_loop_t* loop, + const std::string& assetRoot) final { + return new AssetRequest(resource, callback, loop, assetRoot); + } +}; + +AssetRequest::~AssetRequest() { + MBGL_VERIFY_THREAD(tid); +} + +AssetRequest::AssetRequest(const Resource& resource_, Callback callback_, uv_loop_t* loop, const std::string& assetRoot_) + : RequestBase(resource_, callback_), + assetRoot(assetRoot_) { + req.data = this; + + const auto &url = resource.url; + std::string path; + if (url.size() <= 8 || url[8] == '/') { + // This is an empty or absolute path. + path = mbgl::util::percentDecode(url.substr(8)); + } else { + // This is a relative path. Prefix with the application root. + path = assetRoot + "/" + mbgl::util::percentDecode(url.substr(8)); + } + + uv_fs_open(loop, &req, path.c_str(), O_RDONLY, S_IRUSR, fileOpened); +} + +void AssetRequest::fileOpened(uv_fs_t *req) { + assert(req->data); + auto self = reinterpret_cast(req->data); + MBGL_VERIFY_THREAD(self->tid); + + if (req->result < 0) { + // Opening failed or was canceled. There isn't much left we can do. + notifyError(req); + cleanup(req); + } else { + const uv_file fd = uv_file(req->result); + + // We're going to reuse this handle, so we need to cleanup first. + uv_fs_req_cleanup(req); + + if (self->canceled) { + // The request was canceled. + uv_fs_close(req->loop, req, fd, fileClosed); + } else { + self->fd = fd; + uv_fs_fstat(req->loop, req, fd, fileStated); + } + } +} + +void AssetRequest::fileStated(uv_fs_t *req) { + assert(req->data); + auto self = reinterpret_cast(req->data); + MBGL_VERIFY_THREAD(self->tid); + + if (req->result != 0 || self->canceled) { + // Stating failed or was canceled. We already have an open file handle + // though, which we'll have to close. + notifyError(req); + + uv_fs_req_cleanup(req); + uv_fs_close(req->loop, req, self->fd, fileClosed); + } else { +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + auto stat = static_cast(req->ptr); +#else + auto stat = static_cast(req->ptr); +#endif + if (stat->st_size > std::numeric_limits::max()) { + // File is too large for us to open this way because uv_buf's only support unsigned + // ints as maximum size. + auto response = std::make_unique(); + response->status = Response::Error; +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + response->message = uv_strerror(uv_err_t {UV_EFBIG, 0}); +#else + response->message = uv_strerror(UV_EFBIG); +#endif + self->notify(std::move(response), FileCache::Hint::No); + + uv_fs_req_cleanup(req); + uv_fs_close(req->loop, req, self->fd, fileClosed); + } else { + self->response = std::make_unique(); +#ifdef __APPLE__ + self->response->modified = stat->st_mtimespec.tv_sec; +#else + self->response->modified = stat->st_mtime; +#endif + self->response->etag = util::toString(stat->st_ino); + const auto size = (unsigned int)(stat->st_size); + self->response->data.resize(size); + self->buffer = uv_buf_init(const_cast(self->response->data.data()), size); + uv_fs_req_cleanup(req); +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + uv_fs_read(req->loop, req, self->fd, self->buffer.base, self->buffer.len, -1, fileRead); +#else + uv_fs_read(req->loop, req, self->fd, &self->buffer, 1, 0, fileRead); +#endif + } + } +} + +void AssetRequest::fileRead(uv_fs_t *req) { + assert(req->data); + auto self = reinterpret_cast(req->data); + MBGL_VERIFY_THREAD(self->tid); + + if (req->result < 0 || self->canceled) { + // Stating failed or was canceled. We already have an open file handle + // though, which we'll have to close. + notifyError(req); + } else { + // File was successfully read. + self->response->status = Response::Successful; + self->notify(std::move(self->response), FileCache::Hint::No); + } + + uv_fs_req_cleanup(req); + uv_fs_close(req->loop, req, self->fd, fileClosed); +} + +void AssetRequest::fileClosed(uv_fs_t *req) { + assert(req->data); + auto self = reinterpret_cast(req->data); + MBGL_VERIFY_THREAD(self->tid); + (void(self)); // Silence unused variable error in Release mode + + if (req->result < 0) { + // Closing the file failed. But there isn't anything we can do. + } + + cleanup(req); +} + +void AssetRequest::notifyError(uv_fs_t *req) { + assert(req->data); + auto self = reinterpret_cast(req->data); + MBGL_VERIFY_THREAD(self->tid); + + if (req->result < 0 && !self->canceled && req->result != UV_ECANCELED) { + auto response = std::make_unique(); + response->status = Response::Error; + response->message = uv::getFileRequestError(req); + self->notify(std::move(response), FileCache::Hint::No); + } +} + +void AssetRequest::cleanup(uv_fs_t *req) { + assert(req->data); + auto self = reinterpret_cast(req->data); + MBGL_VERIFY_THREAD(self->tid); + uv_fs_req_cleanup(req); + delete self; +} + +void AssetRequest::cancel() { + canceled = true; + // uv_cancel fails frequently when the request has already been started. + // In that case, we have to let it complete and check the canceled bool + // instead. The cancelation callback will delete the AssetRequest object. + uv_cancel((uv_req_t *)&req); +} + +std::unique_ptr AssetContextBase::createContext(uv_loop_t*) { + return std::make_unique(); +} + +} diff --git a/platform/default/asset_request_zip.cpp b/platform/default/asset_request_zip.cpp new file mode 100644 index 000000000..13c7df4cc --- /dev/null +++ b/platform/default/asset_request_zip.cpp @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include "uv_zip.h" + +#include +#include +#include + +namespace mbgl { + +class AssetZipContext : public AssetContextBase { +public: + explicit AssetZipContext(uv_loop_t *loop); + ~AssetZipContext(); + + RequestBase* createRequest(const Resource& resource, + RequestBase::Callback callback, + uv_loop_t* loop, + const std::string& assetRoot) final; + + uv_zip_t *getHandle(const std::string &path); + void returnHandle(const std::string &path, uv_zip_t *zip); + + // A list of resuable uv_zip handles to avoid creating and destroying them all the time. + std::map> handles; + uv_loop_t *loop; +}; + +AssetZipContext::AssetZipContext(uv_loop_t *loop_) : loop(loop_) { +} + +uv_zip_t *AssetZipContext::getHandle(const std::string &path) { + auto &list = handles[path]; + if (!list.empty()) { + auto zip = list.front(); + list.pop_front(); + return zip; + } else { + return nullptr; + } +} + +void AssetZipContext::returnHandle(const std::string &path, uv_zip_t *zip) { + handles[path].push_front(zip); +} + +AssetZipContext::~AssetZipContext() { + // Close all zip handles + for (auto &list : handles) { + for (auto zip : list.second) { + uv_zip_discard(loop, zip, [](uv_zip_t *zip_) { + uv_zip_cleanup(zip_); + delete zip_; + }); + } + } + handles.clear(); +} + +class AssetRequest : public RequestBase { + MBGL_STORE_THREAD(tid) + +public: + AssetRequest(AssetZipContext&, const Resource&, Callback, const std::string& assetRoot); + ~AssetRequest(); + + void cancel() final; + +private: + AssetZipContext &context; + bool cancelled = false; + const std::string root; + const std::string path; + std::unique_ptr response; + uv_buf_t buffer; + +private: + void openZipArchive(); + void archiveOpened(uv_zip_t *zip); + void fileStated(uv_zip_t *zip); + void fileOpened(uv_zip_t *zip); + void fileRead(uv_zip_t *zip); + void fileClosed(uv_zip_t *zip); + void cleanup(uv_zip_t *zip); + + void notifyError(const char *message); +}; + +RequestBase* AssetZipContext::createRequest(const Resource& resource, + RequestBase::Callback callback, + uv_loop_t*, + const std::string& assetRoot) { + return new AssetRequest(*this, resource, callback, assetRoot); +} + +AssetRequest::AssetRequest(AssetZipContext& context_, const Resource& resource_, Callback callback_, const std::string& assetRoot_) + : RequestBase(resource_, callback_), + context(context_), + root(assetRoot_), + path(std::string { "assets/" } + resource.url.substr(8)) { + auto zip = context.getHandle(root); + if (zip) { + archiveOpened(zip); + } else { + openZipArchive(); + } +} + +AssetRequest::~AssetRequest() { + MBGL_VERIFY_THREAD(tid); +} + +void AssetRequest::openZipArchive() { + uv_fs_t *req = new uv_fs_t(); + req->data = this; + + // We're using uv_fs_open first to obtain a file descriptor. Then, uv_zip_fdopen will operate + // on a read-only file. + uv_fs_open(context.loop, req, root.c_str(), O_RDONLY, S_IRUSR, [](uv_fs_t *fsReq) { + if (fsReq->result < 0) { + auto impl = reinterpret_cast(fsReq->data); + impl->notifyError(uv::getFileRequestError(fsReq)); + delete impl; + } else { + uv_zip_t *zip = new uv_zip_t(); + uv_zip_init(zip); + zip->data = fsReq->data; + uv_zip_fdopen(fsReq->loop, zip, uv_file(fsReq->result), 0, [](uv_zip_t *openZip) { + auto impl = reinterpret_cast(openZip->data); + if (openZip->result < 0) { + impl->notifyError(openZip->message); + delete openZip; + delete impl; + } else { + impl->archiveOpened(openZip); + } + }); + } + + uv_fs_req_cleanup(fsReq); + delete fsReq; + fsReq = nullptr; + }); +} + +#define INVOKE_MEMBER(name) \ + [](uv_zip_t *zip_) { \ + assert(zip_->data); \ + reinterpret_cast(zip_->data)->name(zip_); \ + } + +void AssetRequest::archiveOpened(uv_zip_t *zip) { + MBGL_VERIFY_THREAD(tid); + + zip->data = this; + uv_zip_stat(context.loop, zip, path.c_str(), 0, INVOKE_MEMBER(fileStated)); +} + +void AssetRequest::fileStated(uv_zip_t *zip) { + MBGL_VERIFY_THREAD(tid); + + if (cancelled || zip->result < 0) { + // Stat failed, probably because the file doesn't exist. + if (zip->result < 0) { + notifyError(zip->message); + } + cleanup(zip); + } else if (!(zip->stat->valid & ZIP_STAT_SIZE)) { + // We couldn't obtain the size of the file. + notifyError("Could not determine file size in zip file"); + cleanup(zip); + } else { + response = std::make_unique(); + + // Allocate the space for reading the data. + response->data.resize(zip->stat->size); + buffer = uv_buf_init(const_cast(response->data.data()), zip->stat->size); + + // Get the modification time in case we have one. + if (zip->stat->valid & ZIP_STAT_MTIME) { + response->modified = zip->stat->mtime; + } + + if (zip->stat->valid & ZIP_STAT_INDEX) { + response->etag = std::to_string(zip->stat->index); + } + + uv_zip_fopen(context.loop, zip, path.c_str(), 0, INVOKE_MEMBER(fileOpened)); + } +} + +void AssetRequest::fileOpened(uv_zip_t *zip) { + MBGL_VERIFY_THREAD(tid); + + if (zip->result < 0) { + // Opening failed. + notifyError(zip->message); + cleanup(zip); + } else if (cancelled) { + // The request was canceled. Close the file again. + uv_zip_fclose(context.loop, zip, zip->file, INVOKE_MEMBER(fileClosed)); + } else { + uv_zip_fread(context.loop, zip, zip->file, &buffer, INVOKE_MEMBER(fileRead)); + } +} + +void AssetRequest::fileRead(uv_zip_t *zip) { + MBGL_VERIFY_THREAD(tid); + + if (zip->result < 0) { + // Reading failed. We still have an open file handle though. + notifyError(zip->message); + } else if (!cancelled) { + response->status = Response::Successful; + notify(std::move(response), FileCache::Hint::No); + } + + uv_zip_fclose(context.loop, zip, zip->file, INVOKE_MEMBER(fileClosed)); +} + +void AssetRequest::fileClosed(uv_zip_t *zip) { + MBGL_VERIFY_THREAD(tid); + + if (zip->result < 0) { + // Closing the file failed. But there isn't anything we can do. + } + + cleanup(zip); +} + +void AssetRequest::cleanup(uv_zip_t *zip) { + MBGL_VERIFY_THREAD(tid); + + context.returnHandle(root, zip); + delete this; +} + +void AssetRequest::notifyError(const char *message) { + MBGL_VERIFY_THREAD(tid); + + if (!cancelled) { + response = std::make_unique(); + response->status = Response::Error; + response->message = message; + notify(std::move(response), FileCache::Hint::No); + } else { + // The request was already canceled and deleted. + } +} + +void AssetRequest::cancel() { + cancelled = true; +} + +std::unique_ptr AssetContextBase::createContext(uv_loop_t* loop) { + return std::make_unique(loop); +} + +} diff --git a/platform/default/asset_root.cpp b/platform/default/asset_root.cpp new file mode 100644 index 000000000..2b20018c4 --- /dev/null +++ b/platform/default/asset_root.cpp @@ -0,0 +1,28 @@ +#include + +#include +#include + +namespace mbgl { +namespace platform { + +// Returns the path to the root folder of the application. +const std::string &assetRoot() { + static const std::string root = []() -> std::string { + size_t max = 0; + std::string dir; + do { + // Gradually increase the length of the string in case the path was truncated. + max += 256; + dir.resize(max); + uv_exepath(const_cast(dir.data()), &max); + } while (max == dir.size()); + dir.resize(max - 1); + dir = dirname(const_cast(dir.c_str())); + return dir; + }(); + return root; +} + +} +} diff --git a/platform/default/default_styles.cpp b/platform/default/default_styles.cpp new file mode 100644 index 000000000..e25d96e4c --- /dev/null +++ b/platform/default/default_styles.cpp @@ -0,0 +1,15 @@ +#include "default_styles.hpp" + +namespace mbgl { +namespace util { + +const std::vector> defaultStyles = { + { "asset://styles/mapbox-streets-v7.json", "Mapbox Streets" }, + { "asset://styles/emerald-v7.json", "Emerald" }, + { "asset://styles/light-v7.json", "Light" }, + { "asset://styles/dark-v7.json", "Dark" }, + { "asset://styles/satellite-v7.json", "Satellite" } +}; + +} // end namespace util +} // end namespace mbgl diff --git a/platform/default/default_styles.hpp b/platform/default/default_styles.hpp new file mode 100644 index 000000000..dc1000930 --- /dev/null +++ b/platform/default/default_styles.hpp @@ -0,0 +1,17 @@ +#ifndef MBGL_PLATFORM_DEFAULT_STYLES +#define MBGL_PLATFORM_DEFAULT_STYLES + +#include +#include + +namespace mbgl { +namespace util { + +// A list of default styles, with the first string being the URL +// and the second being the user-visible name. +extern const std::vector> defaultStyles; + +} // end namespace util +} // end namespace mbgl + +#endif diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp new file mode 100644 index 000000000..8453845d1 --- /dev/null +++ b/platform/default/glfw_view.cpp @@ -0,0 +1,507 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +void glfwError(int error, const char *description) { + mbgl::Log::Error(mbgl::Event::OpenGL, "GLFW error (%i): %s", error, description); + assert(false); +} + +GLFWView::GLFWView(bool fullscreen_, bool benchmark_) + : fullscreen(fullscreen_), benchmark(benchmark_) { + glfwSetErrorCallback(glfwError); + + std::srand(std::time(0)); + + if (!glfwInit()) { + mbgl::Log::Error(mbgl::Event::OpenGL, "failed to initialize glfw"); + exit(1); + } + + GLFWmonitor *monitor = nullptr; + if (fullscreen) { + monitor = glfwGetPrimaryMonitor(); + auto videoMode = glfwGetVideoMode(monitor); + width = videoMode->width; + height = videoMode->height; + } + +#ifdef DEBUG + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); +#endif + +#ifdef GL_ES_VERSION_2_0 + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); +#endif + + glfwWindowHint(GLFW_RED_BITS, 8); + glfwWindowHint(GLFW_GREEN_BITS, 8); + glfwWindowHint(GLFW_BLUE_BITS, 8); + glfwWindowHint(GLFW_ALPHA_BITS, 8); + glfwWindowHint(GLFW_STENCIL_BITS, 8); + glfwWindowHint(GLFW_DEPTH_BITS, 16); + + window = glfwCreateWindow(width, height, "Mapbox GL", monitor, NULL); + if (!window) { + glfwTerminate(); + mbgl::Log::Error(mbgl::Event::OpenGL, "failed to initialize window"); + exit(1); + } + + glfwSetWindowUserPointer(window, this); + glfwMakeContextCurrent(window); + if (benchmark) { + // Disables vsync on platforms that support it. + glfwSwapInterval(0); + } else { + glfwSwapInterval(1); + } + + + glfwSetCursorPosCallback(window, onMouseMove); + glfwSetMouseButtonCallback(window, onMouseClick); + glfwSetWindowSizeCallback(window, onWindowResize); + glfwSetFramebufferSizeCallback(window, onFramebufferResize); + glfwSetScrollCallback(window, onScroll); + glfwSetKeyCallback(window, onKey); + + mbgl::gl::InitializeExtensions(glfwGetProcAddress); + + glfwGetWindowSize(window, &width, &height); + glfwGetFramebufferSize(window, &fbWidth, &fbHeight); + pixelRatio = static_cast(fbWidth) / width; + + glfwMakeContextCurrent(nullptr); +} + +GLFWView::~GLFWView() { + glfwDestroyWindow(window); + glfwTerminate(); +} + +void GLFWView::initialize(mbgl::Map *map_) { + View::initialize(map_); +} + +void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + + if (action == GLFW_RELEASE) { + switch (key) { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, true); + break; + case GLFW_KEY_TAB: + view->map->toggleDebug(); + break; + case GLFW_KEY_C: + view->map->toggleCollisionDebug(); + break; + case GLFW_KEY_X: + if (!mods) + view->map->resetPosition(); + break; + case GLFW_KEY_S: + if (view->changeStyleCallback) + view->changeStyleCallback(); + break; + case GLFW_KEY_R: + if (!mods) { + view->map->setDefaultTransitionDuration(std::chrono::milliseconds(300)); + if (view->map->hasClass("night")) { + view->map->removeClass("night"); + } else { + view->map->addClass("night"); + } + } + break; + case GLFW_KEY_N: + if (!mods) + view->map->resetNorth(); + break; + case GLFW_KEY_Q: + view->clearAnnotations(); + break; + case GLFW_KEY_P: { + view->addRandomCustomPointAnnotations(1); + } break; + } + } + + if (action == GLFW_RELEASE || action == GLFW_REPEAT) { + switch (key) { + case GLFW_KEY_W: view->popAnnotation(); break; + case GLFW_KEY_1: view->addRandomPointAnnotations(1); break; + case GLFW_KEY_2: view->addRandomPointAnnotations(10); break; + case GLFW_KEY_3: view->addRandomPointAnnotations(100); break; + case GLFW_KEY_4: view->addRandomPointAnnotations(1000); break; + case GLFW_KEY_5: view->addRandomPointAnnotations(10000); break; + case GLFW_KEY_6: view->addRandomPointAnnotations(100000); break; + case GLFW_KEY_7: view->addRandomShapeAnnotations(1); break; + case GLFW_KEY_8: view->addRandomShapeAnnotations(10); break; + case GLFW_KEY_9: view->addRandomShapeAnnotations(100); break; + case GLFW_KEY_0: view->addRandomShapeAnnotations(1000); break; + } + } +} + +mbgl::LatLng GLFWView::makeRandomPoint() const { + const auto sw = map->latLngForPixel({ 0, 0 }); + const auto ne = map->latLngForPixel({ double(width), double(height) }); + + const double lon = sw.longitude + (ne.longitude - sw.longitude) * (double(std::rand()) / RAND_MAX); + const double lat = sw.latitude + (ne.latitude - sw.latitude) * (double(std::rand()) / RAND_MAX); + + return { lat, lon }; +} + +std::shared_ptr +GLFWView::makeSpriteImage(int width, int height, float pixelRatio) { + const int r = 255 * (double(std::rand()) / RAND_MAX); + const int g = 255 * (double(std::rand()) / RAND_MAX); + const int b = 255 * (double(std::rand()) / RAND_MAX); + + const int w = std::ceil(pixelRatio * width); + const int h = std::ceil(pixelRatio * height); + + std::string pixels(w * h * 4, '\x00'); + auto data = reinterpret_cast(const_cast(pixels.data())); + const int dist = (w / 2) * (w / 2); + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + const int dx = x - w / 2; + const int dy = y - h / 2; + const int diff = dist - (dx * dx + dy * dy); + if (diff > 0) { + const int a = std::min(0xFF, diff) * 0xFF / dist; + // Premultiply the rgb values with alpha + data[w * y + x] = + (a << 24) | ((a * r / 0xFF) << 16) | ((a * g / 0xFF) << 8) | (a * b / 0xFF); + } + } + } + + return std::make_shared(width, height, pixelRatio, std::move(pixels)); +} + +void GLFWView::addRandomCustomPointAnnotations(int count) { + std::vector points; + + for (int i = 0; i < count; i++) { + static int spriteID = 1; + const auto name = std::string{ "marker-" } + mbgl::util::toString(spriteID++); + map->setSprite(name, makeSpriteImage(22, 22, 1)); + spriteIDs.push_back(name); + points.emplace_back(makeRandomPoint(), name); + } + + auto newIDs = map->addPointAnnotations(points); + annotationIDs.insert(annotationIDs.end(), newIDs.begin(), newIDs.end()); +} + +void GLFWView::addRandomPointAnnotations(int count) { + std::vector points; + + for (int i = 0; i < count; i++) { + points.emplace_back(makeRandomPoint(), "default_marker"); + } + + auto newIDs = map->addPointAnnotations(points); + annotationIDs.insert(annotationIDs.end(), newIDs.begin(), newIDs.end()); +} + +void GLFWView::addRandomShapeAnnotations(int count) { + std::vector shapes; + + mbgl::FillProperties fillProperties; + fillProperties.opacity = .1; + + mbgl::StyleProperties properties; + properties.set(fillProperties); + + for (int i = 0; i < count; i++) { + mbgl::AnnotationSegment triangle; + triangle.push_back(makeRandomPoint()); + triangle.push_back(makeRandomPoint()); + triangle.push_back(makeRandomPoint()); + + mbgl::AnnotationSegments segments; + segments.push_back(triangle); + + shapes.emplace_back(segments, properties); + } + + auto newIDs = map->addShapeAnnotations(shapes); + annotationIDs.insert(annotationIDs.end(), newIDs.begin(), newIDs.end()); +} + +void GLFWView::clearAnnotations() { + if (annotationIDs.empty()) { + return; + } + + map->removeAnnotations(annotationIDs); + annotationIDs.clear(); +} + +void GLFWView::popAnnotation() { + if (annotationIDs.empty()) { + return; + } + + map->removeAnnotation(annotationIDs.back()); + annotationIDs.pop_back(); +} + +void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + double delta = yOffset * 40; + + bool isWheel = delta != 0 && std::fmod(delta, 4.000244140625) == 0; + + double absDelta = delta < 0 ? -delta : delta; + double scale = 2.0 / (1.0 + std::exp(-absDelta / 100.0)); + + // Make the scroll wheel a bit slower. + if (!isWheel) { + scale = (scale - 1.0) / 2.0 + 1.0; + } + + // Zooming out. + if (delta < 0 && scale != 0) { + scale = 1.0 / scale; + } + + view->map->scaleBy(scale, view->lastX, view->lastY); +} + +void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + view->width = width; + view->height = height; + + view->map->update(mbgl::Update::Dimensions); +} + +void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + view->fbWidth = width; + view->fbHeight = height; + + view->map->update(mbgl::Update::Repaint); +} + +void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modifiers) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + + if (button == GLFW_MOUSE_BUTTON_RIGHT || + (button == GLFW_MOUSE_BUTTON_LEFT && modifiers & GLFW_MOD_CONTROL)) { + view->rotating = action == GLFW_PRESS; + view->map->setGestureInProgress(view->rotating); + } else if (button == GLFW_MOUSE_BUTTON_LEFT) { + view->tracking = action == GLFW_PRESS; + view->map->setGestureInProgress(view->tracking); + + if (action == GLFW_RELEASE) { + double now = glfwGetTime(); + if (now - view->lastClick < 0.4 /* ms */) { + if (modifiers & GLFW_MOD_SHIFT) { + view->map->scaleBy(0.5, view->lastX, view->lastY, std::chrono::milliseconds(500)); + } else { + view->map->scaleBy(2.0, view->lastX, view->lastY, std::chrono::milliseconds(500)); + } + } + view->lastClick = now; + } + } +} + +void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + if (view->tracking) { + double dx = x - view->lastX; + double dy = y - view->lastY; + if (dx || dy) { + view->map->moveBy(dx, dy); + } + } else if (view->rotating) { + view->map->rotateBy(view->lastX, view->lastY, x, y); + } + view->lastX = x; + view->lastY = y; +} + +void GLFWView::run() { + while (!glfwWindowShouldClose(window)) { + glfwWaitEvents(); + const bool dirty = !clean.test_and_set(); + if (dirty) { + const double started = glfwGetTime(); + map->renderSync(); + report(1000 * (glfwGetTime() - started)); + if (benchmark) { + map->setNeedsRepaint(); + } + map->nudgeTransitions(); + } + } +} + +float GLFWView::getPixelRatio() const { + return pixelRatio; +} + +std::array GLFWView::getSize() const { + return {{ static_cast(width), static_cast(height) }}; +} + +std::array GLFWView::getFramebufferSize() const { + return {{ static_cast(fbWidth), static_cast(fbHeight) }}; +} + +void GLFWView::activate() { + glfwMakeContextCurrent(window); +} + +void GLFWView::deactivate() { + glfwMakeContextCurrent(nullptr); +} + +void GLFWView::notify() { + glfwPostEmptyEvent(); +} + +void GLFWView::invalidate() { + clean.clear(); + glfwPostEmptyEvent(); +} + +void GLFWView::swap() { + glfwSwapBuffers(window); +} + +void GLFWView::report(float duration) { + frames++; + frameTime += duration; + + const double currentTime = glfwGetTime(); + if (currentTime - lastReported >= 1) { + frameTime /= frames; + mbgl::Log::Info(mbgl::Event::OpenGL, "Frame time: %6.2fms (%6.2f fps)", frameTime, + 1000 / frameTime); + frames = 0; + frameTime = 0; + lastReported = currentTime; + } +} + +void GLFWView::setChangeStyleCallback(std::function callback) { + changeStyleCallback = callback; +} + +void GLFWView::setShouldClose() { + glfwSetWindowShouldClose(window, true); + glfwPostEmptyEvent(); +} + +void GLFWView::setWindowTitle(const std::string& title) { + glfwSetWindowTitle(window, (std::string { "Mapbox GL: " } + title).c_str()); +} + +namespace mbgl { +namespace platform { + +#ifndef GL_ES_VERSION_2_0 +void showDebugImage(std::string name, const char *data, size_t width, size_t height) { + glfwInit(); + + static GLFWwindow *debugWindow = nullptr; + if (!debugWindow) { + debugWindow = glfwCreateWindow(width, height, name.c_str(), nullptr, nullptr); + if (!debugWindow) { + glfwTerminate(); + fprintf(stderr, "Failed to initialize window\n"); + exit(1); + } + } + + GLFWwindow *currentWindow = glfwGetCurrentContext(); + + glfwSetWindowSize(debugWindow, width, height); + glfwMakeContextCurrent(debugWindow); + + int fbWidth, fbHeight; + glfwGetFramebufferSize(debugWindow, &fbWidth, &fbHeight); + float scale = static_cast(fbWidth) / static_cast(width); + + { + gl::PreservePixelZoom pixelZoom; + gl::PreserveRasterPos rasterPos; + + MBGL_CHECK_ERROR(glPixelZoom(scale, -scale)); + MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f)); + MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, data)); + } + + glfwSwapBuffers(debugWindow); + + glfwMakeContextCurrent(currentWindow); +} + +void showColorDebugImage(std::string name, const char *data, size_t logicalWidth, size_t logicalHeight, size_t width, size_t height) { + glfwInit(); + + static GLFWwindow *debugWindow = nullptr; + if (!debugWindow) { + debugWindow = glfwCreateWindow(logicalWidth, logicalHeight, name.c_str(), nullptr, nullptr); + if (!debugWindow) { + glfwTerminate(); + fprintf(stderr, "Failed to initialize window\n"); + exit(1); + } + } + + GLFWwindow *currentWindow = glfwGetCurrentContext(); + + glfwSetWindowSize(debugWindow, logicalWidth, logicalHeight); + glfwMakeContextCurrent(debugWindow); + + int fbWidth, fbHeight; + glfwGetFramebufferSize(debugWindow, &fbWidth, &fbHeight); + float xScale = static_cast(fbWidth) / static_cast(width); + float yScale = static_cast(fbHeight) / static_cast(height); + + { + gl::PreserveClearColor clearColor; + gl::PreserveBlend blend; + gl::PreserveBlendFunc blendFunc; + gl::PreservePixelZoom pixelZoom; + gl::PreserveRasterPos rasterPos; + + MBGL_CHECK_ERROR(glClearColor(0.8, 0.8, 0.8, 1)); + MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT)); + MBGL_CHECK_ERROR(glEnable(GL_BLEND)); + MBGL_CHECK_ERROR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + MBGL_CHECK_ERROR(glPixelZoom(xScale, -yScale)); + MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f)); + MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data)); + } + + glfwSwapBuffers(debugWindow); + + glfwMakeContextCurrent(currentWindow); +} +#endif + +} +} diff --git a/platform/default/headless_display.cpp b/platform/default/headless_display.cpp new file mode 100644 index 000000000..c4535fc1a --- /dev/null +++ b/platform/default/headless_display.cpp @@ -0,0 +1,84 @@ +#include + +#include +#include + +#if MBGL_USE_GLX +#include +#endif + +namespace mbgl { + +HeadlessDisplay::HeadlessDisplay() { +#if MBGL_USE_CGL + // TODO: test if OpenGL 4.1 with GL_ARB_ES2_compatibility is supported + // If it is, use kCGLOGLPVersion_3_2_Core and enable that extension. + CGLPixelFormatAttribute attributes[] = { + kCGLPFAOpenGLProfile, + static_cast(kCGLOGLPVersion_Legacy), + kCGLPFAAccelerated, + static_cast(0) + }; + + GLint num; + CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error choosing pixel format:") + CGLErrorString(error) + "\n"); + return; + } + if (num <= 0) { + throw std::runtime_error("No pixel formats found."); + return; + } +#endif + +#if MBGL_USE_GLX + if (!XInitThreads()) { + throw std::runtime_error("Failed to XInitThreads."); + } + + xDisplay = XOpenDisplay(nullptr); + if (xDisplay == nullptr) { + throw std::runtime_error("Failed to open X display."); + } + + const char *extensions = reinterpret_cast(glXQueryServerString(xDisplay, DefaultScreen(xDisplay), GLX_EXTENSIONS)); + if (!extensions) { + throw std::runtime_error("Cannot read GLX extensions."); + } + if (!strstr(extensions,"GLX_SGIX_fbconfig")) { + throw std::runtime_error("Extension GLX_SGIX_fbconfig was not found."); + } + if (!strstr(extensions, "GLX_SGIX_pbuffer")) { + throw std::runtime_error("Cannot find glXCreateContextAttribsARB."); + } + + // We're creating a dummy pbuffer anyway that we're not using. + static int pixelFormat[] = { + GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, + None + }; + + int configs = 0; + fbConfigs = glXChooseFBConfig(xDisplay, DefaultScreen(xDisplay), pixelFormat, &configs); + if (fbConfigs == nullptr) { + throw std::runtime_error("Failed to glXChooseFBConfig."); + } + if (configs <= 0) { + throw std::runtime_error("No Framebuffer configurations."); + } +#endif +} + +HeadlessDisplay::~HeadlessDisplay() { +#if MBGL_USE_CGL + CGLDestroyPixelFormat(pixelFormat); +#endif + +#if MBGL_USE_GLX + XFree(fbConfigs); + XCloseDisplay(xDisplay); +#endif +} + +} diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp new file mode 100644 index 000000000..2d6527785 --- /dev/null +++ b/platform/default/headless_view.cpp @@ -0,0 +1,300 @@ + +#include +#include +#include + +#include + + +#include +#include +#include +#include +#include + +#ifdef MBGL_USE_CGL +#include +#elif MBGL_USE_GLX +#include +#endif + +namespace mbgl { + +HeadlessView::HeadlessView(float pixelRatio_, uint16_t width, uint16_t height) + : display(std::make_shared()), pixelRatio(pixelRatio_) { + resize(width, height); +} + +HeadlessView::HeadlessView(std::shared_ptr display_, + float pixelRatio_, + uint16_t width, + uint16_t height) + : display(display_), pixelRatio(pixelRatio_) { + resize(width, height); +} + +void HeadlessView::loadExtensions() { + if (extensionsLoaded) { + return; + } + +#ifdef MBGL_USE_CGL + gl::InitializeExtensions([](const char * name) { + static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + if (!framework) { + throw std::runtime_error("Failed to load OpenGL framework."); + } + + CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); + void* symbol = CFBundleGetFunctionPointerForName(framework, str); + CFRelease(str); + + return reinterpret_cast(symbol); + }); +#endif + +#ifdef MBGL_USE_GLX + gl::InitializeExtensions([](const char * name) { + return glXGetProcAddress(reinterpret_cast(name)); + }); +#endif + + extensionsLoaded = true; +} + +void HeadlessView::createContext() { + if (!display) { + throw std::runtime_error("Display is not set"); + } + +#if MBGL_USE_CGL + CGLError error = CGLCreateContext(display->pixelFormat, NULL, &glContext); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error creating GL context object:") + CGLErrorString(error) + "\n"); + } + + error = CGLEnable(glContext, kCGLCEMPEngine); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") + CGLErrorString(error) + "\n"); + } +#endif + +#if MBGL_USE_GLX + xDisplay = display->xDisplay; + fbConfigs = display->fbConfigs; + + if (!glContext) { + // Try to create a legacy context + glContext = glXCreateNewContext(xDisplay, fbConfigs[0], GLX_RGBA_TYPE, None, True); + if (glContext) { + if (!glXIsDirect(xDisplay, glContext)) { + Log::Error(Event::OpenGL, "failed to create direct OpenGL Legacy context"); + glXDestroyContext(xDisplay, glContext); + glContext = 0; + } + } + } + + if (glContext == 0) { + throw std::runtime_error("Error creating GL context object."); + } + + // Create a dummy pbuffer. We will render to framebuffers anyway, but we need a pbuffer to + // activate the context. + int pbufferAttributes[] = { + GLX_PBUFFER_WIDTH, 8, + GLX_PBUFFER_HEIGHT, 8, + None + }; + glxPbuffer = glXCreatePbuffer(xDisplay, fbConfigs[0], pbufferAttributes); +#endif +} + +bool HeadlessView::isActive() { + return std::this_thread::get_id() == thread; +} + +void HeadlessView::resize(const uint16_t width, const uint16_t height) { + activate(); + + dimensions = {{ width, height }}; + + clearBuffers(); + + const unsigned int w = dimensions[0] * pixelRatio; + const unsigned int h = dimensions[1] * pixelRatio; + + // Create depth/stencil buffer + MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboDepthStencil)); + MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fboDepthStencil)); + MBGL_CHECK_ERROR(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, w, h)); + MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0)); + + MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboColor)); + MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fboColor)); + MBGL_CHECK_ERROR(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h)); + MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0)); + + MBGL_CHECK_ERROR(glGenFramebuffersEXT(1, &fbo)); + MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); + + MBGL_CHECK_ERROR(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, fboColor)); + MBGL_CHECK_ERROR(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER_EXT, fboDepthStencil)); + + GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)); + + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + std::string error("Couldn't create framebuffer: "); + switch (status) { + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: (error += "incomplete attachment"); break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error += "incomplete missing attachment"; break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error += "incomplete dimensions"; break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error += "incomplete formats"; break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error += "incomplete draw buffer"; break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error += "incomplete read buffer"; break; + case GL_FRAMEBUFFER_UNSUPPORTED: error += "unsupported"; break; + default: error += "other"; break; + } + throw std::runtime_error(error); + } + + deactivate(); +} + +std::unique_ptr HeadlessView::readStillImage() { + assert(isActive()); + + const unsigned int w = dimensions[0] * pixelRatio; + const unsigned int h = dimensions[1] * pixelRatio; + + auto image = std::make_unique(); + image->width = w; + image->height = h; + image->pixels = std::make_unique(w * h); + + MBGL_CHECK_ERROR(glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels.get())); + + const int stride = w * 4; + auto tmp = std::make_unique(stride); + char *rgba = reinterpret_cast(image->pixels.get()); + for (int i = 0, j = h - 1; i < j; i++, j--) { + std::memcpy(tmp.get(), rgba + i * stride, stride); + std::memcpy(rgba + i * stride, rgba + j * stride, stride); + std::memcpy(rgba + j * stride, tmp.get(), stride); + } + + return image; +} + +void HeadlessView::clearBuffers() { + assert(isActive()); + + MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + + if (fbo) { + MBGL_CHECK_ERROR(glDeleteFramebuffersEXT(1, &fbo)); + fbo = 0; + } + + if (fboColor) { + MBGL_CHECK_ERROR(glDeleteTextures(1, &fboColor)); + fboColor = 0; + } + + if (fboDepthStencil) { + MBGL_CHECK_ERROR(glDeleteRenderbuffersEXT(1, &fboDepthStencil)); + fboDepthStencil = 0; + } +} + +HeadlessView::~HeadlessView() { + activate(); + clearBuffers(); + deactivate(); + +#if MBGL_USE_CGL + CGLDestroyContext(glContext); +#endif + +#if MBGL_USE_GLX + if (glxPbuffer) { + glXDestroyPbuffer(xDisplay, glxPbuffer); + glxPbuffer = 0; + } + + glXDestroyContext(xDisplay, glContext); +#endif +} + +void HeadlessView::notify() { + // no-op +} + +float HeadlessView::getPixelRatio() const { + return pixelRatio; +} + +std::array HeadlessView::getSize() const { + return dimensions; +} + +std::array HeadlessView::getFramebufferSize() const { + return {{ static_cast(dimensions[0] * pixelRatio), + static_cast(dimensions[1] * pixelRatio) }}; +} + +void HeadlessView::activate() { + if (thread != std::thread::id()) { + throw std::runtime_error("OpenGL context was already current"); + } + thread = std::this_thread::get_id(); + + if (!glContext) { + createContext(); + } + +#if MBGL_USE_CGL + CGLError error = CGLSetCurrentContext(glContext); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Switching OpenGL context failed:") + CGLErrorString(error) + "\n"); + } +#endif + +#if MBGL_USE_GLX + if (!glXMakeContextCurrent(xDisplay, glxPbuffer, glxPbuffer, glContext)) { + throw std::runtime_error("Switching OpenGL context failed.\n"); + } +#endif + + loadExtensions(); +} + +void HeadlessView::deactivate() { + if (thread == std::thread::id()) { + throw std::runtime_error("OpenGL context was not current"); + } + thread = std::thread::id(); + +#if MBGL_USE_CGL + CGLError error = CGLSetCurrentContext(nullptr); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Removing OpenGL context failed:") + CGLErrorString(error) + "\n"); + } +#endif + +#if MBGL_USE_GLX + if (!glXMakeContextCurrent(xDisplay, 0, 0, nullptr)) { + throw std::runtime_error("Removing OpenGL context failed.\n"); + } +#endif +} + +void HeadlessView::invalidate() { + // no-op +} + +void HeadlessView::swap() { + // no-op +} + +} diff --git a/platform/default/http_request_curl.cpp b/platform/default/http_request_curl.cpp new file mode 100644 index 000000000..e416034b4 --- /dev/null +++ b/platform/default/http_request_curl.cpp @@ -0,0 +1,617 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +void handleError(CURLMcode code) { + if (code != CURLM_OK) { + throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(code)); + } +} + +void handleError(CURLcode code) { + if (code != CURLE_OK) { + throw std::runtime_error(std::string("CURL easy error: ") + curl_easy_strerror(code)); + } +} + +namespace mbgl { + +class HTTPCURLRequest; + +class HTTPCURLContext : public HTTPContextBase { + MBGL_STORE_THREAD(tid) + +public: + explicit HTTPCURLContext(uv_loop_t *loop); + ~HTTPCURLContext(); + + HTTPRequestBase* createRequest(const Resource&, + RequestBase::Callback, + uv_loop_t*, + std::shared_ptr) final; + + static int handleSocket(CURL *handle, curl_socket_t s, int action, void *userp, void *socketp); + static void perform(uv_poll_t *req, int status, int events); + static int startTimeout(CURLM *multi, long timeout_ms, void *userp); +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + static void onTimeout(uv_timer_t *req, int status); +#else + static void onTimeout(uv_timer_t *req); +#endif + + CURL *getHandle(); + void returnHandle(CURL *handle); + void checkMultiInfo(); + + uv_loop_t *loop = nullptr; + + // Used as the CURL timer function to periodically check for socket updates. + uv_timer_t *timeout = nullptr; + + // CURL multi handle that we use to request multiple URLs at the same time, without having to + // block and spawn threads. + CURLM *multi = nullptr; + + // CURL share handles are used for sharing session state (e.g.) + CURLSH *share = nullptr; + + // A queue that we use for storing resuable CURL easy handles to avoid creating and destroying + // them all the time. + std::queue handles; +}; + +class HTTPCURLRequest : public HTTPRequestBase { + MBGL_STORE_THREAD(tid) + +public: + HTTPCURLRequest(HTTPCURLContext*, + const Resource&, + Callback, + uv_loop_t*, + std::shared_ptr); + ~HTTPCURLRequest(); + + void cancel() final; + void retry() final; + + void handleResult(CURLcode code); + +private: + static size_t headerCallback(char *const buffer, const size_t size, const size_t nmemb, void *userp); + static size_t writeCallback(void *const contents, const size_t size, const size_t nmemb, void *userp); + + void retry(uint64_t timeout) final; +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + static void restart(uv_timer_t *timer, int); +#else + static void restart(uv_timer_t *timer); +#endif + void finish(ResponseStatus status); + void start(); + + HTTPCURLContext *context = nullptr; + + // Will store the current response. + std::unique_ptr response; + + // In case of revalidation requests, this will store the old response. + const std::shared_ptr existingResponse; + + CURL *handle = nullptr; + curl_slist *headers = nullptr; + + uv_timer_t *timer = nullptr; + enum : bool { PreemptImmediately, ExponentialBackoff } strategy = PreemptImmediately; + int attempts = 0; + + static const int maxAttempts = 4; + + char error[CURL_ERROR_SIZE]; +}; + + + +struct Socket { +private: + uv_poll_t poll; + +public: + HTTPCURLContext *context = nullptr; + const curl_socket_t sockfd = 0; + +public: + Socket(HTTPCURLContext *context_, curl_socket_t sockfd_) : context(context_), sockfd(sockfd_) { + assert(context); + uv_poll_init_socket(context->loop, &poll, sockfd); + poll.data = this; + } + + void start(int events, uv_poll_cb cb) { + uv_poll_start(&poll, events, cb); + } + + void stop() { + assert(poll.data); + uv_poll_stop(&poll); + uv_close((uv_handle_t *)&poll, [](uv_handle_t *handle) { + assert(handle->data); + delete reinterpret_cast(handle->data); + }); + } + +private: + // Make the destructor private to ensure that we can only close the Socket + // with stop(), and disallow manual deletion. + ~Socket() = default; +}; + +// ------------------------------------------------------------------------------------------------- + +HTTPCURLContext::HTTPCURLContext(uv_loop_t *loop_) + : HTTPContextBase(loop_), + loop(loop_) { + if (curl_global_init(CURL_GLOBAL_ALL)) { + throw std::runtime_error("Could not init cURL"); + } + + timeout = new uv_timer_t; + timeout->data = this; + uv_timer_init(loop, timeout); + + share = curl_share_init(); + + multi = curl_multi_init(); + handleError(curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, handleSocket)); + handleError(curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, this)); + handleError(curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, startTimeout)); + handleError(curl_multi_setopt(multi, CURLMOPT_TIMERDATA, this)); +} + +HTTPCURLContext::~HTTPCURLContext() { + while (!handles.empty()) { + curl_easy_cleanup(handles.front()); + handles.pop(); + } + + curl_multi_cleanup(multi); + multi = nullptr; + + curl_share_cleanup(share); + share = nullptr; + + uv_timer_stop(timeout); + uv::close(timeout); +} + +HTTPRequestBase* HTTPCURLContext::createRequest(const Resource& resource, + RequestBase::Callback callback, + uv_loop_t* loop_, + std::shared_ptr response) { + return new HTTPCURLRequest(this, resource, callback, loop_, response); +} + +CURL *HTTPCURLContext::getHandle() { + if (!handles.empty()) { + auto handle = handles.front(); + handles.pop(); + return handle; + } else { + return curl_easy_init(); + } +} + +void HTTPCURLContext::returnHandle(CURL *handle) { + curl_easy_reset(handle); + handles.push(handle); +} + +void HTTPCURLContext::checkMultiInfo() { + MBGL_VERIFY_THREAD(tid); + CURLMsg *message = nullptr; + int pending = 0; + + while ((message = curl_multi_info_read(multi, &pending))) { + switch (message->msg) { + case CURLMSG_DONE: { + HTTPCURLRequest *baton = nullptr; + curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&baton); + assert(baton); + baton->handleResult(message->data.result); + } break; + + default: + // This should never happen, because there are no other message types. + throw std::runtime_error("CURLMsg returned unknown message type"); + } + } +} + +void HTTPCURLContext::perform(uv_poll_t *req, int /* status */, int events) { + assert(req->data); + auto socket = reinterpret_cast(req->data); + auto context = socket->context; + MBGL_VERIFY_THREAD(context->tid); + + int flags = 0; + + if (events & UV_READABLE) { + flags |= CURL_CSELECT_IN; + } + if (events & UV_WRITABLE) { + flags |= CURL_CSELECT_OUT; + } + + + int running_handles = 0; + curl_multi_socket_action(context->multi, socket->sockfd, flags, &running_handles); + context->checkMultiInfo(); +} + +int HTTPCURLContext::handleSocket(CURL * /* handle */, curl_socket_t s, int action, void *userp, + void *socketp) { + auto socket = reinterpret_cast(socketp); + assert(userp); + auto context = reinterpret_cast(userp); + MBGL_VERIFY_THREAD(context->tid); + + if (!socket && action != CURL_POLL_REMOVE) { + socket = new Socket(context, s); + curl_multi_assign(context->multi, s, (void *)socket); + } + + switch (action) { + case CURL_POLL_IN: + socket->start(UV_READABLE, perform); + break; + case CURL_POLL_OUT: + socket->start(UV_WRITABLE, perform); + break; + case CURL_POLL_REMOVE: + if (socket) { + socket->stop(); + curl_multi_assign(context->multi, s, nullptr); + } + break; + default: + throw std::runtime_error("Unhandled CURL socket action"); + } + + return 0; +} + +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 +void HTTPCURLContext::onTimeout(uv_timer_t *req, int /* status */) { +#else +void HTTPCURLContext::onTimeout(uv_timer_t *req) { +#endif + assert(req->data); + auto context = reinterpret_cast(req->data); + MBGL_VERIFY_THREAD(context->tid); + int running_handles; + CURLMcode error = curl_multi_socket_action(context->multi, CURL_SOCKET_TIMEOUT, 0, &running_handles); + if (error != CURLM_OK) { + throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(error)); + } + context->checkMultiInfo(); +} + +int HTTPCURLContext::startTimeout(CURLM * /* multi */, long timeout_ms, void *userp) { + assert(userp); + auto context = reinterpret_cast(userp); + MBGL_VERIFY_THREAD(context->tid); + if (timeout_ms < 0) { + // A timeout of 0 ms means that the timer will invoked in the next loop iteration. + timeout_ms = 0; + } + uv_timer_stop(context->timeout); + uv_timer_start(context->timeout, onTimeout, timeout_ms, 0); + return 0; +} + +// ------------------------------------------------------------------------------------------------- + +HTTPCURLRequest::HTTPCURLRequest(HTTPCURLContext* context_, const Resource& resource_, Callback callback_, uv_loop_t*, std::shared_ptr response_) + : HTTPRequestBase(resource_, callback_), + context(context_), + existingResponse(response_), + handle(context->getHandle()) { + context->addRequest(this); + + // Zero out the error buffer. + memset(error, 0, sizeof(error)); + + // If there's already a response, set the correct etags/modified headers to make sure we are + // getting a 304 response if possible. This avoids redownloading unchanged data. + if (existingResponse) { + if (!existingResponse->etag.empty()) { + const std::string header = std::string("If-None-Match: ") + existingResponse->etag; + headers = curl_slist_append(headers, header.c_str()); + } else if (existingResponse->modified) { + const std::string time = + std::string("If-Modified-Since: ") + util::rfc1123(existingResponse->modified); + headers = curl_slist_append(headers, time.c_str()); + } + } + + if (headers) { + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); + } + + handleError(curl_easy_setopt(handle, CURLOPT_PRIVATE, this)); + handleError(curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, error)); + handleError(curl_easy_setopt(handle, CURLOPT_CAINFO, "ca-bundle.crt")); + handleError(curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1)); + handleError(curl_easy_setopt(handle, CURLOPT_URL, resource.url.c_str())); + handleError(curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeCallback)); + handleError(curl_easy_setopt(handle, CURLOPT_WRITEDATA, this)); + handleError(curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, headerCallback)); + handleError(curl_easy_setopt(handle, CURLOPT_HEADERDATA, this)); +#if LIBCURL_VERSION_NUM >= ((7) << 16 | (21) << 8 | 6) // Renamed in 7.21.6 + handleError(curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate")); +#else + handleError(curl_easy_setopt(handle, CURLOPT_ENCODING, "gzip, deflate")); +#endif + handleError(curl_easy_setopt(handle, CURLOPT_USERAGENT, "MapboxGL/1.0")); + handleError(curl_easy_setopt(handle, CURLOPT_SHARE, context->share)); + + start(); +} + +HTTPCURLRequest::~HTTPCURLRequest() { + MBGL_VERIFY_THREAD(tid); + + context->removeRequest(this); + + handleError(curl_multi_remove_handle(context->multi, handle)); + context->returnHandle(handle); + handle = nullptr; + + if (timer) { + // Stop the backoff timer to avoid re-triggering this request. + uv_timer_stop(timer); + uv::close(timer); + timer = nullptr; + } + + if (headers) { + curl_slist_free_all(headers); + headers = nullptr; + } +} + +void HTTPCURLRequest::cancel() { + delete this; +} + +void HTTPCURLRequest::start() { + // Count up the attempts. + attempts++; + + // Start requesting the information. + handleError(curl_multi_add_handle(context->multi, handle)); +} + +// This function is called when we have new data for a request. We just append it to the string +// containing the previous data. +size_t HTTPCURLRequest::writeCallback(void *const contents, const size_t size, const size_t nmemb, void *userp) { + assert(userp); + auto impl = reinterpret_cast(userp); + MBGL_VERIFY_THREAD(impl->tid); + + if (!impl->response) { + impl->response = std::make_unique(); + } + + impl->response->data.append((char *)contents, size * nmemb); + return size * nmemb; +} + +// Compares the beginning of the (non-zero-terminated!) data buffer with the (zero-terminated!) +// header string. If the data buffer contains the header string at the beginning, it returns +// the length of the header string == begin of the value, otherwise it returns npos. +// The comparison of the header is ASCII-case-insensitive. +size_t headerMatches(const char *const header, const char *const buffer, const size_t length) { + const size_t headerLength = strlen(header); + if (length < headerLength) { + return std::string::npos; + } + size_t i = 0; + while (i < length && i < headerLength && std::tolower(buffer[i]) == std::tolower(header[i])) { + i++; + } + return i == headerLength ? i : std::string::npos; +} + +int64_t parseCacheControl(const char *value) { + if (value) { + unsigned long long seconds = 0; + // TODO: cache-control may contain other information as well: + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 + if (std::sscanf(value, "max-age=%llu", &seconds) == 1) { + return std::chrono::duration_cast( + SystemClock::now().time_since_epoch()).count() + + seconds; + } + } + + return 0; +} + +size_t HTTPCURLRequest::headerCallback(char *const buffer, const size_t size, const size_t nmemb, void *userp) { + assert(userp); + auto baton = reinterpret_cast(userp); + MBGL_VERIFY_THREAD(baton->tid); + + if (!baton->response) { + baton->response = std::make_unique(); + } + + const size_t length = size * nmemb; + size_t begin = std::string::npos; + if ((begin = headerMatches("last-modified: ", buffer, length)) != std::string::npos) { + // Always overwrite the modification date; We might already have a value here from the + // Date header, but this one is more accurate. + const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n + baton->response->modified = curl_getdate(value.c_str(), nullptr); + } else if ((begin = headerMatches("etag: ", buffer, length)) != std::string::npos) { + baton->response->etag = { buffer + begin, length - begin - 2 }; // remove \r\n + } else if ((begin = headerMatches("cache-control: ", buffer, length)) != std::string::npos) { + const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n + baton->response->expires = parseCacheControl(value.c_str()); + } else if ((begin = headerMatches("expires: ", buffer, length)) != std::string::npos) { + const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n + baton->response->expires = curl_getdate(value.c_str(), nullptr); + } + + return length; +} + +void HTTPCURLRequest::retry(uint64_t timeout) { + handleError(curl_multi_remove_handle(context->multi, handle)); + + response.reset(); + + assert(!timer); + timer = new uv_timer_t; + timer->data = this; + uv_timer_init(context->loop, timer); + uv_timer_start(timer, restart, timeout, 0); +} + +void HTTPCURLRequest::retry() { + // All batons get notified when the network status changed, but some of them + // might not actually wait for the network to become available again. + if (timer && strategy == PreemptImmediately) { + // Triggers the timer upon the next event loop iteration. + uv_timer_stop(timer); + uv_timer_start(timer, restart, 0, 0); + } +} + +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 +void HTTPCURLRequest::restart(uv_timer_t *timer, int) { +#else +void HTTPCURLRequest::restart(uv_timer_t *timer) { +#endif + // Restart the request. + auto baton = reinterpret_cast(timer->data); + + // Get rid of the timer. + baton->timer = nullptr; + uv::close(timer); + + baton->start(); +} + +void HTTPCURLRequest::finish(ResponseStatus status) { + if (status == ResponseStatus::TemporaryError && attempts < maxAttempts) { + strategy = ExponentialBackoff; + return retry((1 << (attempts - 1)) * 1000); + } else if (status == ResponseStatus::ConnectionError && attempts < maxAttempts) { + // By default, we will retry every 30 seconds (network change notification will + // preempt the timeout). + strategy = PreemptImmediately; + return retry(30000); + } + + // Actually return the response. + if (status == ResponseStatus::NotModified) { + notify(std::move(response), FileCache::Hint::Refresh); + } else { + notify(std::move(response), FileCache::Hint::Full); + } + + delete this; +} + +void HTTPCURLRequest::handleResult(CURLcode code) { + MBGL_VERIFY_THREAD(tid); + + if (cancelled) { + // In this case, it doesn't make sense to even process the response even further since + // the request was canceled anyway. + delete this; + return; + } + + // Make sure a response object exists in case we haven't got any headers + // or content. + if (!response) { + response = std::make_unique(); + } + + // Add human-readable error code + if (code != CURLE_OK) { + response->status = Response::Error; + response->message = std::string { curl_easy_strerror(code) } + ": " + error; + + switch (code) { + case CURLE_COULDNT_RESOLVE_PROXY: + case CURLE_COULDNT_RESOLVE_HOST: + case CURLE_COULDNT_CONNECT: + return finish(ResponseStatus::ConnectionError); + + case CURLE_OPERATION_TIMEDOUT: + return finish(ResponseStatus::TemporaryError); + + default: + return finish(ResponseStatus::PermanentError); + } + } else { + long responseCode = 0; + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &responseCode); + + if (responseCode == 304) { + if (existingResponse) { + // We're going to copy over the existing response's data. + response->status = existingResponse->status; + response->message = existingResponse->message; + response->modified = existingResponse->modified; + response->etag = existingResponse->etag; + response->data = existingResponse->data; + return finish(ResponseStatus::NotModified); + } else { + // This is an unsolicited 304 response and should only happen on malfunctioning + // HTTP servers. It likely doesn't include any data, but we don't have much options. + response->status = Response::Successful; + return finish(ResponseStatus::Successful); + } + } else if (responseCode == 200) { + response->status = Response::Successful; + return finish(ResponseStatus::Successful); + } else if (responseCode >= 500 && responseCode < 600) { + // Server errors may be temporary, so back off exponentially. + response->status = Response::Error; + response->message = "HTTP status code " + util::toString(responseCode); + return finish(ResponseStatus::TemporaryError); + } else { + // We don't know how to handle any other errors, so declare them as permanently failing. + response->status = Response::Error; + response->message = "HTTP status code " + util::toString(responseCode); + return finish(ResponseStatus::PermanentError); + } + } + + throw std::runtime_error("Response hasn't been handled"); +} + +std::unique_ptr HTTPContextBase::createContext(uv_loop_t* loop) { + return std::make_unique(loop); +} + +} diff --git a/platform/default/image.cpp b/platform/default/image.cpp new file mode 100644 index 000000000..d7dcfc38b --- /dev/null +++ b/platform/default/image.cpp @@ -0,0 +1,105 @@ +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +// Check png library version. +const static bool png_version_check = []() { + const png_uint_32 version = png_access_version_number(); + if (version != PNG_LIBPNG_VER) { + throw std::runtime_error(mbgl::util::sprintf<96>( + "libpng version mismatch: headers report %d.%d.%d, but library reports %d.%d.%d", + PNG_LIBPNG_VER / 10000, (PNG_LIBPNG_VER / 100) % 100, PNG_LIBPNG_VER % 100, + version / 10000, (version / 100) % 100, version % 100)); + } + return true; +}(); + + +namespace mbgl { +namespace util { + +std::string compress_png(int width, int height, const void *rgba) { + png_voidp error_ptr = 0; + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr, NULL, NULL); + if (!png_ptr) { + Log::Error(Event::Image, "couldn't create png_ptr"); + return ""; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!png_ptr) { + png_destroy_write_struct(&png_ptr, (png_infopp)0); + Log::Error(Event::Image, "couldn't create info_ptr"); + return ""; + } + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + jmp_buf *jmp_context = (jmp_buf *)png_get_error_ptr(png_ptr); + if (jmp_context) { + png_destroy_write_struct(&png_ptr, &info_ptr); + return ""; + } + + std::string result; + png_set_write_fn(png_ptr, &result, [](png_structp png_ptr_, png_bytep data, png_size_t length) { + std::string *out = static_cast(png_get_io_ptr(png_ptr_)); + out->append(reinterpret_cast(data), length); + }, NULL); + + struct ptrs { + ptrs(size_t count) : rows(new png_bytep[count]) {} + ~ptrs() { delete[] rows; } + png_bytep *rows = nullptr; + } pointers(height); + + for (int i = 0; i < height; i++) { + pointers.rows[i] = (png_bytep)((png_bytep)rgba + width * 4 * i); + } + + png_set_rows(png_ptr, info_ptr, pointers.rows); + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + png_destroy_write_struct(&png_ptr, &info_ptr); + + return result; +} + +Image::Image(std::string const& data) +{ + try + { + auto reader = getImageReader(data.c_str(), data.size()); + width = reader->width(); + height = reader->height(); + img = std::make_unique(width * height * 4); + reader->read(0, 0, width, height, img.get()); + } + catch (ImageReaderException const& ex) + { + Log::Error(Event::Image, ex.what()); + img.reset(); + width = 0; + height = 0; + + } + catch (...) // catch the rest + { + Log::Error(Event::Image, "exception in constructor"); + img.reset(); + width = 0; + height = 0; + } +} + +} +} diff --git a/platform/default/image_reader.cpp b/platform/default/image_reader.cpp new file mode 100644 index 000000000..e80ccb681 --- /dev/null +++ b/platform/default/image_reader.cpp @@ -0,0 +1,62 @@ +#include +#include +#include + +#include +#include + +namespace mbgl { namespace util { + +inline boost::optional type_from_bytes(char const* data, size_t size) +{ + using result_type = boost::optional; + if (size >= 4) + { + unsigned int magic = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + if (magic == 0x89504E47U) + { + return result_type("png"); + } + else if (magic == 0x49492A00 || magic == 0x4D4D002A) + { + return result_type("tiff"); + } + } + if (size>=2) + { + unsigned int magic = ((data[0] << 8) | data[1]) & 0xffff; + if (magic == 0xffd8) + { + return result_type("jpeg"); + } + } + + if (size>=12) + { + if (data[0] == 'R' && data[1] == 'I' && data[2] == 'F' && data[3] == 'F' && + data[8] == 'W' && data[9] == 'E' && data[10] == 'B' && data[11] == 'P') + { + return result_type("webp"); + } + } + return result_type(); +} + +std::unique_ptr getImageReader(char const* data, size_t size) +{ + boost::optional type = type_from_bytes(data,size); + if (type) + { + if (*type == "png") + { + return std::make_unique>(data, size); + } + else if (*type == "jpeg") + { + return std::make_unique>(data, size); + } + } + throw ImageReaderException("ImageReader: can't determine type from input data"); +} + +}} diff --git a/platform/default/jpeg_reader.cpp b/platform/default/jpeg_reader.cpp new file mode 100644 index 000000000..f89e76687 --- /dev/null +++ b/platform/default/jpeg_reader.cpp @@ -0,0 +1,203 @@ +#include + +// boost +#include +#include + + +// std +#include +#include + +namespace mbgl { namespace util { + +// ctor +template +JpegReader::JpegReader(char const* data, size_t size) + : source_(data, size), + stream_(source_), + width_(0), + height_(0) +{ + if (!stream_) throw ImageReaderException("cannot open image stream"); + init(); +} + +// dtor +template +JpegReader::~JpegReader() {} + +// jpeg stream wrapper +template +void JpegReader::init_source (j_decompress_ptr cinfo) +{ + jpeg_stream_wrapper* wrap = reinterpret_cast(cinfo->src); + wrap->stream->seekg(0,std::ios_base::beg); +} + +template +boolean JpegReader::fill_input_buffer (j_decompress_ptr cinfo) +{ + jpeg_stream_wrapper* wrap = reinterpret_cast(cinfo->src); + wrap->stream->read(reinterpret_cast(&wrap->buffer[0]),BUF_SIZE); + std::streamsize size = wrap->stream->gcount(); + wrap->manager.next_input_byte = wrap->buffer; + wrap->manager.bytes_in_buffer = BUF_SIZE; + return (size > 0) ? TRUE : FALSE; +} + +template +void JpegReader::skip(j_decompress_ptr cinfo, long count) +{ + if (count <= 0) return; //A zero or negative skip count should be treated as a no-op. + jpeg_stream_wrapper* wrap = reinterpret_cast(cinfo->src); + + if (wrap->manager.bytes_in_buffer > 0 && count < static_cast(wrap->manager.bytes_in_buffer)) + { + wrap->manager.bytes_in_buffer -= count; + wrap->manager.next_input_byte = &wrap->buffer[BUF_SIZE - wrap->manager.bytes_in_buffer]; + } + else + { + wrap->stream->seekg(count - wrap->manager.bytes_in_buffer, std::ios_base::cur); + // trigger buffer fill + wrap->manager.next_input_byte = 0; + wrap->manager.bytes_in_buffer = 0; //bytes_in_buffer may be zero on return. + } +} + +template +void JpegReader::term (j_decompress_ptr /*cinfo*/) +{ +// no-op +} + +template +void JpegReader::attach_stream (j_decompress_ptr cinfo, input_stream* in) +{ + if (cinfo->src == 0) + { + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(jpeg_stream_wrapper)); + } + JpegReader::jpeg_stream_wrapper * src = reinterpret_cast (cinfo->src); + src->manager.init_source = init_source; + src->manager.fill_input_buffer = fill_input_buffer; + src->manager.skip_input_data = skip; + src->manager.resync_to_restart = jpeg_resync_to_restart; + src->manager.term_source = term; + src->manager.bytes_in_buffer = 0; + src->manager.next_input_byte = 0; + src->stream = in; +} + +template +void JpegReader::on_error(j_common_ptr /*cinfo*/) +{ +} + +template +void JpegReader::on_error_message(j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message)(cinfo, buffer); + throw ImageReaderException(std::string("JPEG Reader: libjpeg could not read image: ") + buffer); +} + +template +void JpegReader::init() +{ + jpeg_decompress_struct cinfo; + jpeg_info_guard iguard(&cinfo); + jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jerr.error_exit = on_error; + jerr.output_message = on_error_message; + jpeg_create_decompress(&cinfo); + attach_stream(&cinfo, &stream_); + int ret = jpeg_read_header(&cinfo, TRUE); + if (ret != JPEG_HEADER_OK) + throw ImageReaderException("JPEG Reader: failed to read header"); + jpeg_start_decompress(&cinfo); + width_ = cinfo.output_width; + height_ = cinfo.output_height; + + if (cinfo.out_color_space == JCS_UNKNOWN) + { + throw ImageReaderException("JPEG Reader: failed to read unknown color space"); + } + if (cinfo.output_width == 0 || cinfo.output_height == 0) + { + throw ImageReaderException("JPEG Reader: failed to read image size of"); + } +} + +template +unsigned JpegReader::width() const +{ + return width_; +} + +template +unsigned JpegReader::height() const +{ + return height_; +} + +template +void JpegReader::read(unsigned x0, unsigned y0, unsigned w, unsigned h, char* image) +{ + stream_.clear(); + stream_.seekg(0, std::ios_base::beg); + + jpeg_decompress_struct cinfo; + jpeg_info_guard iguard(&cinfo); + jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jerr.error_exit = on_error; + jerr.output_message = on_error_message; + jpeg_create_decompress(&cinfo); + attach_stream(&cinfo, &stream_); + int ret = jpeg_read_header(&cinfo, TRUE); + if (ret != JPEG_HEADER_OK) throw ImageReaderException("JPEG Reader read(): failed to read header"); + jpeg_start_decompress(&cinfo); + JSAMPARRAY buffer; + int row_stride; + unsigned char r,g,b; + row_stride = cinfo.output_width * cinfo.output_components; + buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + w = std::min(w,width_ - x0); + h = std::min(h,height_ - y0); + + const std::unique_ptr out_row(new unsigned int[w]); + unsigned row = 0; + while (cinfo.output_scanline < cinfo.output_height) + { + jpeg_read_scanlines(&cinfo, buffer, 1); + if (row >= y0 && row < y0 + h) + { + for (unsigned int x = 0; x < w; ++x) + { + unsigned col = x + x0; + r = buffer[0][cinfo.output_components * col]; + if (cinfo.output_components > 2) + { + g = buffer[0][cinfo.output_components * col + 1]; + b = buffer[0][cinfo.output_components * col + 2]; + } else { + g = r; + b = r; + } + out_row[x] = (0xff << 24) | (b << 16) | (g << 8) | r; + } + std::copy((char*)out_row.get(), (char*)out_row.get() + w*4, image + (row - y0)*width_*4); + } + ++row; + } + jpeg_finish_decompress(&cinfo); +} + +template class JpegReader; + +}} diff --git a/platform/default/log_stderr.cpp b/platform/default/log_stderr.cpp new file mode 100644 index 000000000..f7ef34184 --- /dev/null +++ b/platform/default/log_stderr.cpp @@ -0,0 +1,11 @@ +#include + +#include + +namespace mbgl { + +void Log::platformRecord(EventSeverity severity, const std::string &msg) { + std::cerr << "[" << severity << "] " << msg << std::endl; +} + +} diff --git a/platform/default/png_reader.cpp b/platform/default/png_reader.cpp new file mode 100644 index 000000000..ede7e52be --- /dev/null +++ b/platform/default/png_reader.cpp @@ -0,0 +1,217 @@ +#include +#include +#include +extern "C" +{ +#include +} + +// boost +#include +#include +#include + +// stl +#include +#include + +namespace mbgl { namespace util { + +void user_error_fn(png_structp /*png_ptr*/, png_const_charp error_msg) +{ + throw ImageReaderException(std::string("failed to read invalid png: '") + error_msg + "'"); +} + +void user_warning_fn(png_structp /*png_ptr*/, png_const_charp warning_msg) +{ + Log::Warning(Event::Image, "ImageReader (PNG): %s", warning_msg); +} + +template +void PngReader::png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + input_stream * fin = reinterpret_cast(png_get_io_ptr(png_ptr)); + fin->read(reinterpret_cast(data), length); + std::streamsize read_count = fin->gcount(); + if (read_count < 0 || static_cast(read_count) != length) + { + png_error(png_ptr, "Read Error"); + } +} + +template +PngReader::PngReader(char const* data, std::size_t size) + : source_(data,size), + stream_(source_), + width_(0), + height_(0), + bit_depth_(0), + color_type_(0), + has_alpha_(false) +{ + + if (!stream_) throw ImageReaderException("PNG reader: cannot open image stream"); + init(); +} + + +template +PngReader::~PngReader() {} + + +template +void PngReader::init() +{ + png_byte header[8]; + std::memset(header,0,8); + stream_.read(reinterpret_cast(header),8); + if ( stream_.gcount() != 8) + { + throw ImageReaderException("PNG reader: Could not read image"); + } + int is_png=!png_sig_cmp(header,0,8); + if (!is_png) + { + throw ImageReaderException("File or stream is not a png"); + } + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING,0,0,0); + + if (!png_ptr) + { + throw ImageReaderException("failed to allocate png_ptr"); + } + + // catch errors in a custom way to avoid the need for setjmp + png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn); + + png_infop info_ptr; + png_struct_guard sguard(&png_ptr,&info_ptr); + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) throw ImageReaderException("failed to create info_ptr"); + + png_set_read_fn(png_ptr, (png_voidp)&stream_, png_read_data); + + png_set_sig_bytes(png_ptr,8); + png_read_info(png_ptr, info_ptr); + + png_uint_32 w, h; + png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth_, &color_type_,0,0,0); + has_alpha_ = (color_type_ & PNG_COLOR_MASK_ALPHA) || png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); + width_=w; + height_=h; +} + +template +unsigned PngReader::width() const +{ + return width_; +} + +template +unsigned PngReader::height() const +{ + return height_; +} + +template +void PngReader::read(unsigned x0, unsigned y0, unsigned w, unsigned h, char * image) +{ + stream_.clear(); + stream_.seekg(0, std::ios_base::beg); + + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING,0,0,0); + + if (!png_ptr) + { + throw ImageReaderException("failed to allocate png_ptr"); + } + + // catch errors in a custom way to avoid the need for setjmp + png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn); + + png_infop info_ptr; + png_struct_guard sguard(&png_ptr,&info_ptr); + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) throw ImageReaderException("failed to create info_ptr"); + + png_set_read_fn(png_ptr, (png_voidp)&stream_, png_read_data); + png_read_info(png_ptr, info_ptr); + + if (color_type_ == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png_ptr); + if (color_type_ == PNG_COLOR_TYPE_GRAY && bit_depth_ < 8) + png_set_expand(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand(png_ptr); + if (bit_depth_ == 16) + png_set_strip_16(png_ptr); + if (color_type_ == PNG_COLOR_TYPE_GRAY || + color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + + // quick hack -- only work in >=libpng 1.2.7 + png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba + + double gamma; + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, 2.2, gamma); + +#ifdef PNG_ALPHA_PREMULTIPLIED + png_set_alpha_mode(png_ptr, PNG_ALPHA_PREMULTIPLIED, PNG_GAMMA_LINEAR); +#endif + + if (x0 == 0 && y0 == 0 && w >= width_ && h >= height_) + { + if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7) + { + png_set_interlace_handling(png_ptr); // FIXME: libpng bug? + // according to docs png_read_image + // "..automatically handles interlacing, + // so you don't need to call png_set_interlace_handling()" + } + png_read_update_info(png_ptr, info_ptr); + // we can read whole image at once + // alloc row pointers + const std::unique_ptr rows(new png_bytep[height_]); + for (unsigned row = 0; row < height_; ++row) + rows[row] = (png_bytep)image + row * width_ * 4 ; + png_read_image(png_ptr, rows.get()); + +#ifndef PNG_ALPHA_PREMULTIPLIED + // Manually premultiply the image if libpng didn't do it for us. + for (unsigned row = 0; row < height_; ++row) { + for (unsigned x = 0; x < width_; x++) { + png_byte* ptr = &(rows[row][x * 4]); + const float a = ptr[3] / 255.0f; + ptr[0] *= a; + ptr[1] *= a; + ptr[2] *= a; + } + } +#endif + } + else + { + png_read_update_info(png_ptr, info_ptr); + w=std::min(w, width_ - x0); + h=std::min(h, height_ - y0); + unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr); + const std::unique_ptr row(new png_byte[rowbytes]); + for (unsigned i = 0; i < height_; ++i) + { + png_read_row(png_ptr,row.get(),0); + if (i >= y0 && i < (y0 + h)) + { + // TODO: premultiply this + std::copy(&row[x0 * 4], &row[x0 * 4] + w * 4, image + i * width_* 4); + } + } + } + png_read_end(png_ptr,0); +} + +template class PngReader; + +}} diff --git a/platform/default/settings_json.cpp b/platform/default/settings_json.cpp new file mode 100644 index 000000000..9b2ae654a --- /dev/null +++ b/platform/default/settings_json.cpp @@ -0,0 +1,36 @@ +#include +#include + +using namespace mbgl; + +Settings_JSON::Settings_JSON() { load(); } + +void Settings_JSON::load() { + std::ifstream file("/tmp/mbgl-native.cfg"); + if (file) { + file >> longitude; + file >> latitude; + file >> zoom; + file >> bearing; + file >> debug; + } +} + +void Settings_JSON::save() { + std::ofstream file("/tmp/mbgl-native.cfg"); + if (file) { + file << longitude << std::endl; + file << latitude << std::endl; + file << zoom << std::endl; + file << bearing << std::endl; + file << debug << std::endl; + } +} + +void Settings_JSON::clear() { + longitude = 0; + latitude = 0; + zoom = 0; + bearing = 0; + debug = false; +} diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp new file mode 100644 index 000000000..ca525cd20 --- /dev/null +++ b/platform/default/sqlite3.cpp @@ -0,0 +1,185 @@ +#include "sqlite3.hpp" +#include + +#include +#include +#include + +// Check sqlite3 library version. +const static bool sqliteVersionCheck = []() { + if (sqlite3_libversion_number() / 1000000 != SQLITE_VERSION_NUMBER / 1000000) { + char message[96]; + snprintf(message, 96, + "sqlite3 libversion mismatch: headers report %d, but library reports %d", + SQLITE_VERSION_NUMBER, sqlite3_libversion_number()); + throw std::runtime_error(message); + } + + return true; +}(); + +namespace mapbox { +namespace sqlite { + +Database::Database(const std::string &filename, int flags) { + const int err = sqlite3_open_v2(filename.c_str(), &db, flags, nullptr); + if (err != SQLITE_OK) { + Exception ex { err, sqlite3_errmsg(db) }; + db = nullptr; + throw ex; + } +} + +Database::Database(Database &&other) + : db(std::move(other.db)) {} + +Database &Database::operator=(Database &&other) { + std::swap(db, other.db); + return *this; +} + +Database::~Database() { + if (db) { + const int err = sqlite3_close(db); + if (err != SQLITE_OK) { + throw Exception { err, sqlite3_errmsg(db) }; + } + } +} + +Database::operator bool() const { + return db != nullptr; +} + +void Database::exec(const std::string &sql) { + assert(db); + char *msg = nullptr; + const int err = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &msg); + if (msg) { + Exception ex { err, msg }; + sqlite3_free(msg); + throw ex; + } else if (err != SQLITE_OK) { + throw Exception { err, sqlite3_errmsg(db) }; + } +} + +Statement Database::prepare(const char *query) { + assert(db); + return std::move(Statement(db, query)); +} + +Statement::Statement(sqlite3 *db, const char *sql) { + const int err = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr); + if (err != SQLITE_OK) { + stmt = nullptr; + throw Exception { err, sqlite3_errmsg(db) }; + } +} + +#define CHECK_SQLITE_OK_STMT(err, stmt) \ + if (err != SQLITE_OK) { \ + throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(stmt)) }; \ + } + +#define CHECK_SQLITE_OK(err) \ + if (err != SQLITE_OK) { \ + throw Exception { err, sqlite3_errstr(err) }; \ + } + +Statement::Statement(Statement &&other) { + *this = std::move(other); +} + +Statement &Statement::operator=(Statement &&other) { + std::swap(stmt, other.stmt); + return *this; +} + +Statement::~Statement() { + if (stmt) { + sqlite3_finalize(stmt); + } +} + +Statement::operator bool() const { + return stmt != nullptr; +} + +#define BIND_3(type, value, stmt) \ + assert(stmt); \ + const int err = sqlite3_bind_##type(stmt, offset, value); \ + CHECK_SQLITE_OK_STMT(err, stmt) + +#define BIND_5(type, value, length, param, stmt) \ + assert(stmt); \ + const int err = sqlite3_bind_##type(stmt, offset, value, length, param); \ + CHECK_SQLITE_OK_STMT(err, stmt) + +template <> void Statement::bind(int offset, int value) { + BIND_3(int, value, stmt) +} + +template <> void Statement::bind(int offset, int64_t value) { + BIND_3(int64, value, stmt) +} + +template <> void Statement::bind(int offset, double value) { + BIND_3(double, value, stmt) +} + +template <> void Statement::bind(int offset, bool value) { + BIND_3(int, value, stmt) +} + +template <> void Statement::bind(int offset, const char *value) { + BIND_5(text, value, -1, nullptr, stmt) +} + +void Statement::bind(int offset, const std::string &value, bool retain) { + BIND_5(blob, value.data(), int(value.size()), retain ? SQLITE_TRANSIENT : SQLITE_STATIC, stmt) +} + +bool Statement::run() { + assert(stmt); + const int err = sqlite3_step(stmt); + if (err == SQLITE_DONE) { + return false; + } else if (err == SQLITE_ROW) { + return true; + } else { + CHECK_SQLITE_OK_STMT(err, stmt) + return false; + } +} + +template <> int Statement::get(int offset) { + assert(stmt); + return sqlite3_column_int(stmt, offset); +} + +template <> int64_t Statement::get(int offset) { + assert(stmt); + return sqlite3_column_int64(stmt, offset); +} + +template <> double Statement::get(int offset) { + assert(stmt); + return sqlite3_column_double(stmt, offset); +} + +template <> std::string Statement::get(int offset) { + assert(stmt); + return { + reinterpret_cast(sqlite3_column_blob(stmt, offset)), + size_t(sqlite3_column_bytes(stmt, offset)) + }; +} + +void Statement::reset() { + assert(stmt); + sqlite3_reset(stmt); +} + +} +} diff --git a/platform/default/sqlite3.hpp b/platform/default/sqlite3.hpp new file mode 100644 index 000000000..3e324f7ce --- /dev/null +++ b/platform/default/sqlite3.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include +#include + +typedef struct sqlite3 sqlite3; +typedef struct sqlite3_stmt sqlite3_stmt; + +namespace mapbox { +namespace sqlite { + +enum OpenFlag : int { + ReadOnly = 0x00000001, + ReadWrite = 0x00000002, + Create = 0x00000004, + NoMutex = 0x00008000, + FullMutex = 0x00010000, + SharedCache = 0x00020000, + PrivateCache = 0x00040000, +}; + +struct Exception : std::runtime_error { + inline Exception(int err, const char *msg) : std::runtime_error(msg), code(err) {} + const int code = 0; +}; + +class Statement; + +class Database { +private: + Database(const Database &) = delete; + Database &operator=(const Database &) = delete; + +public: + Database(const std::string &filename, int flags = 0); + Database(Database &&); + ~Database(); + Database &operator=(Database &&); + + operator bool() const; + + void exec(const std::string &sql); + Statement prepare(const char *query); + +private: + sqlite3 *db = nullptr; +}; + +class Statement { +private: + Statement(const Statement &) = delete; + Statement &operator=(const Statement &) = delete; + +public: + Statement(sqlite3 *db, const char *sql); + Statement(Statement &&); + ~Statement(); + Statement &operator=(Statement &&); + + operator bool() const; + + template void bind(int offset, T value); + void bind(int offset, const std::string &value, bool retain = true); + template T get(int offset); + + bool run(); + void reset(); + +private: + sqlite3_stmt *stmt = nullptr; +}; + +} +} diff --git a/platform/default/sqlite_cache.cpp b/platform/default/sqlite_cache.cpp new file mode 100644 index 000000000..775c2a68a --- /dev/null +++ b/platform/default/sqlite_cache.cpp @@ -0,0 +1,267 @@ +#include "sqlite_cache_impl.hpp" +#include +#include + +#include +#include +#include +#include + +#include "sqlite3.hpp" +#include + +namespace mbgl { + +std::string removeAccessTokenFromURL(const std::string &url) { + const size_t token_start = url.find("access_token="); + // Ensure that token exists, isn't at the front and is preceded by either & or ?. + if (token_start == std::string::npos || token_start == 0 || !(url[token_start - 1] == '&' || url[token_start - 1] == '?')) { + return url; + } + + const size_t token_end = url.find_first_of('&', token_start); + if (token_end == std::string::npos) { + // The token is the last query argument. We slice away the "&access_token=..." part + return url.substr(0, token_start - 1); + } else { + // We slice away the "access_token=...&" part. + return url.substr(0, token_start) + url.substr(token_end + 1); + } +} + +std::string convertMapboxDomainsToProtocol(const std::string &url) { + const size_t protocol_separator = url.find("://"); + if (protocol_separator == std::string::npos) { + return url; + } + + const std::string protocol = url.substr(0, protocol_separator); + if (!(protocol == "http" || protocol == "https")) { + return url; + } + + const size_t domain_begin = protocol_separator + 3; + const size_t path_separator = url.find("/", domain_begin); + if (path_separator == std::string::npos) { + return url; + } + + const std::string domain = url.substr(domain_begin, path_separator - domain_begin); + if (domain.find(".tiles.mapbox.com") != std::string::npos) { + return "mapbox://" + url.substr(path_separator + 1); + } else { + return url; + } +} + +std::string unifyMapboxURLs(const std::string &url) { + return removeAccessTokenFromURL(convertMapboxDomainsToProtocol(url)); +} + + +using namespace mapbox::sqlite; + +SQLiteCache::SQLiteCache(const std::string& path_) + : thread(std::make_unique>(util::ThreadContext{"SQLite Cache", util::ThreadType::Unknown, util::ThreadPriority::Low}, path_)) { +} + +SQLiteCache::~SQLiteCache() = default; + +SQLiteCache::Impl::Impl(const std::string& path_) + : path(path_) { +} + +SQLiteCache::Impl::~Impl() { + // Deleting these SQLite objects may result in exceptions, but we're in a destructor, so we + // can't throw anything. + try { + getStmt.reset(); + putStmt.reset(); + refreshStmt.reset(); + db.reset(); + } catch (mapbox::sqlite::Exception& ex) { + Log::Error(Event::Database, ex.code, ex.what()); + } +} + +void SQLiteCache::Impl::createDatabase() { + db = std::make_unique(path.c_str(), ReadWrite | Create); +} + +void SQLiteCache::Impl::createSchema() { + constexpr const char *const sql = "" + "CREATE TABLE IF NOT EXISTS `http_cache` (" + " `url` TEXT PRIMARY KEY NOT NULL," + " `status` INTEGER NOT NULL," // The response status (Successful or Error). + " `kind` INTEGER NOT NULL," // The kind of file. + " `modified` INTEGER," // Timestamp when the file was last modified. + " `etag` TEXT," + " `expires` INTEGER," // Timestamp when the server says the file expires. + " `data` BLOB," + " `compressed` INTEGER NOT NULL DEFAULT 0" // Whether the data is compressed. + ");" + "CREATE INDEX IF NOT EXISTS `http_cache_kind_idx` ON `http_cache` (`kind`);"; + + try { + db->exec(sql); + schema = true; + } catch (mapbox::sqlite::Exception &ex) { + if (ex.code == SQLITE_NOTADB) { + Log::Warning(Event::Database, "Trashing invalid database"); + db.reset(); + try { + util::deleteFile(path); + } catch (util::IOException& ioEx) { + Log::Error(Event::Database, ex.code, ex.what()); + } + db = std::make_unique(path.c_str(), ReadWrite | Create); + } else { + Log::Error(Event::Database, ex.code, ex.what()); + } + + // Creating the database table + index failed. That means there may already be one, likely + // with different columsn. Drop it and try to create a new one. + db->exec("DROP TABLE IF EXISTS `http_cache`"); + db->exec(sql); + } +} + +std::unique_ptr SQLiteCache::get(const Resource &resource, Callback callback) { + // Can be called from any thread, but most likely from the file source thread. + // Will try to load the URL from the SQLite database and call the callback when done. + // Note that the callback is probably going to invoked from another thread, so the caller + // must make sure that it can run in that thread. + return thread->invokeWithCallback(&Impl::get, callback, resource); +} + +void SQLiteCache::Impl::get(const Resource &resource, Callback callback) { + try { + // This is called in the SQLite event loop. + if (!db) { + createDatabase(); + } + + if (!schema) { + createSchema(); + } + + if (!getStmt) { + // Initialize the statement 0 1 + getStmt = std::make_unique(db->prepare("SELECT `status`, `modified`, " + // 2 3 4 5 1 + "`etag`, `expires`, `data`, `compressed` FROM `http_cache` WHERE `url` = ?")); + } else { + getStmt->reset(); + } + + const std::string unifiedURL = unifyMapboxURLs(resource.url); + getStmt->bind(1, unifiedURL.c_str()); + if (getStmt->run()) { + // There is data. + auto response = std::make_unique(); + response->status = Response::Status(getStmt->get(0)); + response->modified = getStmt->get(1); + response->etag = getStmt->get(2); + response->expires = getStmt->get(3); + response->data = getStmt->get(4); + if (getStmt->get(5)) { // == compressed + response->data = util::decompress(response->data); + } + callback(std::move(response)); + } else { + // There is no data. + callback(nullptr); + } + } catch (mapbox::sqlite::Exception& ex) { + Log::Error(Event::Database, ex.code, ex.what()); + callback(nullptr); + } +} + +void SQLiteCache::put(const Resource &resource, std::shared_ptr response, Hint hint) { + // Can be called from any thread, but most likely from the file source thread. We are either + // storing a new response or updating the currently stored response, potentially setting a new + // expiry date. + if (hint == Hint::Full) { + thread->invoke(&Impl::put, resource, response); + } else if (hint == Hint::Refresh) { + thread->invoke(&Impl::refresh, resource, response->expires); + } +} + +void SQLiteCache::Impl::put(const Resource& resource, std::shared_ptr response) { + try { + if (!db) { + createDatabase(); + } + + if (!schema) { + createSchema(); + } + + if (!putStmt) { + putStmt = std::make_unique(db->prepare("REPLACE INTO `http_cache` (" + // 1 2 3 4 5 6 7 8 + "`url`, `status`, `kind`, `modified`, `etag`, `expires`, `data`, `compressed`" + ") VALUES(?, ?, ?, ?, ?, ?, ?, ?)")); + } else { + putStmt->reset(); + } + + const std::string unifiedURL = unifyMapboxURLs(resource.url); + putStmt->bind(1 /* url */, unifiedURL.c_str()); + putStmt->bind(2 /* status */, int(response->status)); + putStmt->bind(3 /* kind */, int(resource.kind)); + putStmt->bind(4 /* modified */, response->modified); + putStmt->bind(5 /* etag */, response->etag.c_str()); + putStmt->bind(6 /* expires */, response->expires); + + std::string data; + if (resource.kind != Resource::Image) { + // Do not compress images, since they are typically compressed already. + data = util::compress(response->data); + } + + if (!data.empty() && data.size() < response->data.size()) { + // Store the compressed data when it is smaller than the original + // uncompressed data. + putStmt->bind(7 /* data */, data, false); // do not retain the string internally. + putStmt->bind(8 /* compressed */, true); + } else { + putStmt->bind(7 /* data */, response->data, false); // do not retain the string internally. + putStmt->bind(8 /* compressed */, false); + } + + putStmt->run(); + } catch (mapbox::sqlite::Exception& ex) { + Log::Error(Event::Database, ex.code, ex.what()); + } +} + +void SQLiteCache::Impl::refresh(const Resource& resource, int64_t expires) { + try { + if (!db) { + createDatabase(); + } + + if (!schema) { + createSchema(); + } + + if (!refreshStmt) { + refreshStmt = std::make_unique( // 1 2 + db->prepare("UPDATE `http_cache` SET `expires` = ? WHERE `url` = ?")); + } else { + refreshStmt->reset(); + } + + const std::string unifiedURL = unifyMapboxURLs(resource.url); + refreshStmt->bind(1, int64_t(expires)); + refreshStmt->bind(2, unifiedURL.c_str()); + refreshStmt->run(); + } catch (mapbox::sqlite::Exception& ex) { + Log::Error(Event::Database, ex.code, ex.what()); + } +} + +} diff --git a/platform/default/sqlite_cache_impl.hpp b/platform/default/sqlite_cache_impl.hpp new file mode 100644 index 000000000..700771f2e --- /dev/null +++ b/platform/default/sqlite_cache_impl.hpp @@ -0,0 +1,39 @@ +#ifndef MBGL_STORAGE_DEFAULT_SQLITE_CACHE_IMPL +#define MBGL_STORAGE_DEFAULT_SQLITE_CACHE_IMPL + +#include + +namespace mapbox { +namespace sqlite { +class Database; +class Statement; +} +} + +namespace mbgl { + +class SQLiteCache::Impl { +public: + explicit Impl(const std::string &path = ":memory:"); + ~Impl(); + + void get(const Resource&, Callback); + void put(const Resource& resource, std::shared_ptr response); + void refresh(const Resource& resource, int64_t expires); + +private: + void createDatabase(); + void createSchema(); + + const std::string path; + std::unique_ptr<::mapbox::sqlite::Database> db; + std::unique_ptr<::mapbox::sqlite::Statement> getStmt; + std::unique_ptr<::mapbox::sqlite::Statement> putStmt; + std::unique_ptr<::mapbox::sqlite::Statement> refreshStmt; + bool schema = false; +}; + + +} + +#endif diff --git a/platform/default/string_stdlib.cpp b/platform/default/string_stdlib.cpp new file mode 100644 index 000000000..ac4c26234 --- /dev/null +++ b/platform/default/string_stdlib.cpp @@ -0,0 +1,76 @@ +#include +#include +#define NU_WITH_TOUPPER +#define NU_WITH_TOLOWER +#define NU_WITH_UTF8_WRITER +#include +#include + +namespace mbgl { namespace platform { + +std::string uppercase(const std::string& str) +{ + std::stringstream output; + char const *itr = str.c_str(), *nitr = itr; + char const *end = itr + str.length(); + char lo[5] = { 0 }; + + for (; itr < end; itr = nitr) + { + uint32_t code_point = 0; + char const* buf = 0; + + nitr = _nu_toupper(itr, end, nu_utf8_read, &code_point, &buf, 0); + if (buf != 0) + { + do + { + buf = NU_CASEMAP_DECODING_FUNCTION(buf, &code_point); + if (code_point == 0) break; + output.write(lo, nu_utf8_write(code_point, lo) - lo); + } + while (code_point != 0); + } + else + { + output.write(itr, nitr - itr); + } + } + + return output.str(); + +} + +std::string lowercase(const std::string& str) +{ + std::stringstream output; + char const *itr = str.c_str(), *nitr = itr; + char const *end = itr + str.length(); + char lo[5] = { 0 }; + + for (; itr < end; itr = nitr) + { + uint32_t code_point = 0; + char const* buf = 0; + + nitr = _nu_tolower(itr, end, nu_utf8_read, &code_point, &buf, 0); + if (buf != 0) + { + do + { + buf = NU_CASEMAP_DECODING_FUNCTION(buf, &code_point); + if (code_point == 0) break; + output.write(lo, nu_utf8_write(code_point, lo) - lo); + } + while (code_point != 0); + } + else + { + output.write(itr, nitr - itr); + } + } + + return output.str(); +} + +}} diff --git a/platform/default/thread.cpp b/platform/default/thread.cpp new file mode 100644 index 000000000..12d1802c2 --- /dev/null +++ b/platform/default/thread.cpp @@ -0,0 +1,23 @@ +#include + +#include + +#include +#include + +namespace mbgl { +namespace platform { + +void makeThreadLowPriority() { +#ifdef SCHED_IDLE + struct sched_param param; + param.sched_priority = 0; + int status = sched_setscheduler(0, SCHED_IDLE, ¶m); + if (status != 0) { + Log::Warning(Event::General, "Couldn't set thread scheduling policy"); + } +#endif +} + +} // namespace platform +} // namespace mbgl diff --git a/platform/default/uv_zip.c b/platform/default/uv_zip.c new file mode 100644 index 000000000..3019477eb --- /dev/null +++ b/platform/default/uv_zip.c @@ -0,0 +1,228 @@ +#include "uv_zip.h" + +#include +#include +#include + + +void uv__zip_open_error(uv_zip_t *zip, int error) { + assert(zip); + zip->result = -error; + if (zip->message) { + free((char *)zip->message); + zip->message = NULL; + } + const zip_uint64_t size = zip_error_to_str(NULL, 0, error, errno) + 1; + zip->message = malloc(size); + zip_error_to_str((char *)zip->message, size, error, errno); +} + +void uv__zip_store_error(uv_zip_t *zip, const char *message) { + assert(zip); + if (zip->message) { + free((char *)zip->message); + zip->message = NULL; + } + const unsigned long length = strlen(message) + 1; + zip->message = malloc(length); + strncpy((char *)zip->message, message, length); +} + +void uv__zip_error(uv_zip_t *zip) { + assert(zip); + int error; + zip_error_get(zip->archive, &error, NULL); + zip->result = -error; + uv__zip_store_error(zip, zip_strerror(zip->archive)); +} + +void uv__zip_file_error(uv_zip_t *zip) { + assert(zip); + int error; + zip_file_error_get(zip->file, &error, NULL); + zip->result = -error; + uv__zip_store_error(zip, zip_file_strerror(zip->file)); +} + +void uv__zip_work_fdopen(uv_work_t *req) { + uv_zip_t *zip = (uv_zip_t *)req->data; + assert(zip); + assert(!zip->archive); + + // extract the fd + uv_file fd = *(uv_file *)zip->path; + free((uv_file *)zip->path); + zip->path = NULL; + + int error; + zip->archive = zip_fdopen(fd, zip->flags, &error); + if (!zip->archive) { + uv__zip_open_error(zip, error); + } else { + zip->result = 0; + } +} + +void uv__zip_work_stat(uv_work_t *req) { + uv_zip_t *zip = (uv_zip_t *)req->data; + assert(zip); + assert(zip->archive); + if (!zip->stat) { + zip->stat = malloc(sizeof(struct zip_stat)); + zip_stat_init(zip->stat); + } + if (0 != zip_stat(zip->archive, zip->path, zip->flags, zip->stat)) { + uv__zip_error(zip); + } +} + +void uv__zip_work_fopen(uv_work_t *req) { + uv_zip_t *zip = (uv_zip_t *)req->data; + assert(zip); + assert(zip->archive); + zip->file = zip_fopen(zip->archive, zip->path, zip->flags); + if (!zip->file) { + uv__zip_error(zip); + } +} + +void uv__zip_work_fread(uv_work_t *req) { + uv_zip_t *zip = (uv_zip_t *)req->data; + assert(zip); + assert(zip->file); + assert(zip->buf); + zip->result = zip_fread(zip->file, zip->buf->base, zip->buf->len); + if (zip->result < 0) { + uv__zip_file_error(zip); + } +} + +void uv__zip_work_fclose(uv_work_t *req) { + uv_zip_t *zip = (uv_zip_t *)req->data; + assert(zip); + assert(zip->file); + zip->result = zip_fclose(zip->file); + if (zip->result != 0) { + uv__zip_file_error(zip); + } else { + zip->file = NULL; + } +} + +void uv__zip_work_discard(uv_work_t *req) { + uv_zip_t *zip = (uv_zip_t *)req->data; + assert(zip->archive); + zip_discard(zip->archive); + zip->archive = NULL; + zip->result = 0; +} + +void uv__zip_after_work(uv_work_t *req, int status) { + uv_zip_t *zip = (uv_zip_t *)req->data; + assert(zip); + if (zip->cb) { + zip->cb(zip); + } +} + +void uv_zip_init(uv_zip_t *zip) { + assert(zip); + zip->work.data = zip; + zip->message = NULL; + zip->stat = NULL; + uv_zip_cleanup(zip); +} + +void uv_zip_cleanup(uv_zip_t *zip) { + assert(zip); + zip->data = NULL; + zip->flags = 0; + zip->result = 0; + zip->path = NULL; + zip->cb = NULL; + zip->archive = NULL; + zip->file = NULL; + zip->buf = NULL; + + if (zip->message) { + free((char *)zip->message); + zip->message = NULL; + } + + if (zip->stat) { + free(zip->stat); + zip->stat = NULL; + } +} + +int uv_zip_fdopen(uv_loop_t* loop, uv_zip_t *zip, uv_file fd, int flags, uv_zip_cb cb) { + assert(loop); + assert(zip); + assert(fd); + zip->result = 0; + zip->path = malloc(sizeof(uv_file)); + *(uv_file *)zip->path = fd; + zip->flags = flags; + zip->cb = cb; + return uv_queue_work(loop, &zip->work, uv__zip_work_fdopen, uv__zip_after_work); +} + +int uv_zip_stat(uv_loop_t* loop, uv_zip_t *zip, const char *fname, zip_flags_t flags, uv_zip_cb cb) { + assert(loop); + assert(zip); + assert(fname); + assert(strlen(fname)); + assert(zip->archive); + zip->result = 0; + zip->path = fname; + zip->flags = flags; + zip->cb = cb; + return uv_queue_work(loop, &zip->work, uv__zip_work_stat, uv__zip_after_work); +} + +int uv_zip_fopen(uv_loop_t* loop, uv_zip_t *zip, const char *fname, zip_flags_t flags, uv_zip_cb cb) { + assert(loop); + assert(zip); + assert(fname); + assert(strlen(fname)); + assert(zip->archive); + zip->result = 0; + zip->path = fname; + zip->flags = flags; + zip->file = NULL; + zip->cb = cb; + return uv_queue_work(loop, &zip->work, uv__zip_work_fopen, uv__zip_after_work); +} + +int uv_zip_fclose(uv_loop_t* loop, uv_zip_t *zip, struct zip_file *file, uv_zip_cb cb) { + assert(loop); + assert(zip); + assert(file); + assert(zip->archive); + zip->result = 0; + zip->file = file; + zip->cb = cb; + return uv_queue_work(loop, &zip->work, uv__zip_work_fclose, uv__zip_after_work); +} + +int uv_zip_fread(uv_loop_t* loop, uv_zip_t *zip, struct zip_file *file, uv_buf_t *buf, uv_zip_cb cb) { + assert(loop); + assert(zip); + assert(file); + assert(buf); + assert(zip->archive); + zip->result = 0; + zip->file = file; + zip->buf = buf; + zip->cb = cb; + return uv_queue_work(loop, &zip->work, uv__zip_work_fread, uv__zip_after_work); +} + +int uv_zip_discard(uv_loop_t* loop, uv_zip_t *zip, uv_zip_cb cb) { + assert(loop); + assert(zip); + assert(!zip->file); + zip->result = 0; + zip->cb = cb; + return uv_queue_work(loop, &zip->work, uv__zip_work_discard, uv__zip_after_work); +} diff --git a/platform/default/uv_zip.h b/platform/default/uv_zip.h new file mode 100644 index 000000000..869a415f2 --- /dev/null +++ b/platform/default/uv_zip.h @@ -0,0 +1,44 @@ +#ifndef UV_ZIP +#define UV_ZIP + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +typedef struct uv_zip_s uv_zip_t; + +typedef void (*uv_zip_cb)(uv_zip_t* req); + +struct uv_zip_s { + uv_work_t work; + ssize_t result; + const char *message; + struct zip *archive; + struct zip_file *file; + struct zip_stat *stat; + void *data; + zip_flags_t flags; + const char *path; + uv_zip_cb cb; + uv_buf_t *buf; +}; + +void uv_zip_init(uv_zip_t *zip); +void uv_zip_cleanup(uv_zip_t *zip); + +int uv_zip_fdopen(uv_loop_t* loop, uv_zip_t *zip, uv_file fd, int flags, uv_zip_cb cb); +int uv_zip_stat(uv_loop_t* loop, uv_zip_t *zip, const char *fname, zip_flags_t flags, uv_zip_cb cb); +int uv_zip_fopen(uv_loop_t* loop, uv_zip_t *zip, const char *fname, zip_flags_t flags, uv_zip_cb cb); +int uv_zip_fread(uv_loop_t* loop, uv_zip_t *zip, struct zip_file *file, uv_buf_t *buf, uv_zip_cb cb); +int uv_zip_fclose(uv_loop_t* loop, uv_zip_t *zip, struct zip_file *file, uv_zip_cb cb); +int uv_zip_discard(uv_loop_t* loop, uv_zip_t *zip, uv_zip_cb cb); + +#ifdef __cplusplus +} +#endif + +#endif // UV_ZIP diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m new file mode 100644 index 000000000..710ddd3e3 --- /dev/null +++ b/platform/ios/MGLAccountManager.m @@ -0,0 +1,73 @@ +#import "MGLAccountManager_Private.h" +#import "MGLMapboxEvents.h" +#import "NSProcessInfo+MGLAdditions.h" + +@interface MGLAccountManager() + +@property (atomic) BOOL mapboxMetricsEnabledSettingShownInApp; +@property (atomic) NSString *accessToken; + +@end + + +@implementation MGLAccountManager + ++ (void)load { + // Read the initial configuration from Info.plist. The shown-in-app setting + // preempts the Settings bundle check in -[MGLMapboxEvents init] triggered + // by setting the access token. + NSBundle *bundle = [NSBundle mainBundle]; + NSNumber *shownInAppNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; + if (shownInAppNumber) { + [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = [shownInAppNumber boolValue]; + } + NSString *accessToken = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccessToken"]; + if (accessToken.length) { + self.accessToken = accessToken; + } +} + +// Can be called from any thread. +// ++ (instancetype) sharedManager { + if (NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) { + return nil; + } + static dispatch_once_t onceToken; + static MGLAccountManager *_sharedManager; + void (^setupBlock)() = ^{ + dispatch_once(&onceToken, ^{ + _sharedManager = [[self alloc] init]; + }); + }; + if ( ! [[NSThread currentThread] isMainThread]) { + dispatch_sync(dispatch_get_main_queue(), ^{ + setupBlock(); + }); + } + else { + setupBlock(); + } + return _sharedManager; +} + ++ (BOOL) mapboxMetricsEnabledSettingShownInApp { + return [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp; +} + ++ (void) setAccessToken:(NSString *) accessToken { + if ( ! [accessToken length]) return; + + [MGLAccountManager sharedManager].accessToken = accessToken; + + // Update MGLMapboxEvents + // NOTE: This is (likely) the initial setup of MGLMapboxEvents + [MGLMapboxEvents sharedManager]; +} + ++ (NSString *) accessToken { + return [MGLAccountManager sharedManager].accessToken; +} + + +@end \ No newline at end of file diff --git a/platform/ios/MGLAccountManager_Private.h b/platform/ios/MGLAccountManager_Private.h new file mode 100644 index 000000000..3cc05b09f --- /dev/null +++ b/platform/ios/MGLAccountManager_Private.h @@ -0,0 +1,10 @@ +#import "MGLAccountManager.h" + +@interface MGLAccountManager (Private) + +/** Returns the shared instance of the `MGLAccountManager` class. */ ++ (instancetype)sharedManager; + +@property (atomic) NSString *accessToken; + +@end diff --git a/platform/ios/MGLAnnotationImage.m b/platform/ios/MGLAnnotationImage.m new file mode 100644 index 000000000..e5052bc03 --- /dev/null +++ b/platform/ios/MGLAnnotationImage.m @@ -0,0 +1,30 @@ +#import "MGLAnnotationImage.h" + +@interface MGLAnnotationImage () + +@property (nonatomic) UIImage *image; +@property (nonatomic) NSString *reuseIdentifier; + +@end + +@implementation MGLAnnotationImage + ++ (instancetype)annotationImageWithImage:(UIImage *)image reuseIdentifier:(NSString *)reuseIdentifier +{ + return [[self alloc] initWithImage:image reuseIdentifier:reuseIdentifier]; +} + +- (instancetype)initWithImage:(UIImage *)image reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super init]; + + if (self) + { + _image = image; + _reuseIdentifier = [reuseIdentifier copy]; + } + + return self; +} + +@end diff --git a/platform/ios/MGLFileCache.h b/platform/ios/MGLFileCache.h new file mode 100644 index 000000000..082cec69a --- /dev/null +++ b/platform/ios/MGLFileCache.h @@ -0,0 +1,14 @@ +#import "MGLTypes.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLFileCache : NSObject + ++ (mbgl::SQLiteCache *)obtainSharedCacheWithObject:(NSObject *)object; ++ (void)releaseSharedCacheForObject:(NSObject *)object; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/ios/MGLFileCache.mm b/platform/ios/MGLFileCache.mm new file mode 100644 index 000000000..3303b395f --- /dev/null +++ b/platform/ios/MGLFileCache.mm @@ -0,0 +1,83 @@ +#import "MGLFileCache.h" + +@interface MGLFileCache () + +@property (nonatomic) MGLFileCache *sharedInstance; +@property (nonatomic) mbgl::SQLiteCache *sharedCache; +@property (nonatomic) NSHashTable *retainers; + +@end + +@implementation MGLFileCache + +const std::string &defaultCacheDatabasePath() { + static const std::string path = []() -> std::string { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + if ([paths count] == 0) { + // Disable the cache if we don't have a location to write. + return ""; + } + + NSString *libraryDirectory = [paths objectAtIndex:0]; + return [[libraryDirectory stringByAppendingPathComponent:@"cache.db"] UTF8String]; + }(); + return path; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _retainers = [NSHashTable weakObjectsHashTable]; + } + return self; +} + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static MGLFileCache *_sharedInstance; + dispatch_once(&onceToken, ^{ + _sharedInstance = [[self alloc] init]; + }); + return _sharedInstance; +} + +- (void)teardown { + if (self.sharedCache) { + delete self.sharedCache; + self.sharedCache = nullptr; + } +} + +- (void)dealloc { + [self.retainers removeAllObjects]; + [self teardown]; +} + ++ (mbgl::SQLiteCache *)obtainSharedCacheWithObject:(NSObject *)object { + return [[MGLFileCache sharedInstance] obtainSharedCacheWithObject:object]; +} + +- (mbgl::SQLiteCache *)obtainSharedCacheWithObject:(NSObject *)object { + assert([[NSThread currentThread] isMainThread]); + if (!self.sharedCache) { + self.sharedCache = new mbgl::SQLiteCache(defaultCacheDatabasePath()); + } + [self.retainers addObject:object]; + return self.sharedCache; +} + ++ (void)releaseSharedCacheForObject:(NSObject *)object { + return [[MGLFileCache sharedInstance] releaseSharedCacheForObject:object]; +} + +- (void)releaseSharedCacheForObject:(NSObject *)object { + assert([[NSThread currentThread] isMainThread]); + if ([self.retainers containsObject:object]) { + [self.retainers removeObject:object]; + } + if ([self.retainers count] == 0) { + [self teardown]; + } +} + +@end diff --git a/platform/ios/MGLGeometry.m b/platform/ios/MGLGeometry.m new file mode 100644 index 000000000..9eab5565f --- /dev/null +++ b/platform/ios/MGLGeometry.m @@ -0,0 +1,3 @@ +#import "MGLGeometry.h" + +const MGLCoordinateSpan MGLCoordinateSpanZero = {0, 0}; diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm new file mode 100644 index 000000000..391763b94 --- /dev/null +++ b/platform/ios/MGLMapView.mm @@ -0,0 +1,3061 @@ +#import "MGLMapView.h" +#import "MGLMapView+IBAdditions.h" + +#import +#import + +#import +#import + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#import "Mapbox.h" + +#import "NSBundle+MGLAdditions.h" +#import "NSString+MGLAdditions.h" +#import "NSProcessInfo+MGLAdditions.h" +#import "NSException+MGLAdditions.h" +#import "MGLUserLocationAnnotationView.h" +#import "MGLUserLocation_Private.h" +#import "MGLFileCache.h" +#import "MGLAccountManager_Private.h" +#import "MGLMapboxEvents.h" + +#import "SMCalloutView.h" + +#import +#import + +class MBGLView; + +NSString *const MGLDefaultStyleName = @"mapbox-streets"; +NSString *const MGLStyleVersion = @"7"; +NSString *const MGLDefaultStyleMarkerSymbolName = @"default_marker"; +NSString *const MGLMapboxSetupDocumentationURLDisplayString = @"mapbox.com/guides/first-steps-gl-ios"; + +const NSTimeInterval MGLAnimationDuration = 0.3; +const CGSize MGLAnnotationUpdateViewportOutset = {150, 150}; +const CGFloat MGLMinimumZoom = 3; + +NSString *const MGLAnnotationIDKey = @"MGLAnnotationIDKey"; +NSString *const MGLAnnotationSymbolKey = @"MGLAnnotationSymbolKey"; + +static NSURL *MGLURLForBundledStyleNamed(NSString *styleName) +{ + return [NSURL URLWithString:[NSString stringWithFormat:@"asset://styles/%@.json", styleName]]; +} + +CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees) +{ + return degrees * M_PI / 180; +} + +CLLocationDegrees MGLDegreesFromRadians(CGFloat radians) +{ + return radians * 180 / M_PI; +} + +#pragma mark - Private - + +@interface MGLMapView () + +@property (nonatomic) EAGLContext *context; +@property (nonatomic) GLKView *glView; +@property (nonatomic) UIImageView *glSnapshotView; +@property (nonatomic) NSOperationQueue *regionChangeDelegateQueue; +@property (nonatomic, readwrite) UIImageView *compassView; +@property (nonatomic, readwrite) UIImageView *logoView; +@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *logoViewConstraints; +@property (nonatomic, readwrite) UIButton *attributionButton; +@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints; +@property (nonatomic) UIActionSheet *attributionSheet; +@property (nonatomic) UIPanGestureRecognizer *pan; +@property (nonatomic) UIPinchGestureRecognizer *pinch; +@property (nonatomic) UIRotationGestureRecognizer *rotate; +@property (nonatomic) UILongPressGestureRecognizer *quickZoom; +@property (nonatomic) NSMapTable *annotationIDsByAnnotation; +@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLAnnotationImage *) *annotationImages; +@property (nonatomic) std::vector annotationsNearbyLastTap; +@property (nonatomic, weak) id selectedAnnotation; +@property (nonatomic) SMCalloutView *selectedAnnotationCalloutView; +@property (nonatomic) MGLUserLocationAnnotationView *userLocationAnnotationView; +@property (nonatomic) CLLocationManager *locationManager; +@property (nonatomic) CGPoint centerPoint; +@property (nonatomic) CGFloat scale; +@property (nonatomic) CGFloat angle; +@property (nonatomic) CGFloat quickZoomStart; +@property (nonatomic, getter=isDormant) BOOL dormant; +@property (nonatomic, getter=isAnimatingGesture) BOOL animatingGesture; +@property (nonatomic, readonly, getter=isRotationAllowed) BOOL rotationAllowed; + +@end + +@implementation MGLMapView +{ + mbgl::Map *_mbglMap; + MBGLView *_mbglView; + mbgl::DefaultFileSource *_mbglFileSource; + BOOL _isWaitingForRedundantReachableNotification; + + NS_MUTABLE_ARRAY_OF(NSURL *) *_bundledStyleURLs; + + BOOL _isTargetingInterfaceBuilder; + CLLocationDegrees _pendingLatitude; + CLLocationDegrees _pendingLongitude; +} + +#pragma mark - Setup & Teardown - + +@dynamic debugActive; + +std::chrono::steady_clock::duration secondsAsDuration(float duration) +{ + return std::chrono::duration_cast(std::chrono::duration(duration)); +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) + { + [self commonInit]; + self.styleURL = nil; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame styleURL:(nullable NSURL *)styleURL +{ + if (self = [super initWithFrame:frame]) + { + [self commonInit]; + self.styleURL = styleURL; + } + return self; +} + +- (instancetype)initWithCoder:(nonnull NSCoder *)decoder +{ + if (self = [super initWithCoder:decoder]) + { + [self commonInit]; + self.styleURL = nil; + } + return self; +} + +- (nullable NSString *)accessToken +{ + [NSException raise:@"Method unavailable" format: + @"%s has been removed. " + @"Use +[MGLAccountManager accessToken] or get MGLMapboxAccessToken from the Info.plist.", + __PRETTY_FUNCTION__]; + return nil; +} + +- (void)setAccessToken:(nullable NSString *)accessToken +{ + [NSException raise:@"Method unavailable" format: + @"%s has been replaced by +[MGLAccountManager setAccessToken:].\n\n" + @"If you previously set this access token in a storyboard inspectable, select the MGLMapView in Interface Builder and delete the “accessToken” entry from the User Defined Runtime Attributes section of the Identity inspector. " + @"Then go to the Info.plist file and set MGLMapboxAccessToken to “%@”.", + __PRETTY_FUNCTION__, accessToken]; +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleURL +{ + return [NSSet setWithObject:@"styleID"]; +} + +- (nonnull NSURL *)styleURL +{ + NSString *styleURLString = @(_mbglMap->getStyleURL().c_str()).mgl_stringOrNilIfEmpty; + NSAssert(styleURLString || _isTargetingInterfaceBuilder, @"Invalid style URL string %@", styleURLString); + return styleURLString ? [NSURL URLWithString:styleURLString] : nil; +} + +- (void)setStyleURL:(nullable NSURL *)styleURL +{ + if (_isTargetingInterfaceBuilder) return; + + if ( ! styleURL) + { + styleURL = MGLURLForBundledStyleNamed([NSString stringWithFormat:@"%@-v%@", + MGLDefaultStyleName.lowercaseString, + MGLStyleVersion]); + } + + if ( ! [styleURL scheme]) + { + // Assume a relative path into the developer’s bundle. + styleURL = [[NSBundle mainBundle] URLForResource:styleURL.path withExtension:nil]; + } + + _mbglMap->setStyleURL([[styleURL absoluteString] UTF8String]); +} + +- (void)commonInit +{ + _isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent; + + BOOL background = [UIApplication sharedApplication].applicationState == UIApplicationStateBackground; + if (!background) + { + [self createGLView]; + } + + self.accessibilityLabel = @"Map"; + self.backgroundColor = [UIColor clearColor]; + self.clipsToBounds = YES; + + // setup mbgl map + // + const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; + _mbglView = new MBGLView(self, scaleFactor); + _mbglFileSource = new mbgl::DefaultFileSource([MGLFileCache obtainSharedCacheWithObject:self]); + + // Start paused + _mbglMap = new mbgl::Map(*_mbglView, *_mbglFileSource, mbgl::MapMode::Continuous); + if (_isTargetingInterfaceBuilder || background) { + self.dormant = YES; + _mbglMap->pause(); + } + + // Observe for changes to the global access token (and find out the current one). + [[MGLAccountManager sharedManager] addObserver:self + forKeyPath:@"accessToken" + options:(NSKeyValueObservingOptionInitial | + NSKeyValueObservingOptionNew) + context:NULL]; + + // Notify map object when network reachability status changes. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(reachabilityChanged:) + name:kMGLReachabilityChangedNotification + object:nil]; + + MGLReachability* reachability = [MGLReachability reachabilityForInternetConnection]; + if ([reachability isReachable]) + { + _isWaitingForRedundantReachableNotification = YES; + } + [reachability startNotifier]; + + // setup annotations + // + _annotationIDsByAnnotation = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableStrongMemory]; + + _annotationImages = [NSMutableDictionary dictionary]; + + std::string defaultSymbolName([MGLDefaultStyleMarkerSymbolName UTF8String]); + _mbglMap->setDefaultPointAnnotationSymbol(defaultSymbolName); + + // setup logo bug + // + UIImage *logo = [[MGLMapView resourceImageNamed:@"mapbox.png"] imageWithAlignmentRectInsets:UIEdgeInsetsMake(1.5, 4, 3.5, 2)]; + _logoView = [[UIImageView alloc] initWithImage:logo]; + _logoView.accessibilityLabel = @"Mapbox logo"; + _logoView.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:_logoView]; + _logoViewConstraints = [NSMutableArray array]; + + // setup attribution + // + _attributionButton = [UIButton buttonWithType:UIButtonTypeInfoLight]; + _attributionButton.accessibilityLabel = @"Attribution info"; + [_attributionButton addTarget:self action:@selector(showAttribution) forControlEvents:UIControlEventTouchUpInside]; + _attributionButton.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:_attributionButton]; + _attributionButtonConstraints = [NSMutableArray array]; + + _attributionSheet = [[UIActionSheet alloc] initWithTitle:@"Mapbox for iOS" + delegate:self + cancelButtonTitle:@"Cancel" + destructiveButtonTitle:nil + otherButtonTitles: + @"© Mapbox", + @"© OpenStreetMap", + @"Improve This Map", + nil]; + + // iOS 8+: add action that opens app's Settings.app panel, if applicable + if (&UIApplicationOpenSettingsURLString != NULL && ! [MGLAccountManager mapboxMetricsEnabledSettingShownInApp]) + { + [_attributionSheet addButtonWithTitle:@"Adjust Privacy Settings"]; + } + + // setup compass + // + _compassView = [[UIImageView alloc] initWithImage:[MGLMapView resourceImageNamed:@"Compass.png"]]; + _compassView.accessibilityLabel = @"Compass"; + _compassView.frame = CGRectMake(0, 0, _compassView.image.size.width, _compassView.image.size.height); + _compassView.alpha = 0; + UIView *container = [[UIView alloc] initWithFrame:CGRectZero]; + [container addSubview:_compassView]; + container.translatesAutoresizingMaskIntoConstraints = NO; + [container addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleCompassTapGesture:)]]; + [self addSubview:container]; + + // setup interaction + // + _pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; + _pan.delegate = self; + _pan.maximumNumberOfTouches = 1; + [self addGestureRecognizer:_pan]; + _scrollEnabled = YES; + + _pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)]; + _pinch.delegate = self; + [self addGestureRecognizer:_pinch]; + _zoomEnabled = YES; + + _rotate = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotateGesture:)]; + _rotate.delegate = self; + [self addGestureRecognizer:_rotate]; + _rotateEnabled = YES; + + UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTapGesture:)]; + doubleTap.numberOfTapsRequired = 2; + [self addGestureRecognizer:doubleTap]; + + UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapGesture:)]; + [singleTap requireGestureRecognizerToFail:doubleTap]; + [self addGestureRecognizer:singleTap]; + + UITapGestureRecognizer *twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTapGesture:)]; + twoFingerTap.numberOfTouchesRequired = 2; + [twoFingerTap requireGestureRecognizerToFail:_pinch]; + [twoFingerTap requireGestureRecognizerToFail:_rotate]; + [self addGestureRecognizer:twoFingerTap]; + + if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) + { + _quickZoom = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleQuickZoomGesture:)]; + _quickZoom.numberOfTapsRequired = 1; + _quickZoom.minimumPressDuration = 0.25; + [self addGestureRecognizer:_quickZoom]; + } + + // observe app activity + // + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willTerminate) name:UIApplicationWillTerminateNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sleepGL:) name:UIApplicationWillResignActiveNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sleepGL:) name:UIApplicationDidEnterBackgroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wakeGL:) name:UIApplicationWillEnterForegroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wakeGL:) name:UIApplicationDidBecomeActiveNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; + + // set initial position + // + _mbglMap->setLatLngZoom(mbgl::LatLng(0, 0), _mbglMap->getMinZoom()); + _pendingLatitude = NAN; + _pendingLongitude = NAN; + + // setup change delegate queue + // + _regionChangeDelegateQueue = [NSOperationQueue new]; + _regionChangeDelegateQueue.maxConcurrentOperationCount = 1; + + // metrics: map load event + const mbgl::LatLng latLng = _mbglMap->getLatLng(); + const double zoom = _mbglMap->getZoom(); + + [MGLMapboxEvents pushEvent:MGLEventTypeMapLoad withAttributes:@{ + MGLEventKeyLatitude: @(latLng.latitude), + MGLEventKeyLongitude: @(latLng.longitude), + MGLEventKeyZoomLevel: @(zoom), + MGLEventKeyPushEnabled: @([MGLMapboxEvents checkPushEnabled]) + }]; +} + +- (void)createGLView +{ + if (_context) return; + + // create context + // + _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + NSAssert(_context, @"Failed to create OpenGL ES context."); + + // create GL view + // + _glView = [[GLKView alloc] initWithFrame:self.bounds context:_context]; + _glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _glView.enableSetNeedsDisplay = YES; + _glView.drawableStencilFormat = GLKViewDrawableStencilFormat8; + _glView.drawableDepthFormat = GLKViewDrawableDepthFormat16; + _glView.contentScaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; + _glView.delegate = self; + [_glView bindDrawable]; + [self insertSubview:_glView atIndex:0]; + + _glView.contentMode = UIViewContentModeCenter; + + // load extensions + // + mbgl::gl::InitializeExtensions([](const char * name) { + static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles")); + if (!framework) { + throw std::runtime_error("Failed to load OpenGL framework."); + } + + CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); + void* symbol = CFBundleGetFunctionPointerForName(framework, str); + CFRelease(str); + + return reinterpret_cast(symbol); + }); +} + +- (void)reachabilityChanged:(NSNotification *)notification +{ + MGLReachability *reachability = [notification object]; + if ( ! _isWaitingForRedundantReachableNotification && [reachability isReachable]) + { + mbgl::NetworkStatus::Reachable(); + } + _isWaitingForRedundantReachableNotification = NO; +} + +- (void)dealloc +{ + [_regionChangeDelegateQueue cancelAllOperations]; + + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"]; + + if (_mbglMap) + { + delete _mbglMap; + _mbglMap = nullptr; + } + + if (_mbglFileSource) + { + delete _mbglFileSource; + _mbglFileSource = nullptr; + } + + [MGLFileCache releaseSharedCacheForObject:self]; + + if (_mbglView) + { + delete _mbglView; + _mbglView = nullptr; + } + + if ([[EAGLContext currentContext] isEqual:_context]) + { + [EAGLContext setCurrentContext:nil]; + } + + [self.logoViewConstraints removeAllObjects]; + self.logoViewConstraints = nil; + [self.attributionButtonConstraints removeAllObjects]; + self.attributionButtonConstraints = nil; +} + +- (void)setDelegate:(nullable id)delegate +{ + if (_delegate == delegate) return; + + _delegate = delegate; + + if ([delegate respondsToSelector:@selector(mapView:symbolNameForAnnotation:)]) + { + [NSException raise:@"Method unavailable" format: + @"-mapView:symbolNameForAnnotation: has been removed from the MGLMapViewDelegate protocol, but %@ still implements it. " + @"Implement -[%@ mapView:imageForAnnotation:] instead.", + NSStringFromClass([delegate class]), NSStringFromClass([delegate class])]; + } +} + +#pragma mark - Layout - + +- (void)setFrame:(CGRect)frame +{ + [super setFrame:frame]; + + [self setNeedsLayout]; +} + +- (void)setBounds:(CGRect)bounds +{ + [super setBounds:bounds]; + + [self setNeedsLayout]; +} + ++ (BOOL)requiresConstraintBasedLayout +{ + return YES; +} + +- (UIViewController *)viewControllerForLayoutGuides +{ + // Per -[UIResponder nextResponder] documentation, a UIView’s next responder + // is its managing UIViewController if applicable, or otherwise its + // superview. UIWindow’s next responder is UIApplication, which has no next + // responder. + UIResponder *laterResponder = self; + while ([laterResponder isKindOfClass:[UIView class]]) + { + laterResponder = laterResponder.nextResponder; + } + if ([laterResponder isKindOfClass:[UIViewController class]]) + { + return (UIViewController *)laterResponder; + } + return nil; +} + +- (void)updateConstraints +{ + // If we have a view controller reference, use its layout guides for our various top & bottom + // views so they don't underlap navigation or tool bars. If we don't have a reference, apply + // constraints against ourself to maintain (albeit less ideal) placement of the subviews. + // + UIViewController *viewController = self.viewControllerForLayoutGuides; + UIView *constraintParentView = (viewController.view ? viewController.view : self); + + // compass + // + UIView *compassContainer = self.compassView.superview; + if ([NSLayoutConstraint respondsToSelector:@selector(deactivateConstraints:)]) + { + [NSLayoutConstraint deactivateConstraints:compassContainer.constraints]; + } + else + { + [compassContainer removeConstraints:compassContainer.constraints]; + } + + NSMutableArray *compassContainerConstraints = [NSMutableArray array]; + if (viewController) + { + [compassContainerConstraints addObject: + [NSLayoutConstraint constraintWithItem:compassContainer + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:viewController.topLayoutGuide + attribute:NSLayoutAttributeBottom + multiplier:1 + constant:5]]; + } + [compassContainerConstraints addObject: + [NSLayoutConstraint constraintWithItem:compassContainer + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self + attribute:NSLayoutAttributeTop + multiplier:1 + constant:5]]; + + [compassContainerConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:compassContainer + attribute:NSLayoutAttributeTrailing + multiplier:1 + constant:5]]; + + [compassContainer addConstraint: + [NSLayoutConstraint constraintWithItem:compassContainer + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:self.compassView.image.size.width]]; + + [compassContainer addConstraint: + [NSLayoutConstraint constraintWithItem:compassContainer + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:self.compassView.image.size.height]]; + if ([NSLayoutConstraint respondsToSelector:@selector(activateConstraints:)]) + { + [NSLayoutConstraint activateConstraints:compassContainerConstraints]; + } + else + { + [constraintParentView addConstraints:compassContainerConstraints]; + } + + // logo bug + // + if ([NSLayoutConstraint respondsToSelector:@selector(deactivateConstraints:)]) + { + [NSLayoutConstraint deactivateConstraints:self.logoViewConstraints]; + } + else + { + [self.logoView removeConstraints:self.logoViewConstraints]; + } + [self.logoViewConstraints removeAllObjects]; + if (viewController) + { + [self.logoViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:viewController.bottomLayoutGuide + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.logoView + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8]]; + } + [self.logoViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.logoView + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8]]; + + [self.logoViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:self.logoView + attribute:NSLayoutAttributeLeading + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeLeading + multiplier:1 + constant:8]]; + if ([NSLayoutConstraint respondsToSelector:@selector(activateConstraints:)]) + { + [NSLayoutConstraint activateConstraints:self.logoViewConstraints]; + } + else + { + [constraintParentView addConstraints:self.logoViewConstraints]; + } + + // attribution button + // + if ([NSLayoutConstraint respondsToSelector:@selector(deactivateConstraints:)]) + { + [NSLayoutConstraint deactivateConstraints:self.attributionButtonConstraints]; + } + else + { + [self.attributionButton removeConstraints:self.attributionButtonConstraints]; + } + [self.attributionButtonConstraints removeAllObjects]; + if (viewController) + { + [self.attributionButtonConstraints addObject: + [NSLayoutConstraint constraintWithItem:viewController.bottomLayoutGuide + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8]]; + } + [self.attributionButtonConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8]]; + + [self.attributionButtonConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeTrailing + multiplier:1 + constant:8]]; + if ([NSLayoutConstraint respondsToSelector:@selector(activateConstraints:)]) + { + [NSLayoutConstraint activateConstraints:self.attributionButtonConstraints]; + } + else + { + [constraintParentView addConstraints:self.attributionButtonConstraints]; + } + + [super updateConstraints]; +} + +// This is the delegate of the GLKView object's display call. +- (void)glkView:(__unused GLKView *)view drawInRect:(__unused CGRect)rect +{ + if ( ! self.isDormant) + { + CGFloat zoomFactor = _mbglMap->getMaxZoom() - _mbglMap->getMinZoom() + 1; + CGFloat cpuFactor = (CGFloat)[[NSProcessInfo processInfo] processorCount]; + CGFloat memoryFactor = (CGFloat)[[NSProcessInfo processInfo] physicalMemory] / 1000 / 1000 / 1000; + CGFloat sizeFactor = ((CGFloat)_mbglMap->getWidth() / mbgl::util::tileSize) * + ((CGFloat)_mbglMap->getHeight() / mbgl::util::tileSize); + + NSUInteger cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5; + + _mbglMap->setSourceTileCacheSize(cacheSize); + + _mbglMap->renderSync(); + + [self updateUserLocationAnnotationView]; + + _mbglMap->nudgeTransitions(); + } +} + +// This gets called when the view dimension changes, e.g. because the device is being rotated. +- (void)layoutSubviews +{ + [super layoutSubviews]; + + if ( ! _isTargetingInterfaceBuilder) + { + _mbglMap->update(mbgl::Update::Dimensions); + } + + if (self.attributionSheet.visible) + { + [self.attributionSheet dismissWithClickedButtonIndex:self.attributionSheet.cancelButtonIndex animated:YES]; + } + + if (self.compassView.alpha) + { + [self updateHeadingForDeviceOrientation]; + [self updateCompass]; + [self updateUserLocationAnnotationView]; + } +} + +#pragma mark - Life Cycle - + +- (void)willTerminate +{ + MGLAssertIsMainThread(); + + if ( ! self.isDormant) + { + self.dormant = YES; + _mbglMap->pause(); + [self.glView deleteDrawable]; + } +} + +- (void)sleepGL:(__unused NSNotification *)notification +{ + MGLAssertIsMainThread(); + + if ( ! self.isDormant) + { + self.dormant = YES; + + [MGLMapboxEvents flush]; + + if ( ! self.glSnapshotView) + { + self.glSnapshotView = [[UIImageView alloc] initWithFrame:self.glView.frame]; + self.glSnapshotView.autoresizingMask = self.glView.autoresizingMask; + [self insertSubview:self.glSnapshotView aboveSubview:self.glView]; + } + + self.glSnapshotView.image = self.glView.snapshot; + self.glSnapshotView.hidden = NO; + + if (_mbglMap->getDebug() && [self.glSnapshotView.subviews count] == 0) + { + UIView *snapshotTint = [[UIView alloc] initWithFrame:self.glSnapshotView.bounds]; + snapshotTint.autoresizingMask = self.glSnapshotView.autoresizingMask; + snapshotTint.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.25]; + [self.glSnapshotView addSubview:snapshotTint]; + } + + _mbglMap->pause(); + + [self.glView deleteDrawable]; + } +} + +- (void)wakeGL:(__unused NSNotification *)notification +{ + MGLAssertIsMainThread(); + + if (self.isDormant && [UIApplication sharedApplication].applicationState != UIApplicationStateBackground) + { + self.dormant = NO; + + [self createGLView]; + [MGLMapboxEvents validate]; + + self.glSnapshotView.hidden = YES; + + [self.glSnapshotView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; + + [self.glView bindDrawable]; + + _mbglMap->resume(); + } +} + +- (void)tintColorDidChange +{ + for (UIView *subview in self.subviews) [self updateTintColorForView:subview]; +} + +- (void)updateTintColorForView:(UIView *)view +{ + if ([view respondsToSelector:@selector(setTintColor:)]) view.tintColor = self.tintColor; + + for (UIView *subview in view.subviews) [self updateTintColorForView:subview]; +} + +#pragma mark - Gestures - + +- (void)handleCompassTapGesture:(__unused id)sender +{ + [self resetNorthAnimated:YES]; + + if (self.userTrackingMode == MGLUserTrackingModeFollowWithHeading || + self.userTrackingMode == MGLUserTrackingModeFollowWithCourse) + { + self.userTrackingMode = MGLUserTrackingModeFollow; + } +} + +- (void)touchesBegan:(__unused NS_SET_OF(UITouch *) *)touches withEvent:(__unused UIEvent *)event +{ + _mbglMap->cancelTransitions(); + _mbglMap->setGestureInProgress(false); + self.animatingGesture = NO; +} + +- (void)handlePanGesture:(UIPanGestureRecognizer *)pan +{ + if ( ! self.isScrollEnabled) return; + + _mbglMap->cancelTransitions(); + + if (pan.state == UIGestureRecognizerStateBegan) + { + [self trackGestureEvent:MGLEventGesturePanStart forRecognizer:pan]; + + _mbglMap->setGestureInProgress(true); + + self.centerPoint = CGPointMake(0, 0); + + self.userTrackingMode = MGLUserTrackingModeNone; + } + else if (pan.state == UIGestureRecognizerStateChanged) + { + CGPoint delta = CGPointMake([pan translationInView:pan.view].x - self.centerPoint.x, + [pan translationInView:pan.view].y - self.centerPoint.y); + + _mbglMap->moveBy(delta.x, delta.y); + + self.centerPoint = CGPointMake(self.centerPoint.x + delta.x, self.centerPoint.y + delta.y); + + [self notifyMapChange:mbgl::MapChangeRegionDidChangeAnimated]; + } + else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) + { + CGPoint velocity = [pan velocityInView:pan.view]; + if (sqrtf(velocity.x * velocity.x + velocity.y * velocity.y) < 100) + { + // Not enough velocity to overcome friction + velocity = CGPointZero; + } + + CGFloat duration = UIScrollViewDecelerationRateNormal; + if ( ! CGPointEqualToPoint(velocity, CGPointZero)) + { + CGPoint offset = CGPointMake(velocity.x * duration / 4, velocity.y * duration / 4); + _mbglMap->moveBy(offset.x, offset.y, secondsAsDuration(duration)); + } + + _mbglMap->setGestureInProgress(false); + + if ( ! CGPointEqualToPoint(velocity, CGPointZero)) + { + self.animatingGesture = YES; + + __weak MGLMapView *weakSelf = self; + + [self animateWithDelay:duration animations:^ + { + weakSelf.animatingGesture = NO; + + [weakSelf notifyMapChange:mbgl::MapChangeRegionDidChangeAnimated]; + }]; + } + else + { + [self notifyMapChange:mbgl::MapChangeRegionDidChange]; + } + + // metrics: pan end + CGPoint pointInView = CGPointMake([pan locationInView:pan.view].x, [pan locationInView:pan.view].y); + CLLocationCoordinate2D panCoordinate = [self convertPoint:pointInView toCoordinateFromView:pan.view]; + double zoom = [self zoomLevel]; + + [MGLMapboxEvents pushEvent:MGLEventTypeMapDragEnd withAttributes:@{ + MGLEventKeyLatitude: @(panCoordinate.latitude), + MGLEventKeyLongitude: @(panCoordinate.longitude), + MGLEventKeyZoomLevel: @(zoom) + }]; + } +} + +- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch +{ + if ( ! self.isZoomEnabled) return; + + if (_mbglMap->getZoom() <= _mbglMap->getMinZoom() && pinch.scale < 1) return; + + _mbglMap->cancelTransitions(); + + if (pinch.state == UIGestureRecognizerStateBegan) + { + [self trackGestureEvent:MGLEventGesturePinchStart forRecognizer:pinch]; + + _mbglMap->setGestureInProgress(true); + + self.scale = _mbglMap->getScale(); + + self.userTrackingMode = MGLUserTrackingModeNone; + } + else if (pinch.state == UIGestureRecognizerStateChanged) + { + CGFloat newScale = self.scale * pinch.scale; + + if (log2(newScale) < _mbglMap->getMinZoom()) return; + + _mbglMap->setScale(newScale, [pinch locationInView:pinch.view].x, [pinch locationInView:pinch.view].y); + } + else if (pinch.state == UIGestureRecognizerStateEnded || pinch.state == UIGestureRecognizerStateCancelled) + { + CGFloat velocity = pinch.velocity; + if (isnan(velocity)) + { + // UIPinchGestureRecognizer sometimes returns NaN for the velocity + velocity = 0; + } + if (velocity > -0.5 && velocity < 3) + { + velocity = 0; + } + CGFloat duration = velocity > 0 ? 1 : 0.25; + + CGFloat scale = self.scale * pinch.scale; + CGFloat newScale = scale; + if (velocity >= 0) + { + newScale += scale * velocity * duration * 0.1; + } + else + { + newScale += scale / (velocity * duration) * 0.1; + } + + if (newScale <= 0 || log2(newScale) < _mbglMap->getMinZoom()) + { + velocity = 0; + } + + if (velocity) + { + CGPoint pinchCenter = [pinch locationInView:pinch.view]; + _mbglMap->setScale(newScale, pinchCenter.x, pinchCenter.y, secondsAsDuration(duration)); + } + + _mbglMap->setGestureInProgress(false); + + [self unrotateIfNeededAnimated:YES]; + + if (velocity) + { + self.animatingGesture = YES; + + __weak MGLMapView *weakSelf = self; + + [self animateWithDelay:duration animations:^ + { + weakSelf.animatingGesture = NO; + + [weakSelf notifyMapChange:mbgl::MapChangeRegionDidChangeAnimated]; + }]; + } + else + { + [self notifyMapChange:mbgl::MapChangeRegionDidChange]; + } + } +} + +- (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate +{ + if ( ! self.isRotateEnabled) return; + + _mbglMap->cancelTransitions(); + + if (rotate.state == UIGestureRecognizerStateBegan) + { + [self trackGestureEvent:MGLEventGestureRotateStart forRecognizer:rotate]; + + _mbglMap->setGestureInProgress(true); + + self.angle = MGLRadiansFromDegrees(_mbglMap->getBearing()) * -1; + + self.userTrackingMode = MGLUserTrackingModeNone; + } + else if (rotate.state == UIGestureRecognizerStateChanged) + { + CGFloat newDegrees = MGLDegreesFromRadians(self.angle + rotate.rotation) * -1; + + // constrain to +/-30 degrees when merely rotating like Apple does + // + if ( ! self.isRotationAllowed && std::abs(self.pinch.scale) < 10) + { + newDegrees = fminf(newDegrees, 30); + newDegrees = fmaxf(newDegrees, -30); + } + + _mbglMap->setBearing(newDegrees, + [rotate locationInView:rotate.view].x, + [rotate locationInView:rotate.view].y); + } + else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled) + { + CGFloat velocity = rotate.velocity; + + if (fabs(velocity) > 3) + { + CGFloat radians = self.angle + rotate.rotation; + CGFloat duration = UIScrollViewDecelerationRateNormal; + CGFloat newRadians = radians + velocity * duration * 0.1; + CGFloat newDegrees = MGLDegreesFromRadians(newRadians) * -1; + + _mbglMap->setBearing(newDegrees, secondsAsDuration(duration)); + + _mbglMap->setGestureInProgress(false); + + self.animatingGesture = YES; + + __weak MGLMapView *weakSelf = self; + + [self animateWithDelay:duration animations:^ + { + weakSelf.animatingGesture = NO; + + [weakSelf unrotateIfNeededAnimated:YES]; + + [weakSelf notifyMapChange:mbgl::MapChangeRegionDidChangeAnimated]; + }]; + } + else + { + _mbglMap->setGestureInProgress(false); + + [self unrotateIfNeededAnimated:YES]; + + [self notifyMapChange:mbgl::MapChangeRegionDidChange]; + } + } +} + +- (void)handleSingleTapGesture:(UITapGestureRecognizer *)singleTap +{ + if (singleTap.state == UIGestureRecognizerStateEnded) + { + [self trackGestureEvent:MGLEventGestureSingleTap forRecognizer:singleTap]; + + CGPoint tapPoint = [singleTap locationInView:self]; + + if (self.userLocationVisible && ! [self.selectedAnnotation isEqual:self.userLocation]) + { + CGRect userLocationRect = CGRectMake(tapPoint.x - 15, tapPoint.y - 15, 30, 30); + + if (CGRectContainsPoint(userLocationRect, [self convertCoordinate:self.userLocation.coordinate toPointToView:self])) + { + [self selectAnnotation:self.userLocation animated:YES]; + return; + } + } + + // tolerances based on touch size & typical marker aspect ratio + CGFloat toleranceWidth = 40; + CGFloat toleranceHeight = 60; + + // setup a recognition area weighted 2/3 of the way above the point to account for average marker imagery + CGRect tapRect = CGRectMake(tapPoint.x - toleranceWidth / 2, tapPoint.y - 2 * toleranceHeight / 3, toleranceWidth, toleranceHeight); + CGPoint tapRectLowerLeft = CGPointMake(tapRect.origin.x, tapRect.origin.y + tapRect.size.height); + CGPoint tapRectUpperLeft = CGPointMake(tapRect.origin.x, tapRect.origin.y); + CGPoint tapRectUpperRight = CGPointMake(tapRect.origin.x + tapRect.size.width, tapRect.origin.y); + CGPoint tapRectLowerRight = CGPointMake(tapRect.origin.x + tapRect.size.width, tapRect.origin.y + tapRect.size.height); + + // figure out what that means in coordinate space + CLLocationCoordinate2D coordinate; + mbgl::LatLngBounds tapBounds; + + coordinate = [self convertPoint:tapRectLowerLeft toCoordinateFromView:self]; + tapBounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate)); + + coordinate = [self convertPoint:tapRectUpperLeft toCoordinateFromView:self]; + tapBounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate)); + + coordinate = [self convertPoint:tapRectUpperRight toCoordinateFromView:self]; + tapBounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate)); + + coordinate = [self convertPoint:tapRectLowerRight toCoordinateFromView:self]; + tapBounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate)); + + // query for nearby annotations + std::vector nearbyAnnotations = _mbglMap->getAnnotationsInBounds(tapBounds, mbgl::AnnotationType::Point); + + int32_t newSelectedAnnotationID = -1; + + if (nearbyAnnotations.size()) + { + // there is at least one nearby annotation; select one + // + // first, sort for comparison and iteration + std::sort(nearbyAnnotations.begin(), nearbyAnnotations.end()); + + if (nearbyAnnotations == self.annotationsNearbyLastTap) + { + // the selection candidates haven't changed; cycle through them + if (self.selectedAnnotation && + [[[self.annotationIDsByAnnotation objectForKey:self.selectedAnnotation] + objectForKey:MGLAnnotationIDKey] unsignedIntValue] == self.annotationsNearbyLastTap.back()) + { + // the selected annotation is the last in the set; cycle back to the first + // note: this could be the selected annotation if only one in set + newSelectedAnnotationID = self.annotationsNearbyLastTap.front(); + } + else if (self.selectedAnnotation) + { + // otherwise increment the selection through the candidates + uint32_t currentID = [[[self.annotationIDsByAnnotation objectForKey:self.selectedAnnotation] objectForKey:MGLAnnotationIDKey] unsignedIntValue]; + auto result = std::find(self.annotationsNearbyLastTap.begin(), self.annotationsNearbyLastTap.end(), currentID); + auto distance = std::distance(self.annotationsNearbyLastTap.begin(), result); + newSelectedAnnotationID = self.annotationsNearbyLastTap[distance + 1]; + } + else + { + // no current selection; select the first one + newSelectedAnnotationID = self.annotationsNearbyLastTap.front(); + } + } + else + { + // start tracking a new set of nearby annotations + self.annotationsNearbyLastTap = nearbyAnnotations; + + // select the first one + newSelectedAnnotationID = self.annotationsNearbyLastTap.front(); + } + } + else + { + // there are no nearby annotations; deselect if necessary + newSelectedAnnotationID = -1; + } + + if (newSelectedAnnotationID >= 0) + { + // find & select model object for selection + NSEnumerator *enumerator = self.annotationIDsByAnnotation.keyEnumerator; + + while (id annotation = enumerator.nextObject) + { + if ([[[self.annotationIDsByAnnotation objectForKey:annotation] objectForKey:MGLAnnotationIDKey] integerValue] == newSelectedAnnotationID) + { + // only change selection status if not the currently selected annotation + if ( ! [annotation isEqual:self.selectedAnnotation]) + { + [self selectAnnotation:annotation animated:YES]; + } + + // either way, we should stop enumerating + break; + } + } + } + else + { + // deselect any selected annotation + if (self.selectedAnnotation) [self deselectAnnotation:self.selectedAnnotation animated:YES]; + } + } +} + +- (void)handleDoubleTapGesture:(UITapGestureRecognizer *)doubleTap +{ + if ( ! self.isZoomEnabled) return; + + _mbglMap->cancelTransitions(); + + if (doubleTap.state == UIGestureRecognizerStateBegan) + { + [self trackGestureEvent:MGLEventGestureDoubleTap forRecognizer:doubleTap]; + } + else if (doubleTap.state == UIGestureRecognizerStateEnded) + { + CGPoint doubleTapPoint = [doubleTap locationInView:doubleTap.view]; + + CGPoint zoomInPoint = doubleTapPoint; + CGPoint userPoint = [self convertCoordinate:self.userLocation.coordinate toPointToView:self]; + if (self.userTrackingMode != MGLUserTrackingModeNone) + { + CGRect userLocationRect = CGRectMake(userPoint.x - 40, userPoint.y - 40, 80, 80); + if (CGRectContainsPoint(userLocationRect, doubleTapPoint)) + { + zoomInPoint = userPoint; + } + } + if ( ! CGPointEqualToPoint(zoomInPoint, userPoint)) + { + self.userTrackingMode = MGLUserTrackingModeNone; + } + + _mbglMap->scaleBy(2, zoomInPoint.x, zoomInPoint.y, secondsAsDuration(MGLAnimationDuration)); + + self.animatingGesture = YES; + + __weak MGLMapView *weakSelf = self; + + [self animateWithDelay:MGLAnimationDuration animations:^ + { + weakSelf.animatingGesture = NO; + + [weakSelf unrotateIfNeededAnimated:YES]; + + [weakSelf notifyMapChange:mbgl::MapChangeRegionDidChangeAnimated]; + }]; + } +} + +- (void)handleTwoFingerTapGesture:(UITapGestureRecognizer *)twoFingerTap +{ + if ( ! self.isZoomEnabled) return; + + if (_mbglMap->getZoom() == _mbglMap->getMinZoom()) return; + + _mbglMap->cancelTransitions(); + + if (twoFingerTap.state == UIGestureRecognizerStateBegan) + { + [self trackGestureEvent:MGLEventGestureTwoFingerSingleTap forRecognizer:twoFingerTap]; + } + else if (twoFingerTap.state == UIGestureRecognizerStateEnded) + { + CGPoint zoomOutPoint; + + if (self.userTrackingMode != MGLUserTrackingModeNone) + { + zoomOutPoint = self.center; + } + else + { + self.userTrackingMode = MGLUserTrackingModeNone; + + zoomOutPoint = CGPointMake([twoFingerTap locationInView:twoFingerTap.view].x, [twoFingerTap locationInView:twoFingerTap.view].y); + } + + _mbglMap->scaleBy(0.5, zoomOutPoint.x, zoomOutPoint.y, secondsAsDuration(MGLAnimationDuration)); + + self.animatingGesture = YES; + + __weak MGLMapView *weakSelf = self; + + [self animateWithDelay:MGLAnimationDuration animations:^ + { + weakSelf.animatingGesture = NO; + + [weakSelf unrotateIfNeededAnimated:YES]; + + [weakSelf notifyMapChange:mbgl::MapChangeRegionDidChangeAnimated]; + }]; + } +} + +- (void)handleQuickZoomGesture:(UILongPressGestureRecognizer *)quickZoom +{ + if ( ! self.isZoomEnabled) return; + + _mbglMap->cancelTransitions(); + + if (quickZoom.state == UIGestureRecognizerStateBegan) + { + [self trackGestureEvent:MGLEventGestureQuickZoom forRecognizer:quickZoom]; + + self.scale = _mbglMap->getScale(); + + self.quickZoomStart = [quickZoom locationInView:quickZoom.view].y; + + self.userTrackingMode = MGLUserTrackingModeNone; + } + else if (quickZoom.state == UIGestureRecognizerStateChanged) + { + CGFloat distance = self.quickZoomStart - [quickZoom locationInView:quickZoom.view].y; + + CGFloat newZoom = log2f(self.scale) + (distance / 100); + + if (newZoom < _mbglMap->getMinZoom()) return; + + _mbglMap->scaleBy(powf(2, newZoom) / _mbglMap->getScale(), self.bounds.size.width / 2, self.bounds.size.height / 2); + } + else if (quickZoom.state == UIGestureRecognizerStateEnded || quickZoom.state == UIGestureRecognizerStateCancelled) + { + [self unrotateIfNeededAnimated:YES]; + + [self notifyMapChange:mbgl::MapChangeRegionDidChange]; + } +} + +- (void)handleCalloutAccessoryTapGesture:(UITapGestureRecognizer *)tap +{ + if ([self.delegate respondsToSelector:@selector(mapView:annotation:calloutAccessoryControlTapped:)]) + { + NSAssert([tap.view isKindOfClass:[UIControl class]], @"Tapped view %@ is not a UIControl", tap.view); + [self.delegate mapView:self annotation:self.selectedAnnotation + calloutAccessoryControlTapped:(UIControl *)tap.view]; + } +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer +{ + NSArray *validSimultaneousGestures = @[ self.pan, self.pinch, self.rotate ]; + + return ([validSimultaneousGestures containsObject:gestureRecognizer] && [validSimultaneousGestures containsObject:otherGestureRecognizer]); +} + +- (void)trackGestureEvent:(NSString *)gestureID forRecognizer:(UIGestureRecognizer *)recognizer +{ + CGPoint pointInView = CGPointMake([recognizer locationInView:recognizer.view].x, [recognizer locationInView:recognizer.view].y); + CLLocationCoordinate2D gestureCoordinate = [self convertPoint:pointInView toCoordinateFromView:recognizer.view]; + double zoom = [self zoomLevel]; + + [MGLMapboxEvents pushEvent:MGLEventTypeMapTap withAttributes:@{ + MGLEventKeyLatitude: @(gestureCoordinate.latitude), + MGLEventKeyLongitude: @(gestureCoordinate.longitude), + MGLEventKeyZoomLevel: @(zoom), + MGLEventKeyGestureID: gestureID + }]; +} + +#pragma mark - Attribution - + +- (void)showAttribution +{ + [self.attributionSheet showFromRect:self.attributionButton.frame inView:self animated:YES]; +} + +- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex +{ + if (buttonIndex == actionSheet.firstOtherButtonIndex) + { + [[UIApplication sharedApplication] openURL: + [NSURL URLWithString:@"https://www.mapbox.com/about/maps/"]]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 1) + { + [[UIApplication sharedApplication] openURL: + [NSURL URLWithString:@"http://www.openstreetmap.org/about/"]]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 2) + { + NSString *feedbackURL = [NSString stringWithFormat:@"https://www.mapbox.com/map-feedback/#/%.5f/%.5f/%i", + self.longitude, self.latitude, (int)round(self.zoomLevel)]; + [[UIApplication sharedApplication] openURL: + [NSURL URLWithString:feedbackURL]]; + } + // skips to 4 because button is conditionally added after cancel (index 3) + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 4) + { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; + } +} + +#pragma mark - Properties - + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(__unused void *)context +{ + // Synchronize mbgl::Map’s access token with the global one in MGLAccountManager. + if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) + { + NSString *accessToken = change[NSKeyValueChangeNewKey]; + if (![accessToken isKindOfClass:[NSNull class]]) { + _mbglFileSource->setAccessToken((std::string)[accessToken UTF8String]); + } + } +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomEnabled +{ + return [NSSet setWithObject:@"allowsZooming"]; +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingScrollEnabled +{ + return [NSSet setWithObject:@"allowsScrolling"]; +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingRotateEnabled +{ + return [NSSet setWithObject:@"allowsRotating"]; +} + +- (void)setDebugActive:(BOOL)debugActive +{ + _mbglMap->setDebug(debugActive); + _mbglMap->setCollisionDebug(debugActive); +} + +- (BOOL)isDebugActive +{ + return (_mbglMap->getDebug() || _mbglMap->getCollisionDebug()); +} + +- (void)resetNorth +{ + [self resetNorthAnimated:YES]; +} + +- (void)resetNorthAnimated:(BOOL)animated +{ + CGFloat duration = (animated ? MGLAnimationDuration : 0); + + _mbglMap->setBearing(0, secondsAsDuration(duration)); +} + +- (void)resetPosition +{ + _mbglMap->resetPosition(); + + [self notifyMapChange:mbgl::MapChangeRegionDidChange]; +} + +- (void)toggleDebug +{ + _mbglMap->toggleDebug(); + _mbglMap->toggleCollisionDebug(); +} + +- (void)emptyMemoryCache +{ + _mbglMap->onLowMemory(); +} + +#pragma mark - Geography - + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCenterCoordinate +{ + return [NSSet setWithObjects:@"latitude", @"longitude", nil]; +} + +- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated preservingTracking:(BOOL)tracking +{ + self.userTrackingMode = (tracking ? self.userTrackingMode : MGLUserTrackingModeNone); + + [self setCenterCoordinate:coordinate animated:animated]; +} + +- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated +{ + CGFloat duration = (animated ? MGLAnimationDuration : 0); + + _mbglMap->setLatLngZoom(MGLLatLngFromLocationCoordinate2D(coordinate), + fmaxf(_mbglMap->getZoom(), self.currentMinimumZoom), + secondsAsDuration(duration)); + + [self notifyMapChange:(animated ? mbgl::MapChangeRegionDidChangeAnimated : mbgl::MapChangeRegionDidChange)]; +} + +- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate +{ + [self setCenterCoordinate:centerCoordinate animated:NO]; +} + +- (CLLocationCoordinate2D)centerCoordinate +{ + return MGLLocationCoordinate2DFromLatLng(_mbglMap->getLatLng()); +} + +- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel animated:(BOOL)animated +{ + self.userTrackingMode = MGLUserTrackingModeNone; + + CGFloat duration = (animated ? MGLAnimationDuration : 0); + + _mbglMap->setLatLngZoom(MGLLatLngFromLocationCoordinate2D(centerCoordinate), zoomLevel, secondsAsDuration(duration)); + + [self unrotateIfNeededAnimated:animated]; + + [self notifyMapChange:(animated ? mbgl::MapChangeRegionDidChangeAnimated : mbgl::MapChangeRegionDidChange)]; +} + +- (double)zoomLevel +{ + return _mbglMap->getZoom(); +} + +- (void)setZoomLevel:(double)zoomLevel animated:(BOOL)animated +{ + self.userTrackingMode = MGLUserTrackingModeNone; + + CGFloat duration = (animated ? MGLAnimationDuration : 0); + + _mbglMap->setLatLngZoom(_mbglMap->getLatLng(), + fmaxf(zoomLevel, self.currentMinimumZoom), + secondsAsDuration(duration)); + + [self unrotateIfNeededAnimated:animated]; + + [self notifyMapChange:(animated ? mbgl::MapChangeRegionDidChangeAnimated : mbgl::MapChangeRegionDidChange)]; +} + +- (void)setZoomLevel:(double)zoomLevel +{ + [self setZoomLevel:zoomLevel animated:NO]; +} + +MGLCoordinateBounds MGLCoordinateBoundsFromLatLngBounds(mbgl::LatLngBounds latLngBounds) +{ + return MGLCoordinateBoundsMake(MGLLocationCoordinate2DFromLatLng(latLngBounds.sw), + MGLLocationCoordinate2DFromLatLng(latLngBounds.ne)); +} + +mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBounds coordinateBounds) +{ + return mbgl::LatLngBounds(MGLLatLngFromLocationCoordinate2D(coordinateBounds.sw), MGLLatLngFromLocationCoordinate2D(coordinateBounds.ne)); +} + +- (MGLCoordinateBounds)visibleCoordinateBounds +{ + return MGLCoordinateBoundsFromLatLngBounds(self.viewportBounds); +} + +- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds +{ + [self setVisibleCoordinateBounds:bounds animated:NO]; +} + +- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds animated:(BOOL)animated +{ + [self setVisibleCoordinateBounds:bounds edgePadding:UIEdgeInsetsZero animated:animated]; +} + +- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated +{ + CLLocationCoordinate2D coordinates[] = { + {bounds.ne.latitude, bounds.sw.longitude}, + bounds.sw, + {bounds.sw.latitude, bounds.ne.longitude}, + bounds.ne, + }; + [self setVisibleCoordinates:coordinates + count:sizeof(coordinates) / sizeof(coordinates[0]) + edgePadding:insets + animated:animated]; +} + +- (void)setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated +{ + // NOTE: does not disrupt tracking mode + CGFloat duration = animated ? MGLAnimationDuration : 0; + + [self willChangeValueForKey:@"visibleCoordinateBounds"]; + mbgl::EdgeInsets mbglInsets = {insets.top, insets.left, insets.bottom, insets.right}; + mbgl::AnnotationSegment segment; + segment.reserve(count); + for (NSUInteger i = 0; i < count; i++) + { + segment.push_back({coordinates[i].latitude, coordinates[i].longitude}); + } + _mbglMap->fitBounds(segment, mbglInsets, secondsAsDuration(duration)); + [self didChangeValueForKey:@"visibleCoordinateBounds"]; + + [self unrotateIfNeededAnimated:animated]; + + [self notifyMapChange:(animated ? mbgl::MapChangeRegionDidChangeAnimated : mbgl::MapChangeRegionDidChange)]; +} + +- (CLLocationDirection)direction +{ + return mbgl::util::wrap(_mbglMap->getBearing(), 0., 360.); +} + +- (void)setDirection:(CLLocationDirection)direction animated:(BOOL)animated +{ + if ( ! animated && ! self.rotationAllowed) return; + + self.userTrackingMode = MGLUserTrackingModeNone; + + CGFloat duration = (animated ? MGLAnimationDuration : 0); + + _mbglMap->setBearing(direction, secondsAsDuration(duration)); + + [self notifyMapChange:(animated ? mbgl::MapChangeRegionDidChangeAnimated : mbgl::MapChangeRegionDidChange)]; +} + +- (void)setDirection:(CLLocationDirection)direction +{ + [self setDirection:direction animated:NO]; +} + +- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(nullable UIView *)view +{ + CGPoint convertedPoint = [self convertPoint:point fromView:view]; + + // flip y coordinate for iOS view origin top left + // + convertedPoint.y = self.bounds.size.height - convertedPoint.y; + + return MGLLocationCoordinate2DFromLatLng(_mbglMap->latLngForPixel(mbgl::vec2(convertedPoint.x, convertedPoint.y))); +} + +- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(nullable UIView *)view +{ + mbgl::vec2 pixel = _mbglMap->pixelForLatLng(MGLLatLngFromLocationCoordinate2D(coordinate)); + + // flip y coordinate for iOS view origin in top left + // + pixel.y = self.bounds.size.height - pixel.y; + + return [self convertPoint:CGPointMake(pixel.x, pixel.y) toView:view]; +} + +- (CLLocationDistance)metersPerPixelAtLatitude:(CLLocationDegrees)latitude +{ + return _mbglMap->getMetersPerPixelAtLatitude(latitude, self.zoomLevel); +} + +mbgl::LatLng MGLLatLngFromLocationCoordinate2D(CLLocationCoordinate2D coordinate) +{ + return mbgl::LatLng(coordinate.latitude, coordinate.longitude); +} + +CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng) +{ + return CLLocationCoordinate2DMake(latLng.latitude, latLng.longitude); +} + +- (mbgl::LatLngBounds)viewportBounds +{ + mbgl::LatLngBounds bounds; + + bounds.extend(MGLLatLngFromLocationCoordinate2D( + [self convertPoint:CGPointMake(0, 0) toCoordinateFromView:self])); + bounds.extend(MGLLatLngFromLocationCoordinate2D( + [self convertPoint:CGPointMake(self.bounds.size.width, 0) toCoordinateFromView:self])); + bounds.extend(MGLLatLngFromLocationCoordinate2D( + [self convertPoint:CGPointMake(0, self.bounds.size.height) toCoordinateFromView:self])); + bounds.extend(MGLLatLngFromLocationCoordinate2D( + [self convertPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height) toCoordinateFromView:self])); + + return bounds; +} + +#pragma mark - Styling - + +- (NS_ARRAY_OF(NSURL *) *)bundledStyleURLs +{ + if ( ! _bundledStyleURLs) + { + NSString *stylesPath = [[NSBundle mgl_resourceBundlePath] stringByAppendingPathComponent:@"styles"]; + + _bundledStyleURLs = [NSMutableArray array]; + + NSArray *bundledStyleNamesWithExtensions = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:stylesPath error:nil]; + for (NSString *fileName in bundledStyleNamesWithExtensions) + { + [_bundledStyleURLs addObject:MGLURLForBundledStyleNamed([fileName stringByDeletingPathExtension])]; + } + } + + return [NSArray arrayWithArray:_bundledStyleURLs]; +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleID +{ + return [NSSet setWithObject:@"styleURL"]; +} + +- (nullable NSString *)styleID +{ + NSURL *styleURL = self.styleURL; + return [styleURL.scheme isEqualToString:@"mapbox"] ? styleURL.host.mgl_stringOrNilIfEmpty : nil; +} + +- (void)setStyleID:(nullable NSString *)styleID +{ + self.styleURL = styleID ? [NSURL URLWithString:[NSString stringWithFormat:@"mapbox://%@", styleID]] : nil; +} + +- (nullable NSString *)mapID +{ + [NSException raise:@"Method unavailable" format: + @"%s has been renamed -[MGLMapView styleID].", + __PRETTY_FUNCTION__]; + return nil; +} + +- (void)setMapID:(nullable NSString *)mapID +{ + [NSException raise:@"Method unavailable" format: + @"%s has been renamed -[MGLMapView setStyleID:].\n\n" + @"If you previously set this map ID in a storyboard inspectable, select the MGLMapView in Interface Builder and delete the “mapID” entry from the User Defined Runtime Attributes section of the Identity inspector. " + @"Then go to the Attributes inspector and enter “%@” into the “Style ID” field.", + __PRETTY_FUNCTION__, mapID]; +} + +- (NS_ARRAY_OF(NSString *) *)styleClasses +{ + NSMutableArray *returnArray = [NSMutableArray array]; + + const std::vector &appliedClasses = _mbglMap->getClasses(); + + for (auto class_it = appliedClasses.begin(); class_it != appliedClasses.end(); class_it++) + { + [returnArray addObject:@(class_it->c_str())]; + } + + return returnArray; +} + +- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses +{ + [self setStyleClasses:appliedClasses transitionDuration:0]; +} + +- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration +{ + std::vector newAppliedClasses; + + for (NSString *appliedClass in appliedClasses) + { + newAppliedClasses.insert(newAppliedClasses.end(), [appliedClass UTF8String]); + } + + _mbglMap->setDefaultTransitionDuration(secondsAsDuration(transitionDuration)); + _mbglMap->setClasses(newAppliedClasses); +} + +- (BOOL)hasStyleClass:(NSString *)styleClass +{ + return styleClass && _mbglMap->hasClass([styleClass UTF8String]); +} + +- (void)addStyleClass:(NSString *)styleClass +{ + if (styleClass) + { + _mbglMap->addClass([styleClass UTF8String]); + } +} + +- (void)removeStyleClass:(NSString *)styleClass +{ + if (styleClass) + { + _mbglMap->removeClass([styleClass UTF8String]); + } +} + +#pragma mark - Annotations - + +- (nullable NS_ARRAY_OF(id ) *)annotations +{ + if ([_annotationIDsByAnnotation count]) + { + NSMutableArray *result = [NSMutableArray array]; + + NSEnumerator *keyEnumerator = [_annotationIDsByAnnotation keyEnumerator]; + id annotation; + + while (annotation = [keyEnumerator nextObject]) + { + [result addObject:annotation]; + } + + return [NSArray arrayWithArray:result]; + } + + return nil; +} + +- (void)addAnnotation:(id )annotation +{ + if ( ! annotation) return; + + // The core bulk add API is efficient with respect to indexing and + // screen refreshes, thus we should defer to it even for individual adds. + // + [self addAnnotations:@[ annotation ]]; +} + +- (void)addAnnotations:(NS_ARRAY_OF(id ) *)annotations +{ + if ( ! annotations) return; + + std::vector points; + std::vector shapes; + + BOOL delegateImplementsImageForPoint = [self.delegate respondsToSelector:@selector(mapView:imageForAnnotation:)]; + BOOL delegateImplementsAlphaForShape = [self.delegate respondsToSelector:@selector(mapView:alphaForShapeAnnotation:)]; + BOOL delegateImplementsStrokeColorForShape = [self.delegate respondsToSelector:@selector(mapView:strokeColorForShapeAnnotation:)]; + BOOL delegateImplementsFillColorForPolygon = [self.delegate respondsToSelector:@selector(mapView:fillColorForPolygonAnnotation:)]; + BOOL delegateImplementsLineWidthForPolyline = [self.delegate respondsToSelector:@selector(mapView:lineWidthForPolylineAnnotation:)]; + + const std::string spritePrefix = "com.mapbox.sprites."; + + for (id annotation in annotations) + { + assert([annotation conformsToProtocol:@protocol(MGLAnnotation)]); + + if ([annotation isKindOfClass:[MGLMultiPoint class]]) + { + NSUInteger count = [(MGLMultiPoint *)annotation pointCount]; + + if (count == 0) break; + + CGFloat alpha = (delegateImplementsAlphaForShape ? + [self.delegate mapView:self alphaForShapeAnnotation:annotation] : + 1.0); + + UIColor *strokeColor = (delegateImplementsStrokeColorForShape ? + [self.delegate mapView:self strokeColorForShapeAnnotation:annotation] : + [UIColor blackColor]); + + assert(strokeColor); + + CGFloat r,g,b,a; + [strokeColor getRed:&r green:&g blue:&b alpha:&a]; + mbgl::Color strokeNativeColor({{ (float)r, (float)g, (float)b, (float)a }}); + + mbgl::StyleProperties shapeProperties; + + if ([annotation isKindOfClass:[MGLPolyline class]]) + { + CGFloat lineWidth = (delegateImplementsLineWidthForPolyline ? + [self.delegate mapView:self lineWidthForPolylineAnnotation:(MGLPolyline *)annotation] : + 3.0); + + mbgl::LineProperties lineProperties; + lineProperties.opacity = alpha; + lineProperties.color = strokeNativeColor; + lineProperties.width = lineWidth; + shapeProperties.set(lineProperties); + + } + else if ([annotation isKindOfClass:[MGLPolygon class]]) + { + UIColor *fillColor = (delegateImplementsFillColorForPolygon ? + [self.delegate mapView:self fillColorForPolygonAnnotation:(MGLPolygon *)annotation] : + [UIColor blueColor]); + + assert(fillColor); + + [fillColor getRed:&r green:&g blue:&b alpha:&a]; + mbgl::Color fillNativeColor({{ (float)r, (float)g, (float)b, (float)a }}); + + mbgl::FillProperties fillProperties; + fillProperties.opacity = alpha; + fillProperties.stroke_color = strokeNativeColor; + fillProperties.fill_color = fillNativeColor; + shapeProperties.set(fillProperties); + } + else + { + [[NSException exceptionWithName:@"MGLUnknownShapeClassException" + reason:[NSString stringWithFormat:@"%@ is an unknown shape class", [annotation class]] + userInfo:nil] raise]; + } + + CLLocationCoordinate2D *coordinates = (CLLocationCoordinate2D *)malloc(count * sizeof(CLLocationCoordinate2D)); + [(MGLMultiPoint *)annotation getCoordinates:coordinates range:NSMakeRange(0, count)]; + + mbgl::AnnotationSegment segment; + segment.reserve(count); + + for (NSUInteger i = 0; i < count; i++) + { + segment.push_back(mbgl::LatLng(coordinates[i].latitude, coordinates[i].longitude)); + } + + free(coordinates); + + shapes.emplace_back(mbgl::AnnotationSegments {{ segment }}, shapeProperties); + } + else + { + MGLAnnotationImage *annotationImage = nil; + NSString *symbolName = nil; + + if (delegateImplementsImageForPoint) + { + annotationImage = [self.delegate mapView:self imageForAnnotation:annotation]; + + if (annotationImage) + { + const std::string cSymbolName = spritePrefix + std::string(annotationImage.reuseIdentifier.UTF8String); + symbolName = [NSString stringWithUTF8String:cSymbolName.c_str()]; + + if ( ! [self.annotationImages objectForKey:annotationImage.reuseIdentifier]) + { + // store image & symbol name + [self.annotationImages setObject:annotationImage forKey:annotationImage.reuseIdentifier]; + + // retrieve pixels + CGImageRef image = annotationImage.image.CGImage; + size_t width = CGImageGetWidth(image); + size_t height = CGImageGetHeight(image); + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + std::string pixels(width * height * 4, '\0'); + size_t bytesPerPixel = 4; + size_t bytesPerRow = bytesPerPixel * width; + size_t bitsPerComponent = 8; + char *pixelData = const_cast(pixels.data()); + CGContextRef context = CGBitmapContextCreate(pixelData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast); + CGContextDrawImage(context, CGRectMake(0, 0, width, height), image); + CGContextRelease(context); + CGColorSpaceRelease(colorSpace); + + // add sprite + auto cSpriteImage = std::make_shared( + uint16_t(annotationImage.image.size.width), + uint16_t(annotationImage.image.size.height), + float(annotationImage.image.scale), + std::move(pixels)); + + // sprite upload + _mbglMap->setSprite(cSymbolName, cSpriteImage); + } + } + } + + points.emplace_back(MGLLatLngFromLocationCoordinate2D(annotation.coordinate), symbolName ? [symbolName UTF8String] : ""); + } + } + + if (points.size()) + { + std::vector pointAnnotationIDs = _mbglMap->addPointAnnotations(points); + + for (size_t i = 0; i < pointAnnotationIDs.size(); ++i) + { + [self.annotationIDsByAnnotation setObject:@{ + MGLAnnotationIDKey : @(pointAnnotationIDs[i]), + MGLAnnotationSymbolKey : [NSString stringWithUTF8String:points[i].icon.c_str()] + } forKey:annotations[i]]; + } + } + + if (shapes.size()) + { + std::vector shapeAnnotationIDs = _mbglMap->addShapeAnnotations(shapes); + + for (size_t i = 0; i < shapeAnnotationIDs.size(); ++i) + { + [self.annotationIDsByAnnotation setObject:@{ MGLAnnotationIDKey : @(shapeAnnotationIDs[i]) } + forKey:annotations[i]]; + } + } +} + +- (void)removeAnnotation:(id )annotation +{ + if ( ! annotation) return; + + // The core bulk deletion API is efficient with respect to indexing + // and screen refreshes, thus we should defer to it even for + // individual deletes. + // + [self removeAnnotations:@[ annotation ]]; +} + +- (void)removeAnnotations:(NS_ARRAY_OF(id ) *)annotations +{ + if ( ! annotations) return; + + std::vector annotationIDsToRemove; + annotationIDsToRemove.reserve(annotations.count); + + for (id annotation in annotations) + { + assert([annotation conformsToProtocol:@protocol(MGLAnnotation)]); + + NSDictionary *infoDictionary = [self.annotationIDsByAnnotation objectForKey:annotation]; + annotationIDsToRemove.push_back([[infoDictionary objectForKey:MGLAnnotationIDKey] unsignedIntValue]); + + [self.annotationIDsByAnnotation removeObjectForKey:annotation]; + + if (annotation == self.selectedAnnotation) + { + [self deselectAnnotation:annotation animated:NO]; + } + } + + _mbglMap->removeAnnotations(annotationIDsToRemove); +} + +- (MGLAnnotationImage *)dequeueReusableAnnotationImageWithIdentifier:(NSString *)identifier +{ + return [self.annotationImages objectForKey:identifier]; +} + +- (NS_ARRAY_OF(id ) *)selectedAnnotations +{ + return (self.selectedAnnotation ? @[ self.selectedAnnotation ] : @[]); +} + +- (void)setSelectedAnnotations:(NS_ARRAY_OF(id ) *)selectedAnnotations +{ + if ( ! selectedAnnotations.count) return; + + id firstAnnotation = selectedAnnotations[0]; + + assert([firstAnnotation conformsToProtocol:@protocol(MGLAnnotation)]); + + if ([firstAnnotation isKindOfClass:[MGLMultiPoint class]]) return; + + if ( ! [self viewportBounds].contains(MGLLatLngFromLocationCoordinate2D(firstAnnotation.coordinate))) return; + + [self selectAnnotation:firstAnnotation animated:NO]; +} + +- (void)selectAnnotation:(id )annotation animated:(BOOL)animated +{ + if ( ! annotation) return; + + if ([annotation isKindOfClass:[MGLMultiPoint class]]) return; + + if ( ! [self viewportBounds].contains(MGLLatLngFromLocationCoordinate2D(annotation.coordinate))) return; + + if (annotation == self.selectedAnnotation) return; + + self.userTrackingMode = MGLUserTrackingModeNone; + + [self deselectAnnotation:self.selectedAnnotation animated:NO]; + + self.selectedAnnotation = annotation; + + if ([annotation respondsToSelector:@selector(title)] && + annotation.title && + [self.delegate respondsToSelector:@selector(mapView:annotationCanShowCallout:)] && + [self.delegate mapView:self annotationCanShowCallout:annotation]) + { + // build the callout + self.selectedAnnotationCalloutView = [self calloutViewForAnnotation:annotation]; + + CGRect calloutBounds; + + if ([annotation isEqual:self.userLocation]) + { + CGPoint calloutAnchorPoint = [self convertCoordinate:annotation.coordinate toPointToView:self]; + calloutBounds = CGRectMake(calloutAnchorPoint.x - 1, calloutAnchorPoint.y - 13, 0, 0); + } + else + { + // determine symbol in use for point + NSString *customSymbol = [[self.annotationIDsByAnnotation objectForKey:annotation] objectForKey:MGLAnnotationSymbolKey]; + NSString *symbolName = [customSymbol length] ? customSymbol : MGLDefaultStyleMarkerSymbolName; + std::string cSymbolName([symbolName UTF8String]); + + // determine anchor point based on symbol + CGPoint calloutAnchorPoint = [self convertCoordinate:annotation.coordinate toPointToView:self]; + double y = _mbglMap->getTopOffsetPixelsForAnnotationSymbol(cSymbolName); + calloutBounds = CGRectMake(calloutAnchorPoint.x - 1, calloutAnchorPoint.y + y, 0, 0); + } + + // consult delegate for left and/or right accessory views + if ([self.delegate respondsToSelector:@selector(mapView:leftCalloutAccessoryViewForAnnotation:)]) + { + self.selectedAnnotationCalloutView.leftAccessoryView = + [self.delegate mapView:self leftCalloutAccessoryViewForAnnotation:annotation]; + + if ([self.selectedAnnotationCalloutView.leftAccessoryView isKindOfClass:[UIControl class]]) + { + UITapGestureRecognizer *calloutAccessoryTap = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(handleCalloutAccessoryTapGesture:)]; + + [self.selectedAnnotationCalloutView.leftAccessoryView addGestureRecognizer:calloutAccessoryTap]; + } + } + + if ([self.delegate respondsToSelector:@selector(mapView:rightCalloutAccessoryViewForAnnotation:)]) + { + self.selectedAnnotationCalloutView.rightAccessoryView = + [self.delegate mapView:self rightCalloutAccessoryViewForAnnotation:annotation]; + + if ([self.selectedAnnotationCalloutView.rightAccessoryView isKindOfClass:[UIControl class]]) + { + UITapGestureRecognizer *calloutAccessoryTap = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(handleCalloutAccessoryTapGesture:)]; + + [self.selectedAnnotationCalloutView.rightAccessoryView addGestureRecognizer:calloutAccessoryTap]; + } + } + + // present popup + [self.selectedAnnotationCalloutView presentCalloutFromRect:calloutBounds + inView:self.glView + constrainedToView:self.glView + animated:animated]; + } + + // notify delegate + if ([self.delegate respondsToSelector:@selector(mapView:didSelectAnnotation:)]) + { + [self.delegate mapView:self didSelectAnnotation:annotation]; + } +} + +- (SMCalloutView *)calloutViewForAnnotation:(id )annotation +{ + SMCalloutView *calloutView = [SMCalloutView platformCalloutView]; + + if ([annotation respondsToSelector:@selector(title)]) calloutView.title = annotation.title; + if ([annotation respondsToSelector:@selector(subtitle)]) calloutView.subtitle = annotation.subtitle; + + calloutView.tintColor = self.tintColor; + + return calloutView; +} + +- (void)deselectAnnotation:(id )annotation animated:(BOOL)animated +{ + if ( ! annotation) return; + + if ([self.selectedAnnotation isEqual:annotation]) + { + // dismiss popup + [self.selectedAnnotationCalloutView dismissCalloutAnimated:animated]; + + // clean up + self.selectedAnnotationCalloutView = nil; + self.selectedAnnotation = nil; + + // notify delegate + if ([self.delegate respondsToSelector:@selector(mapView:didDeselectAnnotation:)]) + { + [self.delegate mapView:self didDeselectAnnotation:annotation]; + } + } +} + +- (void)showAnnotations:(NS_ARRAY_OF(id ) *)annotations animated:(BOOL)animated +{ + if ( ! annotations || ! annotations.count) return; + + mbgl::LatLngBounds bounds; + + for (id annotation in annotations) + { + if ([annotation conformsToProtocol:@protocol(MGLOverlay)]) + { + bounds.extend(MGLLatLngBoundsFromCoordinateBounds(((id )annotation).overlayBounds)); + } + else + { + bounds.extend(MGLLatLngFromLocationCoordinate2D(annotation.coordinate)); + } + } + + [self setVisibleCoordinateBounds:MGLCoordinateBoundsFromLatLngBounds(bounds) + edgePadding:UIEdgeInsetsMake(100, 100, 100, 100) + animated:animated]; +} + +#pragma mark - User Location - + +- (void)setShowsUserLocation:(BOOL)showsUserLocation +{ + if (showsUserLocation == _showsUserLocation) return; + + _showsUserLocation = showsUserLocation; + + if (showsUserLocation) + { + if ([self.delegate respondsToSelector:@selector(mapViewWillStartLocatingUser:)]) + { + [self.delegate mapViewWillStartLocatingUser:self]; + } + + self.userLocationAnnotationView = [[MGLUserLocationAnnotationView alloc] initInMapView:self]; + self.userLocationAnnotationView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | + UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); + + self.locationManager = [CLLocationManager new]; + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 + // enable iOS 8+ location authorization API + // + if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) + { + BOOL hasLocationDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] || + [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]; + if (!hasLocationDescription) + { + [NSException raise:@"Missing Location Services usage description" format: + @"In iOS 8 and above, this app must have a value for NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in its Info.plist."]; + } + [self.locationManager requestWhenInUseAuthorization]; + } +#endif + + self.locationManager.headingFilter = 5.0; + self.locationManager.delegate = self; + [self.locationManager startUpdatingLocation]; + } + else + { + [self.locationManager stopUpdatingLocation]; + [self.locationManager stopUpdatingHeading]; + self.locationManager.delegate = nil; + self.locationManager = nil; + + if ([self.delegate respondsToSelector:@selector(mapViewDidStopLocatingUser:)]) + { + [self.delegate mapViewDidStopLocatingUser:self]; + } + + [self setUserTrackingMode:MGLUserTrackingModeNone animated:YES]; + + [self.userLocationAnnotationView removeFromSuperview]; + self.userLocationAnnotationView = nil; + } +} + +- (void)setUserLocationAnnotationView:(MGLUserLocationAnnotationView *)newAnnotationView +{ + if ( ! [newAnnotationView isEqual:_userLocationAnnotationView]) + { + _userLocationAnnotationView = newAnnotationView; + } +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingUserLocation +{ + return [NSSet setWithObject:@"userLocationAnnotationView"]; +} + +- (nullable MGLUserLocation *)userLocation +{ + return self.userLocationAnnotationView.annotation; +} + +- (BOOL)isUserLocationVisible +{ + if (self.userLocationAnnotationView) + { + CGPoint locationPoint = [self convertCoordinate:self.userLocation.coordinate toPointToView:self]; + + CGRect locationRect = CGRectMake(locationPoint.x - self.userLocation.location.horizontalAccuracy, + locationPoint.y - self.userLocation.location.horizontalAccuracy, + self.userLocation.location.horizontalAccuracy * 2, + self.userLocation.location.horizontalAccuracy * 2); + + return CGRectIntersectsRect([self bounds], locationRect); + } + + return NO; +} + +- (void)setUserTrackingMode:(MGLUserTrackingMode)mode +{ + [self setUserTrackingMode:mode animated:YES]; +} + +- (void)setUserTrackingMode:(MGLUserTrackingMode)mode animated:(BOOL)animated +{ + if (mode == _userTrackingMode) return; + + if ((mode == MGLUserTrackingModeFollowWithHeading || mode == MGLUserTrackingModeFollowWithCourse) && + ! CLLocationCoordinate2DIsValid(self.userLocation.coordinate)) + { + mode = MGLUserTrackingModeNone; + } + + _userTrackingMode = mode; + + switch (_userTrackingMode) + { + case MGLUserTrackingModeNone: + { + [self.locationManager stopUpdatingHeading]; + + break; + } + case MGLUserTrackingModeFollow: + { + self.showsUserLocation = YES; + + [self.locationManager stopUpdatingHeading]; + + if (self.userLocationAnnotationView) + { + [self locationManager:self.locationManager didUpdateLocations:@[self.userLocation.location]]; + } + + break; + } + case MGLUserTrackingModeFollowWithHeading: + case MGLUserTrackingModeFollowWithCourse: + { + self.showsUserLocation = YES; + + if (self.zoomLevel < self.currentMinimumZoom) [self setZoomLevel:self.currentMinimumZoom animated:YES]; + + if (self.userLocationAnnotationView) + { + [self locationManager:self.locationManager didUpdateLocations:@[self.userLocation.location]]; + } + + [self updateHeadingForDeviceOrientation]; + + [self.locationManager startUpdatingHeading]; + + break; + } + } + + if ([self.delegate respondsToSelector:@selector(mapView:didChangeUserTrackingMode:animated:)]) + { + [self.delegate mapView:self didChangeUserTrackingMode:_userTrackingMode animated:animated]; + } +} + +- (void)locationManager:(__unused CLLocationManager *)manager didUpdateLocations:(NSArray *)locations +{ + CLLocation *oldLocation = self.userLocation.location; + CLLocation *newLocation = locations.lastObject; + + if ( ! _showsUserLocation || ! newLocation || ! CLLocationCoordinate2DIsValid(newLocation.coordinate)) return; + + if (! oldLocation || ! CLLocationCoordinate2DIsValid(oldLocation.coordinate) || [newLocation distanceFromLocation:oldLocation]) + { + self.userLocation.location = newLocation; + + // deselect user if applicable since we don't do callout tracking yet + if ([self.selectedAnnotation isEqual:self.userLocation]) [self deselectAnnotation:self.userLocation animated:NO]; + + if ([self.delegate respondsToSelector:@selector(mapView:didUpdateUserLocation:)]) + { + [self.delegate mapView:self didUpdateUserLocation:self.userLocation]; + } + } + + if (self.userTrackingMode != MGLUserTrackingModeNone) + { + // center on user location unless we're already centered there (or very close) + // + CGPoint mapCenterPoint = [self convertPoint:self.center fromView:self.superview]; + CGPoint userLocationPoint = [self convertCoordinate:self.userLocation.coordinate toPointToView:self]; + + if (std::abs(userLocationPoint.x - mapCenterPoint.x) > 1.0 || std::abs(userLocationPoint.y - mapCenterPoint.y) > 1.0) + { + if (round(self.zoomLevel) >= 10) + { + // at sufficient detail, just re-center the map; don't zoom + // + [self setCenterCoordinate:self.userLocation.location.coordinate animated:YES preservingTracking:YES]; + } + else + { + // otherwise re-center and zoom in to near accuracy confidence + // + float delta = (newLocation.horizontalAccuracy / 110000) * 1.2; // approx. meter per degree latitude, plus some margin + + CLLocationCoordinate2D desiredSouthWest = CLLocationCoordinate2DMake(newLocation.coordinate.latitude - delta, + newLocation.coordinate.longitude - delta); + + CLLocationCoordinate2D desiredNorthEast = CLLocationCoordinate2DMake(newLocation.coordinate.latitude + delta, + newLocation.coordinate.longitude + delta); + + CGFloat pixelRadius = fminf(self.bounds.size.width, self.bounds.size.height) / 2; + + CLLocationCoordinate2D actualSouthWest = [self convertPoint:CGPointMake(userLocationPoint.x - pixelRadius, + userLocationPoint.y - pixelRadius) + toCoordinateFromView:self]; + + CLLocationCoordinate2D actualNorthEast = [self convertPoint:CGPointMake(userLocationPoint.x + pixelRadius, + userLocationPoint.y + pixelRadius) + toCoordinateFromView:self]; + + if (desiredNorthEast.latitude != actualNorthEast.latitude || + desiredNorthEast.longitude != actualNorthEast.longitude || + desiredSouthWest.latitude != actualSouthWest.latitude || + desiredSouthWest.longitude != actualSouthWest.longitude) + { + // assumes we won't disrupt tracking mode + [self setVisibleCoordinateBounds:MGLCoordinateBoundsMake(desiredSouthWest, desiredNorthEast) animated:YES]; + } + } + } + } + + CLLocationDirection course = self.userLocation.location.course; + if (course >= 0 && self.userTrackingMode == MGLUserTrackingModeFollowWithCourse) + { + _mbglMap->setBearing(course); + } + + self.userLocationAnnotationView.haloLayer.hidden = ! CLLocationCoordinate2DIsValid(self.userLocation.coordinate) || + newLocation.horizontalAccuracy > 10; + + [self updateUserLocationAnnotationView]; +} + +- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager +{ + if (self.displayHeadingCalibration) [manager performSelector:@selector(dismissHeadingCalibrationDisplay) + withObject:nil + afterDelay:10.0]; + + return self.displayHeadingCalibration; +} + +- (void)locationManager:(__unused CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading +{ + if ( ! _showsUserLocation || self.pan.state == UIGestureRecognizerStateBegan || newHeading.headingAccuracy < 0) return; + + self.userLocation.heading = newHeading; + + if ([self.delegate respondsToSelector:@selector(mapView:didUpdateUserLocation:)]) + { + [self.delegate mapView:self didUpdateUserLocation:self.userLocation]; + + if ( ! _showsUserLocation) return; + } + + CLLocationDirection headingDirection = (newHeading.trueHeading >= 0 ? newHeading.trueHeading : newHeading.magneticHeading); + + if (headingDirection >= 0 && self.userTrackingMode == MGLUserTrackingModeFollowWithHeading) + { + _mbglMap->setBearing(headingDirection, secondsAsDuration(MGLAnimationDuration)); + } +} + +- (void)locationManager:(__unused CLLocationManager *)manager didFailWithError:(NSError *)error +{ + if ([error code] == kCLErrorDenied) + { + self.userTrackingMode = MGLUserTrackingModeNone; + self.showsUserLocation = NO; + + if ([self.delegate respondsToSelector:@selector(mapView:didFailToLocateUserWithError:)]) + { + [self.delegate mapView:self didFailToLocateUserWithError:error]; + } + } +} + +- (void)updateHeadingForDeviceOrientation +{ + if (self.locationManager) + { + // note that right/left device and interface orientations are opposites (see UIApplication.h) + // + switch ([[UIApplication sharedApplication] statusBarOrientation]) + { + case (UIInterfaceOrientationLandscapeLeft): + { + self.locationManager.headingOrientation = CLDeviceOrientationLandscapeRight; + break; + } + case (UIInterfaceOrientationLandscapeRight): + { + self.locationManager.headingOrientation = CLDeviceOrientationLandscapeLeft; + break; + } + case (UIInterfaceOrientationPortraitUpsideDown): + { + self.locationManager.headingOrientation = CLDeviceOrientationPortraitUpsideDown; + break; + } + case (UIInterfaceOrientationPortrait): + default: + { + self.locationManager.headingOrientation = CLDeviceOrientationPortrait; + break; + } + } + } +} + +#pragma mark - Utility - + +- (void)animateWithDelay:(NSTimeInterval)delay animations:(void (^)(void))animations +{ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), animations); +} + +- (CGFloat)currentMinimumZoom +{ + return fmaxf(_mbglMap->getMinZoom(), MGLMinimumZoom); +} + +- (BOOL)isRotationAllowed +{ + return (self.zoomLevel >= self.currentMinimumZoom); +} + +// correct rotations to north as needed +// +- (void)unrotateIfNeededAnimated:(BOOL)animated +{ + // don't worry about it in the midst of pinch or rotate gestures + // + if (self.pinch.state == UIGestureRecognizerStateChanged || self.rotate.state == UIGestureRecognizerStateChanged) return; + + // but otherwise, do + // + if (self.direction != 0 && ! self.isRotationAllowed) + { + if (animated) + { + self.animatingGesture = YES; + + self.userInteractionEnabled = NO; + + __weak MGLMapView *weakSelf = self; + + [self animateWithDelay:0.1 animations:^ + { + [weakSelf resetNorthAnimated:YES]; + + [self animateWithDelay:MGLAnimationDuration animations:^ + { + weakSelf.userInteractionEnabled = YES; + + self.animatingGesture = NO; + }]; + + }]; + } + else + { + [self resetNorthAnimated:NO]; + } + } +} + +- (void)unsuspendRegionChangeDelegateQueue +{ + @synchronized (self.regionChangeDelegateQueue) + { + [self.regionChangeDelegateQueue setSuspended:NO]; + } +} + +- (void)notifyMapChange:(mbgl::MapChange)change +{ + // Ignore map updates when the Map object isn't set. + if (!_mbglMap) { + return; + } + + switch (change) + { + case mbgl::MapChangeRegionWillChange: + case mbgl::MapChangeRegionWillChangeAnimated: + { + [self deselectAnnotation:self.selectedAnnotation animated:NO]; + + BOOL animated = (change == mbgl::MapChangeRegionWillChangeAnimated); + + @synchronized (self.regionChangeDelegateQueue) + { + if ([self.regionChangeDelegateQueue operationCount] == 0) + { + if ([self.delegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)]) + { + [self.delegate mapView:self regionWillChangeAnimated:animated]; + } + } + + [self.regionChangeDelegateQueue setSuspended:YES]; + + if ([self.regionChangeDelegateQueue operationCount] == 0) + { + [self.regionChangeDelegateQueue addOperationWithBlock:^ + { + dispatch_async(dispatch_get_main_queue(), ^ + { + if ([self.delegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)]) + { + [self.delegate mapView:self regionDidChangeAnimated:animated]; + } + }); + }]; + } + } + break; + } + case mbgl::MapChangeRegionIsChanging: + { + [self updateCompass]; + + if ([self.delegate respondsToSelector:@selector(mapViewRegionIsChanging:)]) + { + [self.delegate mapViewRegionIsChanging:self]; + } + break; + } + case mbgl::MapChangeRegionDidChange: + case mbgl::MapChangeRegionDidChangeAnimated: + { + [self updateCompass]; + + if (self.pan.state == UIGestureRecognizerStateChanged || + self.pinch.state == UIGestureRecognizerStateChanged || + self.rotate.state == UIGestureRecognizerStateChanged || + self.quickZoom.state == UIGestureRecognizerStateChanged) return; + + if (self.isAnimatingGesture) return; + + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(unsuspendRegionChangeDelegateQueue) object:nil]; + [self performSelector:@selector(unsuspendRegionChangeDelegateQueue) withObject:nil afterDelay:0]; + + break; + } + case mbgl::MapChangeWillStartLoadingMap: + { + if ([self.delegate respondsToSelector:@selector(mapViewWillStartLoadingMap:)]) + { + [self.delegate mapViewWillStartLoadingMap:self]; + } + break; + } + case mbgl::MapChangeDidFinishLoadingMap: + { + if ([self.delegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)]) + { + [self.delegate mapViewDidFinishLoadingMap:self]; + } + break; + } + case mbgl::MapChangeDidFailLoadingMap: + { + if ([self.delegate respondsToSelector:@selector(mapViewDidFailLoadingMap:withError:)]) + { + NSError *error = [NSError errorWithDomain:MGLErrorDomain code:0 userInfo:nil]; + [self.delegate mapViewDidFailLoadingMap:self withError:error]; + } + break; + } + case mbgl::MapChangeWillStartRenderingMap: + { + if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingMap:)]) + { + [self.delegate mapViewWillStartRenderingMap:self]; + } + break; + } + case mbgl::MapChangeDidFinishRenderingMap: + case mbgl::MapChangeDidFinishRenderingMapFullyRendered: + { + if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingMap:fullyRendered:)]) + { + [self.delegate mapViewDidFinishRenderingMap:self fullyRendered:(change == mbgl::MapChangeDidFinishRenderingMapFullyRendered)]; + } + break; + } + case mbgl::MapChangeWillStartRenderingFrame: + { + if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingFrame:)]) + { + [self.delegate mapViewWillStartRenderingFrame:self]; + } + break; + } + case mbgl::MapChangeDidFinishRenderingFrame: + case mbgl::MapChangeDidFinishRenderingFrameFullyRendered: + { + if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingFrame:fullyRendered:)]) + { + [self.delegate mapViewDidFinishRenderingFrame:self fullyRendered:(change == mbgl::MapChangeDidFinishRenderingFrameFullyRendered)]; + } + break; + } + } +} + +- (void)updateUserLocationAnnotationView +{ + if ( ! CLLocationCoordinate2DIsValid(self.userLocation.coordinate)) { + self.userLocationAnnotationView.layer.hidden = YES; + return; + } + + if ( ! self.userLocationAnnotationView.superview) [self.glView addSubview:self.userLocationAnnotationView]; + + CGPoint userPoint = [self convertCoordinate:self.userLocation.coordinate toPointToView:self]; + + if (CGRectContainsPoint(CGRectInset(self.bounds, -MGLAnnotationUpdateViewportOutset.width, + -MGLAnnotationUpdateViewportOutset.height), userPoint)) + { + self.userLocationAnnotationView.center = userPoint; + + self.userLocationAnnotationView.layer.hidden = NO; + + [self.userLocationAnnotationView setupLayers]; + } + else + { + self.userLocationAnnotationView.layer.hidden = YES; + } +} + +- (void)updateCompass +{ + CLLocationDirection degrees = mbgl::util::wrap(-self.direction, 0., 360.); + + self.compassView.transform = CGAffineTransformMakeRotation(MGLRadiansFromDegrees(degrees)); + + if (_mbglMap->getBearing() && self.compassView.alpha < 1) + { + [UIView animateWithDuration:MGLAnimationDuration + delay:0 + options:UIViewAnimationOptionBeginFromCurrentState + animations:^ + { + self.compassView.alpha = 1; + } + completion:nil]; + } + else if (_mbglMap->getBearing() == 0 && self.compassView.alpha > 0) + { + [UIView animateWithDuration:MGLAnimationDuration + delay:0 + options:UIViewAnimationOptionBeginFromCurrentState + animations:^ + { + self.compassView.alpha = 0; + } + completion:nil]; + } +} + ++ (UIImage *)resourceImageNamed:(NSString *)imageName +{ + if ( ! [[imageName pathExtension] length]) + { + imageName = [imageName stringByAppendingString:@".png"]; + } + + return [UIImage imageWithContentsOfFile:[self pathForBundleResourceNamed:imageName ofType:nil inDirectory:@""]]; +} + ++ (NSString *)pathForBundleResourceNamed:(NSString *)name ofType:(NSString *)extension inDirectory:(NSString *)directory +{ + NSString *path = [[NSBundle bundleWithPath:[NSBundle mgl_resourceBundlePath]] pathForResource:name ofType:extension inDirectory:directory]; + + if (!path) + { + [NSException raise:@"Resource not found" format: + @"The resource named “%@” could not be found in the Mapbox resource bundle.", name]; + } + + return path; +} + +- (void)invalidate +{ + MGLAssertIsMainThread(); + [self.glView setNeedsDisplay]; +} + +- (BOOL)isFullyLoaded +{ + return _mbglMap->isFullyLoaded(); +} + +- (void)prepareForInterfaceBuilder +{ + [super prepareForInterfaceBuilder]; + + self.layer.borderColor = [UIColor colorWithRed:59/255. + green:178/255. + blue:208/255. + alpha:0.8].CGColor; + self.layer.borderWidth = 4; + self.layer.backgroundColor = [UIColor whiteColor].CGColor; + + UIView *diagnosticView = [[UIView alloc] init]; + diagnosticView.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:diagnosticView]; + + // Headline + UILabel *headlineLabel = [[UILabel alloc] init]; + headlineLabel.text = @"MGLMapView"; + headlineLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + headlineLabel.textAlignment = NSTextAlignmentCenter; + headlineLabel.numberOfLines = 1; + headlineLabel.translatesAutoresizingMaskIntoConstraints = NO; + [headlineLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow + forAxis:UILayoutConstraintAxisHorizontal]; + [diagnosticView addSubview:headlineLabel]; + + // Explanation + UILabel *explanationLabel = [[UILabel alloc] init]; + explanationLabel.text = (@"To display a Mapbox-hosted map here:\n\n" + @"1. Set MGLMapboxAccessToken to your access token in Info.plist\n" + @"2. Add a Settings bundle that allows the user to turn Mapbox Metrics on and off\n\n" + @"For detailed instructions, see:"); + explanationLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + explanationLabel.numberOfLines = 0; + explanationLabel.translatesAutoresizingMaskIntoConstraints = NO; + [explanationLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow + forAxis:UILayoutConstraintAxisHorizontal]; + [diagnosticView addSubview:explanationLabel]; + + // Link + UIButton *linkButton = [UIButton buttonWithType:UIButtonTypeSystem]; + [linkButton setTitle:MGLMapboxSetupDocumentationURLDisplayString forState:UIControlStateNormal]; + linkButton.translatesAutoresizingMaskIntoConstraints = NO; + linkButton.titleLabel.numberOfLines = 0; + [linkButton setContentCompressionResistancePriority:UILayoutPriorityDefaultLow + forAxis:UILayoutConstraintAxisHorizontal]; + [diagnosticView addSubview:linkButton]; + + // Constraints + NSDictionary *views = @{ + @"container": diagnosticView, + @"headline": headlineLabel, + @"explanation": explanationLabel, + @"link": linkButton, + }; + [self addConstraint: + [NSLayoutConstraint constraintWithItem:diagnosticView + attribute:NSLayoutAttributeCenterYWithinMargins + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeCenterYWithinMargins + multiplier:1 + constant:0]]; + [self addConstraint: + [NSLayoutConstraint constraintWithItem:diagnosticView + attribute:NSLayoutAttributeTopMargin + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self + attribute:NSLayoutAttributeTopMargin + multiplier:1 + constant:8]]; + [self addConstraint: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeBottomMargin + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:diagnosticView + attribute:NSLayoutAttributeBottomMargin + multiplier:1 + constant:8]]; + [self addConstraints: + [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[container(20@20)]-|" + options:NSLayoutFormatAlignAllCenterY + metrics:nil + views:views]]; + [self addConstraints: + [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[headline]-[explanation]-[link]|" + options:0 + metrics:nil + views:views]]; + [self addConstraints: + [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[headline]|" + options:0 + metrics:nil + views:views]]; + [self addConstraints: + [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[explanation]|" + options:0 + metrics:nil + views:views]]; + [self addConstraints: + [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[link]|" + options:0 + metrics:nil + views:views]]; +} + +class MBGLView : public mbgl::View +{ + public: + MBGLView(MGLMapView* nativeView_, const float scaleFactor_) + : nativeView(nativeView_), scaleFactor(scaleFactor_) { + } + virtual ~MBGLView() {} + + + float getPixelRatio() const override { + return scaleFactor; + } + + std::array getSize() const override { + return {{ static_cast([nativeView bounds].size.width), + static_cast([nativeView bounds].size.height) }}; + } + + std::array getFramebufferSize() const override { + return {{ static_cast([[nativeView glView] drawableWidth]), + static_cast([[nativeView glView] drawableHeight]) }}; + } + + void notify() override + { + // no-op + } + + void notifyMapChange(mbgl::MapChange change) override + { + assert([[NSThread currentThread] isMainThread]); + [nativeView notifyMapChange:change]; + } + + void activate() override + { + [EAGLContext setCurrentContext:nativeView.context]; + } + + void deactivate() override + { + [EAGLContext setCurrentContext:nil]; + } + + void invalidate() override + { + [nativeView performSelectorOnMainThread:@selector(invalidate) + withObject:nil + waitUntilDone:NO]; + } + + void swap() override + { + // no-op + } + + private: + __weak MGLMapView *nativeView = nullptr; + const float scaleFactor; +}; + +@end + +@implementation MGLMapView (IBAdditions) + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLatitude +{ + return [NSSet setWithObject:@"centerCoordinate"]; +} + +- (double)latitude +{ + return self.centerCoordinate.latitude; +} + +- (void)setLatitude:(double)latitude +{ + if ( ! isnan(_pendingLongitude)) + { + self.centerCoordinate = CLLocationCoordinate2DMake(latitude, _pendingLongitude); + _pendingLatitude = NAN; + _pendingLongitude = NAN; + } + else + { + // Not enough info to make a valid center coordinate yet. Stash this + // latitude away until the longitude is set too. + _pendingLatitude = latitude; + } +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLongitude +{ + return [NSSet setWithObject:@"centerCoordinate"]; +} + +- (double)longitude +{ + return self.centerCoordinate.longitude; +} + +- (void)setLongitude:(double)longitude +{ + if ( ! isnan(_pendingLatitude)) + { + self.centerCoordinate = CLLocationCoordinate2DMake(_pendingLatitude, longitude); + _pendingLatitude = NAN; + _pendingLongitude = NAN; + } + else + { + // Not enough info to make a valid center coordinate yet. Stash this + // longitude away until the latitude is set too. + _pendingLongitude = longitude; + } +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsZooming +{ + return [NSSet setWithObject:@"zoomEnabled"]; +} + +- (BOOL)allowsZooming +{ + return self.zoomEnabled; +} + +- (void)setAllowsZooming:(BOOL)allowsZooming +{ + self.zoomEnabled = allowsZooming; +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsScrolling +{ + return [NSSet setWithObject:@"scrollEnabled"]; +} + +- (BOOL)allowsScrolling +{ + return self.scrollEnabled; +} + +- (void)setAllowsScrolling:(BOOL)allowsScrolling +{ + self.scrollEnabled = allowsScrolling; +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsRotating +{ + return [NSSet setWithObject:@"rotateEnabled"]; +} + +- (BOOL)allowsRotating +{ + return self.rotateEnabled; +} + +- (void)setAllowsRotating:(BOOL)allowsRotating +{ + self.rotateEnabled = allowsRotating; +} + +- (void)didReceiveMemoryWarning +{ + _mbglMap->onLowMemory(); +} + +@end diff --git a/platform/ios/MGLMapboxEvents.h b/platform/ios/MGLMapboxEvents.h new file mode 100644 index 000000000..9efb53c5e --- /dev/null +++ b/platform/ios/MGLMapboxEvents.h @@ -0,0 +1,70 @@ +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const MGLEventTypeAppUserTurnstile; +extern NSString *const MGLEventTypeMapLoad; +extern NSString *const MGLEventTypeMapTap; +extern NSString *const MGLEventTypeMapDragEnd; +extern NSString *const MGLEventTypeLocation; +extern NSString *const MGLEventTypeVisit; + +extern NSString *const MGLEventKeyLatitude; +extern NSString *const MGLEventKeyLongitude; +extern NSString *const MGLEventKeyZoomLevel; +extern NSString *const MGLEventKeySpeed; +extern NSString *const MGLEventKeyCourse; +extern NSString *const MGLEventKeyAltitude; +extern NSString *const MGLEventKeyHorizontalAccuracy; +extern NSString *const MGLEventKeyVerticalAccuracy; +extern NSString *const MGLEventKeyPushEnabled; +extern NSString *const MGLEventKeyEmailEnabled; +extern NSString *const MGLEventKeyGestureID; +extern NSString *const MGLEventKeyArrivalDate; +extern NSString *const MGLEventKeyDepartureDate; + +extern NSString *const MGLEventGestureSingleTap; +extern NSString *const MGLEventGestureDoubleTap; +extern NSString *const MGLEventGestureTwoFingerSingleTap; +extern NSString *const MGLEventGestureQuickZoom; +extern NSString *const MGLEventGesturePanStart; +extern NSString *const MGLEventGesturePinchStart; +extern NSString *const MGLEventGestureRotateStart; + +typedef NS_DICTIONARY_OF(NSString *, id) MGLMapboxEventAttributes; +typedef NS_MUTABLE_DICTIONARY_OF(NSString *, id) MGLMutableMapboxEventAttributes; + +@interface MGLMapboxEvents : NSObject + ++ (nullable instancetype)sharedManager; + +// You must call these methods from the main thread. +// ++ (void) pauseMetricsCollection; ++ (void) resumeMetricsCollection; + +// You can call this method from any thread. Significant work will +// be dispatched to a low-priority background queue and all +// resulting calls are guaranteed threadsafe. +// +// Events or attributes passed could be accessed on non-main threads, +// so you must not reference UI elements from within any arguments. +// Copy any values needed first or create dedicated methods in this +// class for threadsafe access to UIKit classes. +// ++ (void) pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary; + +// You can call these methods from any thread. +// ++ (BOOL) checkPushEnabled; + +// You can call this method from any thread. +// ++ (void) flush; + +// Main thread only ++ (void)validate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m new file mode 100644 index 000000000..314d50dd0 --- /dev/null +++ b/platform/ios/MGLMapboxEvents.m @@ -0,0 +1,928 @@ +#import "MGLMapboxEvents.h" + +#import +#import +#import +#import +#import + +#import "MGLAccountManager.h" +#import "NSProcessInfo+MGLAdditions.h" +#import "NSBundle+MGLAdditions.h" +#import "NSException+MGLAdditions.h" + +#include + +static const NSUInteger version = 1; +static NSString *const MGLMapboxEventsUserAgent = @"MapboxEventsiOS/1.0"; +static NSString *MGLMapboxEventsAPIBase = @"https://api.tiles.mapbox.com"; + +NSString *const MGLEventTypeAppUserTurnstile = @"appUserTurnstile"; +NSString *const MGLEventTypeMapLoad = @"map.load"; +NSString *const MGLEventTypeMapTap = @"map.click"; +NSString *const MGLEventTypeMapDragEnd = @"map.dragend"; +NSString *const MGLEventTypeLocation = @"location"; +NSString *const MGLEventTypeVisit = @"visit"; + +NSString *const MGLEventKeyLatitude = @"lat"; +NSString *const MGLEventKeyLongitude = @"lng"; +NSString *const MGLEventKeyZoomLevel = @"zoom"; +NSString *const MGLEventKeySpeed = @"speed"; +NSString *const MGLEventKeyCourse = @"course"; +NSString *const MGLEventKeyAltitude = @"altitude"; +NSString *const MGLEventKeyHorizontalAccuracy = @"horizontalAccuracy"; +NSString *const MGLEventKeyVerticalAccuracy = @"verticalAccuracy"; +NSString *const MGLEventKeyPushEnabled = @"enabled.push"; +NSString *const MGLEventKeyEmailEnabled = @"enabled.email"; +NSString *const MGLEventKeyGestureID = @"gesture"; +NSString *const MGLEventKeyArrivalDate = @"arrivalDate"; +NSString *const MGLEventKeyDepartureDate = @"departureDate"; + +NSString *const MGLEventGestureSingleTap = @"SingleTap"; +NSString *const MGLEventGestureDoubleTap = @"DoubleTap"; +NSString *const MGLEventGestureTwoFingerSingleTap = @"TwoFingerTap"; +NSString *const MGLEventGestureQuickZoom = @"QuickZoom"; +NSString *const MGLEventGesturePanStart = @"Pan"; +NSString *const MGLEventGesturePinchStart = @"Pinch"; +NSString *const MGLEventGestureRotateStart = @"Rotation"; + +const NSUInteger MGLMaximumEventsPerFlush = 20; +const NSTimeInterval MGLFlushInterval = 60; + +@interface MGLMapboxEventsData : NSObject + +// All of the following properties are written to only from +// the main thread, but can be read on any thread. +// +@property (atomic) NSString *advertiserId; +@property (atomic) NSString *vendorId; +@property (atomic) NSString *model; +@property (atomic) NSString *iOSVersion; +@property (atomic) NSString *carrier; +@property (atomic) CGFloat scale; + +@end + +@implementation MGLMapboxEventsData + +- (instancetype)init { + if (self = [super init]) { + + // Dynamic detection of ASIdentifierManager from Mixpanel + // https://github.com/mixpanel/mixpanel-iphone/blob/master/LICENSE + _advertiserId = @""; + Class ASIdentifierManagerClass = NSClassFromString(@"ASIdentifierManager"); + if (ASIdentifierManagerClass) { + SEL sharedManagerSelector = NSSelectorFromString(@"sharedManager"); + id sharedManager = ((id (*)(id, SEL))[ASIdentifierManagerClass methodForSelector:sharedManagerSelector])(ASIdentifierManagerClass, sharedManagerSelector); + // Add check here + SEL isAdvertisingTrackingEnabledSelector = NSSelectorFromString(@"isAdvertisingTrackingEnabled"); + BOOL trackingEnabled = ((BOOL (*)(id, SEL))[sharedManager methodForSelector:isAdvertisingTrackingEnabledSelector])(sharedManager, isAdvertisingTrackingEnabledSelector); + if (trackingEnabled) { + SEL advertisingIdentifierSelector = NSSelectorFromString(@"advertisingIdentifier"); + NSUUID *uuid = ((NSUUID* (*)(id, SEL))[sharedManager methodForSelector:advertisingIdentifierSelector])(sharedManager, advertisingIdentifierSelector); + _advertiserId = [uuid UUIDString]; + } + } + _vendorId = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + + _model = [self sysInfoByName:"hw.machine"]; + _iOSVersion = [NSString stringWithFormat:@"%@ %@", [UIDevice currentDevice].systemName, [UIDevice currentDevice].systemVersion]; + if ([UIScreen instancesRespondToSelector:@selector(nativeScale)]) { + _scale = [UIScreen mainScreen].nativeScale; + } else { + _scale = [UIScreen mainScreen].scale; + } + CTCarrier *carrierVendor = [[[CTTelephonyNetworkInfo alloc] init] subscriberCellularProvider]; + _carrier = [carrierVendor carrierName]; + } + return self; +} + +// Can be called from any thread. +// +- (NSString *)sysInfoByName:(char *)typeSpecifier +{ + size_t size; + sysctlbyname(typeSpecifier, NULL, &size, NULL, 0); + + char *answer = malloc(size); + sysctlbyname(typeSpecifier, answer, &size, NULL, 0); + + NSString *results = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding]; + + free(answer); + return results; +} + +@end + +// +// Threadsafety conventions: +// +// All variables accessed from more than one thread are +// designated `atomic` and accessed through dot syntax. The +// main thread uses underscore syntax during the +// initialization of the variable. +// +// All variables accessed outside of initialization and +// from within a single thread use underscore syntax. +// +// All captures of `self` from within asynchronous +// dispatches will use a `strongSelf` to avoid cyclical +// strong references. +// + +@interface MGLMapboxEvents () + +// All of the following properties are written to only from +// the main thread, but can be read on any thread. +// +@property (atomic) MGLMapboxEventsData *data; +@property (atomic) NSString *appBundleId; +@property (atomic) NSString *appName; +@property (atomic) NSString *appVersion; +@property (atomic) NSString *appBuildNumber; +@property (atomic) NSString *instanceID; +@property (atomic) NSDateFormatter *rfc3339DateFormatter; +@property (atomic) NSURLSession *session; +@property (atomic) NSData *digicertCert; +@property (atomic) NSData *geoTrustCert; +@property (atomic) NSData *testServerCert; +@property (atomic) BOOL usesTestServer; + +// Main thread only +@property (nonatomic) CLLocationManager *locationManager; + +// The paused state tracker is only ever accessed from the main thread. +// +@property (nonatomic, getter=isPaused) BOOL paused; + +// The timer is only ever accessed from the main thread. +// +@property (nonatomic) NSTimer *timer; + +// This is an array of events to push. All access to it will be +// from our own serial queue. +// +@property (nonatomic) NS_MUTABLE_ARRAY_OF(MGLMapboxEventAttributes *) *eventQueue; + +// This is a custom serial queue for accessing the event queue. +// +@property (nonatomic) dispatch_queue_t serialQueue; + +@end + +@implementation MGLMapboxEvents { + id _userDefaultsObserver; +} + ++ (void)initialize { + if (self == [MGLMapboxEvents class]) { + NSBundle *bundle = [NSBundle mainBundle]; + NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccountType"]; + [[NSUserDefaults standardUserDefaults] registerDefaults:@{ + @"MGLMapboxAccountType": accountTypeNumber ? accountTypeNumber : @0, + @"MGLMapboxMetricsEnabled": @YES, + }]; + } +} + ++ (BOOL)isEnabled { + return ([[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsEnabled"] && + [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0); +} + +// Must be called from the main thread. Only called internally. +// +- (instancetype) init { + MGLAssertIsMainThread(); + + self = [super init]; + if (self) { + if (! [MGLAccountManager mapboxMetricsEnabledSettingShownInApp] && + [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0) { + // Opt Out is not configured in UI, so check for Settings.bundle + // Put Settings bundle into memory + id defaultEnabledValue; + NSString *appSettingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"]; + + if (appSettingsBundle) { + // Dynamic Settings.bundle loading based on: + // http://stackoverflow.com/questions/510216/can-you-make-the-settings-in-settings-bundle-default-even-if-you-dont-open-the + NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[appSettingsBundle stringByAppendingPathComponent:@"Root.plist"]]; + NSArray *preferences = settings[@"PreferenceSpecifiers"]; + for (NSDictionary *prefSpecification in preferences) { + if ([prefSpecification[@"Key"] isEqualToString:@"MGLMapboxMetricsEnabled"]) { + defaultEnabledValue = prefSpecification[@"DefaultValue"]; + } + } + } + + if (!defaultEnabledValue) + { + [NSException raise:@"MGLMapboxMetricsEnabled setting missing" format: + @"End users must be able to opt out of Metrics in your app, either inside Settings (via Settings.bundle) or inside this app. " + @"If you implement the opt-out control inside this app, disable this assertion by setting MGLMapboxMetricsEnabledSettingShownInApp to YES in Info.plist."]; + } + [[NSUserDefaults standardUserDefaults] registerDefaults:@{ + @"MGLMapboxMetricsEnabled": defaultEnabledValue, + }]; + } + + _appBundleId = [[NSBundle mainBundle] bundleIdentifier]; + _appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + _appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + _appBuildNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; + _instanceID = [[NSUUID UUID] UUIDString]; + + NSString *uniqueID = [[NSProcessInfo processInfo] globallyUniqueString]; + _serialQueue = dispatch_queue_create([[NSString stringWithFormat:@"%@.%@.events.serial", _appBundleId, uniqueID] UTF8String], DISPATCH_QUEUE_SERIAL); + + // Configure Events Infrastructure + // =============================== + + // Check for TEST Metrics URL + NSString *testURL = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLMetricsTestServerURL"]; + if (testURL != nil) { + MGLMapboxEventsAPIBase = testURL; + _usesTestServer = YES; + } else { + // Explicitly Set For Clarity + _usesTestServer = NO; + } + + _paused = YES; + [self resumeMetricsCollection]; + NSBundle *resourceBundle = [NSBundle bundleWithPath:[NSBundle mgl_resourceBundlePath]]; + + // Load Local Copy of Server's Public Key + NSString *cerPath = nil; + cerPath = [resourceBundle pathForResource:@"api_mapbox_com-geotrust" ofType:@"der"]; + if (cerPath != nil) { + _geoTrustCert = [NSData dataWithContentsOfFile:cerPath]; + } + + cerPath = [resourceBundle pathForResource:@"api_mapbox_com-digicert" ofType:@"der"]; + if (cerPath != nil) { + _digicertCert = [NSData dataWithContentsOfFile:cerPath]; + } + cerPath = [resourceBundle pathForResource:@"star_tilestream_net" ofType:@"der"]; + if (cerPath != nil) { + _testServerCert = [NSData dataWithContentsOfFile:cerPath]; + } + + // Events Control + _eventQueue = [[NSMutableArray alloc] init]; + + // Setup Date Format + _rfc3339DateFormatter = [[NSDateFormatter alloc] init]; + NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + + [_rfc3339DateFormatter setLocale:enUSPOSIXLocale]; + [_rfc3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"]; + // Clear Any System TimeZone Cache + [NSTimeZone resetSystemTimeZone]; + [_rfc3339DateFormatter setTimeZone:[NSTimeZone systemTimeZone]]; + + // Enable Battery Monitoring + [UIDevice currentDevice].batteryMonitoringEnabled = YES; + + __weak MGLMapboxEvents *weakSelf = self; + _userDefaultsObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification + object:nil + queue:[NSOperationQueue mainQueue] + usingBlock: + ^(NSNotification *notification) { + MGLMapboxEvents *strongSelf = weakSelf; + [strongSelf validate]; + }]; + + // Turn the Mapbox Turnstile to Count App Users + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + [self pushTurnstileEvent]; + }); + } + return self; +} + +// Can be called from any thread. Called implicitly from any +// public class convenience methods. May return nil if this feature is disabled. +// ++ (nullable instancetype)sharedManager { + if (NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) { + return nil; + } + static dispatch_once_t onceToken; + static MGLMapboxEvents *_sharedManager; + void (^setupBlock)() = ^{ + dispatch_once(&onceToken, ^{ + _sharedManager = [[self alloc] init]; + }); + }; + if ( ! [[NSThread currentThread] isMainThread]) { + dispatch_sync(dispatch_get_main_queue(), ^{ + setupBlock(); + }); + } + else { + setupBlock(); + } + return _sharedManager; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:_userDefaultsObserver]; + [self pauseMetricsCollection]; +} + ++ (void)validate { + [[MGLMapboxEvents sharedManager] validate]; +} + +// Used to determine if Mapbox Metrics should be collected at any given point in time +- (void)validate { + MGLAssertIsMainThread(); + BOOL enabledInSettings = [[self class] isEnabled]; + if (self.paused && enabledInSettings) { + [self resumeMetricsCollection]; + } else if (!self.paused && !enabledInSettings) { + [self pauseMetricsCollection]; + } + + [self validateUpdatingLocation]; +} + +- (void)validateUpdatingLocation { + MGLAssertIsMainThread(); + if (self.paused) { + [self stopUpdatingLocation]; + } else { + CLAuthorizationStatus authStatus = [CLLocationManager authorizationStatus]; + if (authStatus == kCLAuthorizationStatusDenied || + authStatus == kCLAuthorizationStatusRestricted) { + [self stopUpdatingLocation]; + } else if (authStatus == kCLAuthorizationStatusAuthorized || + authStatus == kCLAuthorizationStatusAuthorizedWhenInUse) { + [self startUpdatingLocation]; + } + } +} + ++ (void)pauseMetricsCollection { + [[MGLMapboxEvents sharedManager] pauseMetricsCollection]; +} + +// Must be called from the main thread. +// +- (void)pauseMetricsCollection { + MGLAssertIsMainThread(); + if (self.paused) { + return; + } + self.paused = YES; + [_timer invalidate]; + _timer = nil; + [_eventQueue removeAllObjects]; + _data = nil; + [_session invalidateAndCancel]; + _session = nil; + + [self validateUpdatingLocation]; +} + +- (void)stopUpdatingLocation { + [_locationManager stopUpdatingLocation]; + + // -[CLLocationManager stopMonitoringVisits] is only available in iOS 8+. + if ([_locationManager respondsToSelector:@selector(stopMonitoringVisits)]) { + [_locationManager stopMonitoringVisits]; + } + + _locationManager = nil; +} + ++ (void)resumeMetricsCollection { + [[MGLMapboxEvents sharedManager] resumeMetricsCollection]; +} + +// Must be called from the main thread. +// +- (void)resumeMetricsCollection { + MGLAssertIsMainThread(); + if (!self.paused || ![[self class] isEnabled]) { + return; + } + self.paused = NO; + _data = [[MGLMapboxEventsData alloc] init]; + _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]; + + [self validateUpdatingLocation]; +} + +- (void)startUpdatingLocation { + MGLAssertIsMainThread(); + if (_locationManager || _paused) { + NSAssert(!(_locationManager && _paused), + @"MGLMapboxEvents should not have a CLLocationManager while paused."); + return; + } + _locationManager = [[CLLocationManager alloc] init]; + _locationManager.desiredAccuracy = kCLLocationAccuracyKilometer; + _locationManager.distanceFilter = 10; + _locationManager.delegate = self; + + [_locationManager startUpdatingLocation]; + + // -[CLLocationManager startMonitoringVisits] is only available in iOS 8+. + if ([_locationManager respondsToSelector:@selector(startMonitoringVisits)]) { + [_locationManager startMonitoringVisits]; + } +} + +- (void) pushTurnstileEvent { + + __weak MGLMapboxEvents *weakSelf = self; + + dispatch_async(_serialQueue, ^{ + + MGLMapboxEvents *strongSelf = weakSelf; + + if ( ! strongSelf) return; + + // Build only IDFV event + NSString *vid = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + NSDictionary *vevt = @{ + @"event" : MGLEventTypeAppUserTurnstile, + @"created" : [strongSelf.rfc3339DateFormatter stringFromDate:[NSDate date]], + @"appBundleId" : strongSelf.appBundleId, + @"vendorId": vid, + @"version": @(version), + @"instance": strongSelf.instanceID + }; + + // Add to Queue + [_eventQueue addObject:vevt]; + + // Flush + [strongSelf flush]; + }); +} + +// Can be called from any thread. Can be called rapidly from +// the UI thread, so performance is paramount. +// ++ (void) pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + [[MGLMapboxEvents sharedManager] pushEvent:event withAttributes:attributeDictionary]; + }); +} + +// Can be called from any thread. Called implicitly from public +// use of +pushEvent:withAttributes:. +// +- (void) pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary { + __weak MGLMapboxEvents *weakSelf = self; + + dispatch_async(_serialQueue, ^{ + + MGLMapboxEvents *strongSelf = weakSelf; + + if ( ! strongSelf) return; + + // Metrics Collection Has Been Paused + if (_paused) { + return; + } + + if (!event) return; + + MGLMutableMapboxEventAttributes *evt = [MGLMutableMapboxEventAttributes dictionaryWithDictionary:attributeDictionary]; + // mapbox-events stock attributes + [evt setObject:event forKey:@"event"]; + [evt setObject:@(version) forKey:@"version"]; + [evt setObject:[strongSelf.rfc3339DateFormatter stringFromDate:[NSDate date]] forKey:@"created"]; + [evt setObject:strongSelf.instanceID forKey:@"instance"]; + [evt setObject:strongSelf.data.advertiserId forKey:@"advertiserId"]; + [evt setObject:strongSelf.data.vendorId forKey:@"vendorId"]; + [evt setObject:strongSelf.appBundleId forKeyedSubscript:@"appBundleId"]; + + // mapbox-events-ios stock attributes + [evt setValue:strongSelf.data.model forKey:@"model"]; + [evt setValue:strongSelf.data.iOSVersion forKey:@"operatingSystem"]; + [evt setValue:[strongSelf deviceOrientation] forKey:@"orientation"]; + [evt setValue:@((int)(100 * [UIDevice currentDevice].batteryLevel)) forKey:@"batteryLevel"]; + [evt setValue:@(strongSelf.data.scale) forKey:@"resolution"]; + [evt setValue:strongSelf.data.carrier forKey:@"carrier"]; + + NSString *cell = [strongSelf currentCellularNetworkConnectionType]; + if (cell) { + [evt setValue:cell forKey:@"cellularNetworkType"]; + } else { + [evt setObject:[NSNull null] forKey:@"cellularNetworkType"]; + } + + NSString *wifi = [strongSelf wifiNetworkName]; + if (wifi) { + [evt setValue:wifi forKey:@"wifi"]; + } else { + [evt setObject:[NSNull null] forKey:@"wifi"]; + } + + [evt setValue:@([strongSelf contentSizeScale]) forKey:@"accessibilityFontScale"]; + + // Make Immutable Version + NSDictionary *finalEvent = [NSDictionary dictionaryWithDictionary:evt]; + + // Put On The Queue + [_eventQueue addObject:finalEvent]; + + // Has Flush Limit Been Reached? + if (_eventQueue.count >= MGLMaximumEventsPerFlush) { + [strongSelf flush]; + } else if (_eventQueue.count == 1) { + // If this is first new event on queue start timer, + [strongSelf startTimer]; + } + }); +} + +// Can be called from any thread. +// ++ (void) flush { + [[MGLMapboxEvents sharedManager] flush]; +} + +// Can be called from any thread. +// +- (void) flush { + if ([MGLAccountManager accessToken] == nil) return; + + __weak MGLMapboxEvents *weakSelf = self; + + dispatch_async(_serialQueue, ^{ + MGLMapboxEvents *strongSelf = weakSelf; + if ( ! strongSelf || [_eventQueue count] == 0) return; + + // Make an immutable copy + NSArray *events = [NSArray arrayWithArray:_eventQueue]; + + // Update Queue to remove events sent to server + [_eventQueue removeAllObjects]; + + // Send Array of Events to Server + [strongSelf postEvents:events]; + + // Cancel Any Timer That May Running + if (strongSelf.timer) { + [strongSelf.timer invalidate]; + strongSelf.timer = nil; + } + }); +} + +// Can be called from any thread. Called implicitly from public +// use of +flush. Posts an async network request to upload metrics. +// +- (void) postEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events { + __weak MGLMapboxEvents *weakSelf = self; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + MGLMapboxEvents *strongSelf = weakSelf; + if (!strongSelf) return; + + // Setup URL Request + NSString *url = [NSString stringWithFormat:@"%@/events/v1?access_token=%@", MGLMapboxEventsAPIBase, [MGLAccountManager accessToken]]; + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]]; + [request setValue:strongSelf.userAgent forHTTPHeaderField:@"User-Agent"]; + [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; + [request setHTTPMethod:@"POST"]; + + // Convert Array of Dictionaries to JSON + if ([NSJSONSerialization isValidJSONObject:events]) { + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:events options:NSJSONWritingPrettyPrinted error:nil]; + [request setHTTPBody:jsonData]; + + // Send non blocking HTTP Request to server + [[_session dataTaskWithRequest:request] resume]; + } + }); +} + +// Can be called from any thread. +// +- (void) startTimer { + void (^timerBlock)() = ^{ + // Stop Timer if it already exists + [_timer invalidate]; + + // Start New Timer + _timer = [NSTimer scheduledTimerWithTimeInterval:MGLFlushInterval + target:self + selector:@selector(flush) + userInfo:nil + repeats:YES]; + }; + + if ( ! [[NSThread currentThread] isMainThread]) { + dispatch_sync(dispatch_get_main_queue(), ^{ + timerBlock(); + }); + } else { + timerBlock(); + } +} + +// Can be called from any thread. +// +- (NSString *) userAgent { + return [NSString stringWithFormat:@"%@/%@/%@ %@", self.appName, self.appVersion, self.appBuildNumber, MGLMapboxEventsUserAgent]; +} + +// Can be called from any thread. +// +- (NSString *) deviceOrientation { + __block NSString *result; + + NSString *(^deviceOrientationBlock)(void) = ^{ + switch ([UIDevice currentDevice].orientation) { + case UIDeviceOrientationUnknown: + result = @"Unknown"; + break; + case UIDeviceOrientationPortrait: + result = @"Portrait"; + break; + case UIDeviceOrientationPortraitUpsideDown: + result = @"PortraitUpsideDown"; + break; + case UIDeviceOrientationLandscapeLeft: + result = @"LandscapeLeft"; + break; + case UIDeviceOrientationLandscapeRight: + result = @"LandscapeRight"; + break; + case UIDeviceOrientationFaceUp: + result = @"FaceUp"; + break; + case UIDeviceOrientationFaceDown: + result = @"FaceDown"; + break; + default: + result = @"Default - Unknown"; + break; + } + + return result; + }; + + if ( ! [[NSThread currentThread] isMainThread]) { + dispatch_sync(dispatch_get_main_queue(), ^{ + result = deviceOrientationBlock(); + }); + } else { + result = deviceOrientationBlock(); + } + + return result; +} + +// Can be called from any thread. +// +- (NSInteger) contentSizeScale { + __block NSInteger result = -9999; + + NSInteger (^contentSizeScaleBlock)(void) = ^{ + NSString *sc = [UIApplication sharedApplication].preferredContentSizeCategory; + + if ([sc isEqualToString:UIContentSizeCategoryExtraSmall]) { + result = -3; + } else if ([sc isEqualToString:UIContentSizeCategorySmall]) { + result = -2; + } else if ([sc isEqualToString:UIContentSizeCategoryMedium]) { + result = -1; + } else if ([sc isEqualToString:UIContentSizeCategoryLarge]) { + result = 0; + } else if ([sc isEqualToString:UIContentSizeCategoryExtraLarge]) { + result = 1; + } else if ([sc isEqualToString:UIContentSizeCategoryExtraExtraLarge]) { + result = 2; + } else if ([sc isEqualToString:UIContentSizeCategoryExtraExtraExtraLarge]) { + result = 3; + } else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityMedium]) { + result = -11; + } else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityLarge]) { + result = 10; + } else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityExtraLarge]) { + result = 11; + } else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityExtraExtraLarge]) { + result = 12; + } else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityExtraExtraExtraLarge]) { + result = 13; + } + + return result; + }; + + if ( ! [[NSThread currentThread] isMainThread]) { + dispatch_sync(dispatch_get_main_queue(), ^{ + result = contentSizeScaleBlock(); + }); + } else { + result = contentSizeScaleBlock(); + } + + return result; +} + +// Can be called from any thread. +// +- (NSString *) wifiNetworkName { + + NSString *ssid = nil; + CFArrayRef interfaces = CNCopySupportedInterfaces(); + if (interfaces) { + NSDictionary *info = CFBridgingRelease(CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(interfaces, 0))); + if (info) { + ssid = info[@"SSID"]; + } + CFRelease(interfaces); + } + + return ssid; +} + +// Can be called from any thread. +// +- (NSString *) currentCellularNetworkConnectionType { + CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init]; + NSString *radioTech = telephonyInfo.currentRadioAccessTechnology; + + if (radioTech == nil) { + return nil; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyGPRS]) { + return @"GPRS"; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyEdge]) { + return @"EDGE"; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyWCDMA]) { + return @"WCDMA"; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyHSDPA]) { + return @"HSDPA"; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyHSUPA]) { + return @"HSUPA"; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyCDMA1x]) { + return @"CDMA1x"; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0]) { + return @"CDMAEVDORev0"; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA]) { + return @"CDMAEVDORevA"; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB]) { + return @"CDMAEVDORevB"; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyeHRPD]) { + return @"HRPD"; + } else if ([radioTech isEqualToString:CTRadioAccessTechnologyLTE]) { + return @"LTE"; + } else { + return @"Unknown"; + } +} + +// Can be called from any thread. +// ++ (BOOL) checkPushEnabled { + BOOL (^pushCheckBlock)(void) = ^{ + BOOL blockResult; + if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) { + // iOS 8+ + blockResult = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications]; + } else { + // iOS 7 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes]; + blockResult = (types == UIRemoteNotificationTypeNone) ? NO : YES; +#pragma clang diagnostic pop + } + return blockResult; + }; + + __block BOOL result; + + if ( ! [[NSThread currentThread] isMainThread]) { + dispatch_sync(dispatch_get_main_queue(), ^{ + result = pushCheckBlock(); + }); + } else { + result = pushCheckBlock(); + } + + return result; +} + +#pragma mark CLLocationManagerDelegate +- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { + // Iterate through locations to pass all data + for (CLLocation *loc in locations) { + [MGLMapboxEvents pushEvent:MGLEventTypeLocation withAttributes:@{ + MGLEventKeyLatitude: @(loc.coordinate.latitude), + MGLEventKeyLongitude: @(loc.coordinate.longitude), + MGLEventKeySpeed: @(loc.speed), + MGLEventKeyCourse: @(loc.course), + MGLEventKeyAltitude: @(loc.altitude), + MGLEventKeyHorizontalAccuracy: @(loc.horizontalAccuracy), + MGLEventKeyVerticalAccuracy: @(loc.verticalAccuracy) + }]; + } +} + +- (void)locationManager:(CLLocationManager *)manager didVisit:(CLVisit *)visit { + [MGLMapboxEvents pushEvent:MGLEventTypeVisit withAttributes:@{ + MGLEventKeyLatitude: @(visit.coordinate.latitude), + MGLEventKeyLongitude: @(visit.coordinate.longitude), + MGLEventKeyHorizontalAccuracy: @(visit.horizontalAccuracy), + MGLEventKeyArrivalDate: [[NSDate distantPast] isEqualToDate:visit.arrivalDate] ? [NSNull null] : [_rfc3339DateFormatter stringFromDate:visit.arrivalDate], + MGLEventKeyDepartureDate: [[NSDate distantFuture] isEqualToDate:visit.departureDate] ? [NSNull null] : [_rfc3339DateFormatter stringFromDate:visit.departureDate] + }]; +} + +- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { + [self validateUpdatingLocation]; +} + +#pragma mark NSURLSessionDelegate +- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^) (NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { + + if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + + SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust]; + SecTrustResultType trustResult; + + // Validate the certificate chain with the device's trust store anyway + // This *might* give use revocation checking + SecTrustEvaluate(serverTrust, &trustResult); + if (trustResult == kSecTrustResultUnspecified) + { + // Look for a pinned certificate in the server's certificate chain + long numKeys = SecTrustGetCertificateCount(serverTrust); + + BOOL found = NO; + // Try GeoTrust Cert First + for (int lc = 0; lc < numKeys; lc++) { + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc); + NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate)); + + // Compare Remote Key With Local Version + if ([remoteCertificateData isEqualToData:_geoTrustCert]) { + // Found the certificate; continue connecting + completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + found = YES; + break; + } + } + + if (!found) { + // Fallback to Digicert Cert + for (int lc = 0; lc < numKeys; lc++) { + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc); + NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate)); + + // Compare Remote Key With Local Version + if ([remoteCertificateData isEqualToData:_digicertCert]) { + // Found the certificate; continue connecting + completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + found = YES; + break; + } + } + + if (!found && _usesTestServer) { + // See if this is test server + for (int lc = 0; lc < numKeys; lc++) { + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc); + NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate)); + + // Compare Remote Key With Local Version + if ([remoteCertificateData isEqualToData:_testServerCert]) { + // Found the certificate; continue connecting + completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + found = YES; + break; + } + } + } + + if (!found) { + // The certificate wasn't found in GeoTrust nor Digicert. Cancel the connection. + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + } + } + } + else + { + // Certificate chain validation failed; cancel the connection + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + } + } + +} + +@end diff --git a/platform/ios/MGLMultiPoint.mm b/platform/ios/MGLMultiPoint.mm new file mode 100644 index 000000000..624c1658a --- /dev/null +++ b/platform/ios/MGLMultiPoint.mm @@ -0,0 +1,102 @@ +#import "MGLMultiPoint.h" +#import "MGLGeometry.h" + +#import + +@implementation MGLMultiPoint +{ + CLLocationCoordinate2D *_coords; + size_t _count; + mbgl::LatLngBounds _bounds; +} + +- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords + count:(NSUInteger)count +{ + self = [super init]; + + if (self) + { + _count = count; + _coords = (CLLocationCoordinate2D *)malloc(_count * sizeof(CLLocationCoordinate2D)); + + for (NSUInteger i = 0; i < _count; i++) + { + _coords[i] = coords[i]; + _bounds.extend(mbgl::LatLng(coords[i].latitude, coords[i].longitude)); + } + } + + return self; +} + +- (void)dealloc +{ + free(_coords); +} + +- (CLLocationCoordinate2D)coordinate +{ + if ([self isMemberOfClass:[MGLMultiPoint class]]) + { + [[NSException exceptionWithName:@"MGLAbstractClassException" + reason:@"MGLMultiPoint is an abstract class" + userInfo:nil] raise]; + } + + assert(_count > 0); + + return CLLocationCoordinate2DMake(_coords[0].latitude, _coords[0].longitude); +} + +- (NSUInteger)pointCount +{ + if ([self isMemberOfClass:[MGLMultiPoint class]]) + { + [[NSException exceptionWithName:@"MGLAbstractClassException" + reason:@"MGLMultiPoint is an abstract class" + userInfo:nil] raise]; + } + + return _count; +} + +- (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range +{ + if ([self isMemberOfClass:[MGLMultiPoint class]]) + { + [[NSException exceptionWithName:@"MGLAbstractClassException" + reason:@"MGLMultiPoint is an abstract class" + userInfo:nil] raise]; + } + + assert(range.location + range.length <= _count); + + NSUInteger index = 0; + + for (NSUInteger i = range.location; i < range.location + range.length; i++) + { + coords[index] = _coords[i]; + index++; + } +} + +- (MGLCoordinateBounds)overlayBounds +{ + return { + CLLocationCoordinate2DMake(_bounds.sw.latitude, _bounds.sw.longitude), + CLLocationCoordinate2DMake(_bounds.ne.latitude, _bounds.ne.longitude) + }; +} + +- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds +{ + mbgl::LatLngBounds area( + mbgl::LatLng(overlayBounds.sw.latitude, overlayBounds.sw.longitude), + mbgl::LatLng(overlayBounds.ne.latitude, overlayBounds.ne.longitude) + ); + + return _bounds.intersects(area); +} + +@end diff --git a/platform/ios/MGLMultiPoint_Private.h b/platform/ios/MGLMultiPoint_Private.h new file mode 100644 index 000000000..a1a70a677 --- /dev/null +++ b/platform/ios/MGLMultiPoint_Private.h @@ -0,0 +1,8 @@ +#import "MGLMultiPoint.h" + +@interface MGLMultiPoint (Private) + +- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; +- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds; + +@end diff --git a/platform/ios/MGLPointAnnotation.m b/platform/ios/MGLPointAnnotation.m new file mode 100644 index 000000000..13fbba108 --- /dev/null +++ b/platform/ios/MGLPointAnnotation.m @@ -0,0 +1,7 @@ +#import "MGLPointAnnotation.h" + +@implementation MGLPointAnnotation + +@synthesize coordinate; + +@end diff --git a/platform/ios/MGLPolygon.m b/platform/ios/MGLPolygon.m new file mode 100644 index 000000000..770a2a4b9 --- /dev/null +++ b/platform/ios/MGLPolygon.m @@ -0,0 +1,15 @@ +#import "MGLPolygon.h" + +#import "MGLMultiPoint_Private.h" + +@implementation MGLPolygon + +@dynamic overlayBounds; + ++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords + count:(NSUInteger)count +{ + return [[self alloc] initWithCoordinates:coords count:count]; +} + +@end diff --git a/platform/ios/MGLPolyline.m b/platform/ios/MGLPolyline.m new file mode 100644 index 000000000..bcd652e0d --- /dev/null +++ b/platform/ios/MGLPolyline.m @@ -0,0 +1,15 @@ +#import "MGLPolyline.h" + +#import "MGLMultiPoint_Private.h" + +@implementation MGLPolyline + +@dynamic overlayBounds; + ++ (instancetype)polylineWithCoordinates:(CLLocationCoordinate2D *)coords + count:(NSUInteger)count +{ + return [[self alloc] initWithCoordinates:coords count:count]; +} + +@end diff --git a/platform/ios/MGLShape.m b/platform/ios/MGLShape.m new file mode 100644 index 000000000..e3d92c38c --- /dev/null +++ b/platform/ios/MGLShape.m @@ -0,0 +1,14 @@ +#import "MGLShape.h" + +@implementation MGLShape + +- (CLLocationCoordinate2D)coordinate +{ + [[NSException exceptionWithName:@"MGLAbstractClassException" + reason:@"MGLShape is an abstract class" + userInfo:nil] raise]; + + return CLLocationCoordinate2DMake(MAXFLOAT, MAXFLOAT); +} + +@end diff --git a/platform/ios/MGLTypes.m b/platform/ios/MGLTypes.m new file mode 100644 index 000000000..01e9a1467 --- /dev/null +++ b/platform/ios/MGLTypes.m @@ -0,0 +1,3 @@ +#import "MGLTypes.h" + +NSString * const MGLErrorDomain = @"MGLErrorDomain"; diff --git a/platform/ios/MGLUserLocation.m b/platform/ios/MGLUserLocation.m new file mode 100644 index 000000000..36d71c13b --- /dev/null +++ b/platform/ios/MGLUserLocation.m @@ -0,0 +1,74 @@ +#import "MGLUserLocation_Private.h" + +#import "MGLMapView.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLUserLocation () + +@property (nonatomic, weak) MGLMapView *mapView; + +@end + +NS_ASSUME_NONNULL_END + +@implementation MGLUserLocation + +- (instancetype)initWithMapView:(MGLMapView *)mapView +{ + if (self = [super init]) + { + _location = [[CLLocation alloc] initWithLatitude:MAXFLOAT longitude:MAXFLOAT]; + _mapView = mapView; + } + + return self; +} + ++ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key +{ + return ! [key isEqualToString:@"location"] && ! [key isEqualToString:@"heading"]; +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCoordinate +{ + return [NSSet setWithObject:@"location"]; +} + +- (void)setLocation:(CLLocation *)newLocation +{ + if ( ! newLocation || ! CLLocationCoordinate2DIsValid(newLocation.coordinate)) return; + if ( _location && CLLocationCoordinate2DIsValid(_location.coordinate) && [newLocation distanceFromLocation:_location] == 0) return; + if (newLocation.coordinate.latitude == 0 && newLocation.coordinate.longitude == 0) return; + + [self willChangeValueForKey:@"location"]; + _location = newLocation; + [self didChangeValueForKey:@"location"]; +} + +- (BOOL)isUpdating +{ + return self.mapView.userTrackingMode != MGLUserTrackingModeNone; +} + +- (void)setHeading:(CLHeading *)newHeading +{ + if (newHeading.trueHeading != _heading.trueHeading) + { + [self willChangeValueForKey:@"heading"]; + _heading = newHeading; + [self didChangeValueForKey:@"heading"]; + } +} + +- (CLLocationCoordinate2D)coordinate +{ + return self.location.coordinate; +} + +- (NSString *)title +{ + return (_title ? _title : @"You Are Here"); +} + +@end diff --git a/platform/ios/MGLUserLocationAnnotationView.h b/platform/ios/MGLUserLocationAnnotationView.h new file mode 100644 index 000000000..1eb50b774 --- /dev/null +++ b/platform/ios/MGLUserLocationAnnotationView.h @@ -0,0 +1,23 @@ +#import +#import + +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@class MGLMapView; +@class MGLUserLocation; + +/** View representing an MGLUserLocation on screen. */ +@interface MGLUserLocationAnnotationView : UIView + +@property (nonatomic, weak) MGLMapView *mapView; +@property (nonatomic) MGLUserLocation *annotation; +@property (nonatomic, readonly, nullable) CALayer *haloLayer; + +- (instancetype)initInMapView:(MGLMapView *)mapView NS_DESIGNATED_INITIALIZER; +- (void)setupLayers; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/ios/MGLUserLocationAnnotationView.m b/platform/ios/MGLUserLocationAnnotationView.m new file mode 100644 index 000000000..7733674e6 --- /dev/null +++ b/platform/ios/MGLUserLocationAnnotationView.m @@ -0,0 +1,334 @@ +#import "MGLUserLocationAnnotationView.h" + +#import "MGLUserLocation.h" +#import "MGLUserLocation_Private.h" +#import "MGLAnnotation.h" +#import "MGLMapView.h" + +const CGFloat MGLUserLocationAnnotationDotSize = 22.0; +const CGFloat MGLUserLocationAnnotationHaloSize = 115.0; + +@interface MGLUserLocationAnnotationView () + +@property (nonatomic, readwrite) CALayer *haloLayer; + +@end + +#pragma mark - + +@implementation MGLUserLocationAnnotationView +{ + CALayer *_headingIndicatorLayer; + CAShapeLayer *_headingIndicatorMaskLayer; + CALayer *_accuracyRingLayer; + CALayer *_dotBorderLayer; + CALayer *_dotLayer; + + double _oldHeadingAccuracy; + CLLocationAccuracy _oldHorizontalAccuracy; + double _oldZoom; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + NSAssert(NO, @"No containing map view specified. Call -initInMapView: instead."); + return self = [self init]; +} + +- (instancetype)initInMapView:(MGLMapView *)mapView +{ + if (self = [super initWithFrame:CGRectMake(0, 0, MGLUserLocationAnnotationDotSize, MGLUserLocationAnnotationDotSize)]) + { + self.annotation = [[MGLUserLocation alloc] initWithMapView:mapView]; + _mapView = mapView; + [self setupLayers]; + self.accessibilityLabel = @"User location"; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)decoder +{ + MGLMapView *mapView = [decoder valueForKey:@"mapView"]; + return [self initInMapView:mapView]; +} + +- (void)setTintColor:(UIColor *)tintColor +{ + if (_accuracyRingLayer) + { + _accuracyRingLayer.backgroundColor = [tintColor CGColor]; + } + + _haloLayer.backgroundColor = [tintColor CGColor]; + _dotLayer.backgroundColor = [tintColor CGColor]; + + _headingIndicatorLayer.contents = (__bridge id)[[self headingIndicatorTintedGradientImage] CGImage]; +} + +- (void)setupLayers +{ + if (CLLocationCoordinate2DIsValid(self.annotation.coordinate)) + { + // update heading indicator + // + if (_headingIndicatorLayer) + { + _headingIndicatorLayer.hidden = !(_mapView.userTrackingMode == MGLUserTrackingModeFollowWithHeading || + _mapView.userTrackingMode == MGLUserTrackingModeFollowWithCourse); + + if (_oldHeadingAccuracy != self.annotation.heading.headingAccuracy) + { + // recalculate the clipping mask based on updated accuracy + _headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath]; + + _oldHeadingAccuracy = self.annotation.heading.headingAccuracy; + } + } + + // heading indicator (tinted, semi-circle) + // + if ( ! _headingIndicatorLayer && self.annotation.heading.headingAccuracy) + { + CGFloat headingIndicatorSize = MGLUserLocationAnnotationHaloSize; + + _headingIndicatorLayer = [CALayer layer]; + _headingIndicatorLayer.bounds = CGRectMake(0, 0, headingIndicatorSize, headingIndicatorSize); + _headingIndicatorLayer.position = CGPointMake(super.bounds.size.width / 2.0, super.bounds.size.height / 2.0); + _headingIndicatorLayer.contents = (__bridge id)[[self headingIndicatorTintedGradientImage] CGImage]; + _headingIndicatorLayer.contentsGravity = kCAGravityBottom; + _headingIndicatorLayer.contentsScale = [UIScreen mainScreen].scale; + _headingIndicatorLayer.opacity = 0.4; + _headingIndicatorLayer.shouldRasterize = YES; + _headingIndicatorLayer.rasterizationScale = [UIScreen mainScreen].scale; + _headingIndicatorLayer.drawsAsynchronously = YES; + + [self.layer insertSublayer:_headingIndicatorLayer below:_dotBorderLayer]; + } + + // heading indicator accuracy mask (fan-shaped) + // + if ( ! _headingIndicatorMaskLayer && self.annotation.heading.headingAccuracy) + { + _headingIndicatorMaskLayer = [CAShapeLayer layer]; + _headingIndicatorMaskLayer.frame = _headingIndicatorLayer.bounds; + _headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath]; + + // apply the mask to the halo-radius-sized gradient layer + _headingIndicatorLayer.mask = _headingIndicatorMaskLayer; + + _oldHeadingAccuracy = self.annotation.heading.headingAccuracy; + } + + // update accuracy ring (if zoom or horizontal accuracy have changed) + // + if (_accuracyRingLayer && (_oldZoom != self.mapView.zoomLevel || _oldHorizontalAccuracy != self.annotation.location.horizontalAccuracy)) + { + CGFloat accuracyRingSize = [self calculateAccuracyRingSize]; + + // only show the accuracy ring if it won't be obscured by the location dot + if (accuracyRingSize > MGLUserLocationAnnotationDotSize + 15) + { + _accuracyRingLayer.hidden = NO; + _accuracyRingLayer.bounds = CGRectMake(0, 0, accuracyRingSize, accuracyRingSize); + _accuracyRingLayer.cornerRadius = accuracyRingSize / 2; + + // match the halo to the accuracy ring + _haloLayer.bounds = _accuracyRingLayer.bounds; + _haloLayer.cornerRadius = _accuracyRingLayer.cornerRadius; + _haloLayer.shouldRasterize = NO; + } + else + { + _accuracyRingLayer.hidden = YES; + + _haloLayer.bounds = CGRectMake(0, 0, MGLUserLocationAnnotationHaloSize, MGLUserLocationAnnotationHaloSize); + _haloLayer.cornerRadius = MGLUserLocationAnnotationHaloSize / 2.0; + _haloLayer.shouldRasterize = YES; + _haloLayer.rasterizationScale = [UIScreen mainScreen].scale; + } + + // store accuracy and zoom so we're not redrawing unchanged location updates + _oldHorizontalAccuracy = self.annotation.location.horizontalAccuracy; + _oldZoom = self.mapView.zoomLevel; + } + + // accuracy ring (circular, tinted, mostly-transparent) + // + if ( ! _accuracyRingLayer && self.annotation.location.horizontalAccuracy) + { + CGFloat accuracyRingSize = [self calculateAccuracyRingSize]; + _accuracyRingLayer = [self circleLayerWithSize:accuracyRingSize]; + _accuracyRingLayer.backgroundColor = [_mapView.tintColor CGColor]; + _accuracyRingLayer.opacity = 0.1; + _accuracyRingLayer.shouldRasterize = NO; + _accuracyRingLayer.allowsGroupOpacity = NO; + + [self.layer addSublayer:_accuracyRingLayer]; + } + + // expanding sonar-like pulse (circular, tinted, fades out) + // + if ( ! _haloLayer) + { + _haloLayer = [self circleLayerWithSize:MGLUserLocationAnnotationHaloSize]; + _haloLayer.backgroundColor = [_mapView.tintColor CGColor]; + _haloLayer.allowsGroupOpacity = NO; + + // set defaults for the animations + CAAnimationGroup *animationGroup = [self loopingAnimationGroupWithDuration:3.0]; + + // scale out radially with initial acceleration + CAKeyframeAnimation *boundsAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.xy"]; + boundsAnimation.values = @[@0, @0.35, @1]; + boundsAnimation.keyTimes = @[@0, @0.2, @1]; + + // go transparent as scaled out, start semi-opaque + CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; + opacityAnimation.values = @[@0.4, @0.4, @0]; + opacityAnimation.keyTimes = @[@0, @0.2, @1]; + + animationGroup.animations = @[boundsAnimation, opacityAnimation]; + + [_haloLayer addAnimation:animationGroup forKey:@"animateTransformAndOpacity"]; + + [self.layer addSublayer:_haloLayer]; + } + + // background dot (white with black shadow) + // + if ( ! _dotBorderLayer) + { + _dotBorderLayer = [self circleLayerWithSize:MGLUserLocationAnnotationDotSize]; + _dotBorderLayer.backgroundColor = [[UIColor whiteColor] CGColor]; + _dotBorderLayer.shadowColor = [[UIColor blackColor] CGColor]; + _dotBorderLayer.shadowOffset = CGSizeMake(0, 0); + _dotBorderLayer.shadowRadius = 3; + _dotBorderLayer.shadowOpacity = 0.25; + + [self.layer addSublayer:_dotBorderLayer]; + } + + // inner dot (pulsing, tinted) + // + if ( ! _dotLayer) + { + _dotLayer = [self circleLayerWithSize:MGLUserLocationAnnotationDotSize * 0.75]; + _dotLayer.backgroundColor = [_mapView.tintColor CGColor]; + _dotLayer.shouldRasterize = NO; + + // set defaults for the animations + CAAnimationGroup *animationGroup = [self loopingAnimationGroupWithDuration:1.5]; + animationGroup.autoreverses = YES; + animationGroup.fillMode = kCAFillModeBoth; + + // scale the dot up and down + CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.xy"]; + pulseAnimation.fromValue = @0.8; + pulseAnimation.toValue = @1; + + // fade opacity in and out, subtly + CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; + opacityAnimation.fromValue = @0.8; + opacityAnimation.toValue = @1; + + animationGroup.animations = @[pulseAnimation, opacityAnimation]; + + [_dotLayer addAnimation:animationGroup forKey:@"animateTransformAndOpacity"]; + + [self.layer addSublayer:_dotLayer]; + } + } +} + +- (CALayer *)circleLayerWithSize:(CGFloat)layerSize +{ + CALayer *circleLayer = [CALayer layer]; + circleLayer.bounds = CGRectMake(0, 0, layerSize, layerSize); + circleLayer.position = CGPointMake(super.bounds.size.width / 2.0, super.bounds.size.height / 2.0); + circleLayer.cornerRadius = layerSize / 2.0; + circleLayer.shouldRasterize = YES; + circleLayer.rasterizationScale = [UIScreen mainScreen].scale; + circleLayer.drawsAsynchronously = YES; + + return circleLayer; +} + +- (CAAnimationGroup *)loopingAnimationGroupWithDuration:(CGFloat)animationDuration +{ + CAAnimationGroup *animationGroup = [CAAnimationGroup animation]; + animationGroup.duration = animationDuration; + animationGroup.repeatCount = INFINITY; + animationGroup.removedOnCompletion = NO; + animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; + + return animationGroup; +} + +- (CGFloat)calculateAccuracyRingSize +{ + CGFloat latRadians = self.annotation.coordinate.latitude * M_PI / 180.0f; + CGFloat pixelRadius = self.annotation.location.horizontalAccuracy / cos(latRadians) / [self.mapView metersPerPixelAtLatitude:self.annotation.coordinate.latitude]; + + return pixelRadius * 2; +} + +- (UIImage *)headingIndicatorTintedGradientImage +{ + UIImage *image; + + CGFloat haloRadius = MGLUserLocationAnnotationHaloSize / 2.0; + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(MGLUserLocationAnnotationHaloSize, haloRadius), NO, 0); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = UIGraphicsGetCurrentContext(); + + // gradient from the tint color to no-alpha tint color + CGFloat gradientLocations[] = {0.0, 1.0}; + CGGradientRef gradient = CGGradientCreateWithColors( + colorSpace, (__bridge CFArrayRef)@[(id)[_mapView.tintColor CGColor], + (id)[[_mapView.tintColor colorWithAlphaComponent:0] CGColor]], gradientLocations); + + // draw the gradient from the center point to the edge (full halo radius) + CGPoint centerPoint = CGPointMake(haloRadius, haloRadius); + CGContextDrawRadialGradient(context, gradient, + centerPoint, 0.0, + centerPoint, haloRadius, + nil); + + image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + CGGradientRelease(gradient); + CGColorSpaceRelease(colorSpace); + + return image; +} + +- (UIBezierPath *)headingIndicatorClippingMask +{ + CGFloat accuracy = self.annotation.heading.headingAccuracy; + + // size the mask using exagerated accuracy, but keep within a good display range + CGFloat clippingDegrees = 90 - (accuracy * 1.5); + clippingDegrees = fmin(clippingDegrees, 55); + clippingDegrees = fmax(clippingDegrees, 10); + + CGRect ovalRect = CGRectMake(0, 0, MGLUserLocationAnnotationHaloSize, MGLUserLocationAnnotationHaloSize); + UIBezierPath *ovalPath = UIBezierPath.bezierPath; + + // clip the oval to ± incoming accuracy degrees (converted to radians), from the top + [ovalPath addArcWithCenter:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect)) + radius:CGRectGetWidth(ovalRect) / 2.0 + startAngle:(-180 + clippingDegrees) * M_PI / 180 + endAngle:-clippingDegrees * M_PI / 180 + clockwise:YES]; + + [ovalPath addLineToPoint:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))]; + [ovalPath closePath]; + + return ovalPath; +} + +@end diff --git a/platform/ios/MGLUserLocation_Private.h b/platform/ios/MGLUserLocation_Private.h new file mode 100644 index 000000000..892ddfa47 --- /dev/null +++ b/platform/ios/MGLUserLocation_Private.h @@ -0,0 +1,17 @@ +#import "MGLUserLocation.h" + +NS_ASSUME_NONNULL_BEGIN + +@class MGLMapView; + +@interface MGLUserLocation (Private) + +@property (nonatomic, weak) MGLMapView *mapView; +@property (nonatomic, readwrite, nullable) CLLocation *location; +@property (nonatomic, readwrite, nullable) CLHeading *heading; + +- (instancetype)initWithMapView:(MGLMapView *)mapView; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/ios/NSBundle+MGLAdditions.h b/platform/ios/NSBundle+MGLAdditions.h new file mode 100644 index 000000000..0de96bf31 --- /dev/null +++ b/platform/ios/NSBundle+MGLAdditions.h @@ -0,0 +1,11 @@ +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface NSBundle (MGLAdditions) + ++ (NSString *)mgl_resourceBundlePath; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/ios/NSBundle+MGLAdditions.m b/platform/ios/NSBundle+MGLAdditions.m new file mode 100644 index 000000000..d8ba7dacc --- /dev/null +++ b/platform/ios/NSBundle+MGLAdditions.m @@ -0,0 +1,16 @@ +#import "NSBundle+MGLAdditions.h" + +#import "MGLMapView.h" + +@implementation NSBundle (MGLAdditions) + ++ (NSString *)mgl_resourceBundlePath +{ + NSString *resourceBundlePath = [[NSBundle bundleForClass:[MGLMapView class]] pathForResource:@"Mapbox" ofType:@"bundle"]; + + if ( ! resourceBundlePath) resourceBundlePath = [[NSBundle mainBundle] bundlePath]; + + return resourceBundlePath; +} + +@end diff --git a/platform/ios/NSException+MGLAdditions.h b/platform/ios/NSException+MGLAdditions.h new file mode 100644 index 000000000..f75b54c15 --- /dev/null +++ b/platform/ios/NSException+MGLAdditions.h @@ -0,0 +1,3 @@ +#import + +#define MGLAssertIsMainThread() NSAssert([[NSThread currentThread] isMainThread], @"%s must be accessed on the main thread, not %@", __PRETTY_FUNCTION__, [NSThread currentThread]) diff --git a/platform/ios/NSProcessInfo+MGLAdditions.h b/platform/ios/NSProcessInfo+MGLAdditions.h new file mode 100644 index 000000000..a117f3b76 --- /dev/null +++ b/platform/ios/NSProcessInfo+MGLAdditions.h @@ -0,0 +1,7 @@ +#import + +@interface NSProcessInfo (MGLAdditions) + +- (BOOL)mgl_isInterfaceBuilderDesignablesAgent; + +@end diff --git a/platform/ios/NSProcessInfo+MGLAdditions.m b/platform/ios/NSProcessInfo+MGLAdditions.m new file mode 100644 index 000000000..fca183c1f --- /dev/null +++ b/platform/ios/NSProcessInfo+MGLAdditions.m @@ -0,0 +1,10 @@ +#import "NSProcessInfo+MGLAdditions.h" + +@implementation NSProcessInfo (MGLAdditions) + +- (BOOL)mgl_isInterfaceBuilderDesignablesAgent +{ + return [self.processName isEqualToString:@"IBDesignablesAgentCocoaTouch"]; +} + +@end diff --git a/platform/ios/NSString+MGLAdditions.h b/platform/ios/NSString+MGLAdditions.h new file mode 100644 index 000000000..6359576c2 --- /dev/null +++ b/platform/ios/NSString+MGLAdditions.h @@ -0,0 +1,12 @@ +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface NSString (MGLAdditions) + +/** Returns the receiver if non-empty or nil if empty. */ +- (nullable NSString *)mgl_stringOrNilIfEmpty; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/ios/NSString+MGLAdditions.m b/platform/ios/NSString+MGLAdditions.m new file mode 100644 index 000000000..969886651 --- /dev/null +++ b/platform/ios/NSString+MGLAdditions.m @@ -0,0 +1,10 @@ +#import "NSString+MGLAdditions.h" + +@implementation NSString (MGLAdditions) + +- (nullable NSString *)mgl_stringOrNilIfEmpty +{ + return self.length ? self : nil; +} + +@end diff --git a/platform/ios/resources/Compass.png b/platform/ios/resources/Compass.png new file mode 100644 index 000000000..e6b0b52c5 Binary files /dev/null and b/platform/ios/resources/Compass.png differ diff --git a/platform/ios/resources/Compass@2x.png b/platform/ios/resources/Compass@2x.png new file mode 100644 index 000000000..58e7e08d2 Binary files /dev/null and b/platform/ios/resources/Compass@2x.png differ diff --git a/platform/ios/resources/Compass@3x.png b/platform/ios/resources/Compass@3x.png new file mode 100644 index 000000000..470cd3d08 Binary files /dev/null and b/platform/ios/resources/Compass@3x.png differ diff --git a/platform/ios/resources/api_mapbox_com-digicert.der b/platform/ios/resources/api_mapbox_com-digicert.der new file mode 100644 index 000000000..d84cee390 Binary files /dev/null and b/platform/ios/resources/api_mapbox_com-digicert.der differ diff --git a/platform/ios/resources/api_mapbox_com-geotrust.der b/platform/ios/resources/api_mapbox_com-geotrust.der new file mode 100644 index 000000000..116144bc0 Binary files /dev/null and b/platform/ios/resources/api_mapbox_com-geotrust.der differ diff --git a/platform/ios/resources/mapbox.png b/platform/ios/resources/mapbox.png new file mode 100644 index 000000000..5a9da3fe3 Binary files /dev/null and b/platform/ios/resources/mapbox.png differ diff --git a/platform/ios/resources/mapbox@2x.png b/platform/ios/resources/mapbox@2x.png new file mode 100644 index 000000000..194aa64da Binary files /dev/null and b/platform/ios/resources/mapbox@2x.png differ diff --git a/platform/ios/resources/mapbox@3x.png b/platform/ios/resources/mapbox@3x.png new file mode 100644 index 000000000..d1260a16f Binary files /dev/null and b/platform/ios/resources/mapbox@3x.png differ diff --git a/platform/ios/resources/star_tilestream_net.der b/platform/ios/resources/star_tilestream_net.der new file mode 100644 index 000000000..e302cd768 Binary files /dev/null and b/platform/ios/resources/star_tilestream_net.der differ diff --git a/platform/ios/vendor/SMCalloutView b/platform/ios/vendor/SMCalloutView new file mode 160000 index 000000000..717078fb6 --- /dev/null +++ b/platform/ios/vendor/SMCalloutView @@ -0,0 +1 @@ +Subproject commit 717078fb6b0d02b944a12f4d40fc15567489d23b diff --git a/proto/glyphs.proto b/proto/glyphs.proto new file mode 100644 index 000000000..6930b47a2 --- /dev/null +++ b/proto/glyphs.proto @@ -0,0 +1,33 @@ +// Protocol Version 1 + +package mapboxgl.glyphs; + +option optimize_for = LITE_RUNTIME; + +// Stores a glyph with metrics and optional SDF bitmap information. +message glyph { + required uint32 id = 1; + + // A signed distance field of the glyph with a border of 3 pixels. + optional bytes bitmap = 2; + + // Glyph metrics. + required uint32 width = 3; + required uint32 height = 4; + required sint32 left = 5; + required sint32 top = 6; + required uint32 advance = 7; +} + +// Stores fontstack information and a list of faces. +message fontstack { + required string name = 1; + required string range = 2; + repeated glyph glyphs = 3; +} + +message glyphs { + repeated fontstack stacks = 1; + + extensions 16 to 8191; +} diff --git a/proto/style.proto b/proto/style.proto new file mode 100644 index 000000000..90e5b6506 --- /dev/null +++ b/proto/style.proto @@ -0,0 +1,110 @@ +enum bucket_type { + fill = 1; + line = 2; + point = 3; + + background = 15; +} + +enum cap_type { + round_cap = 1; + butt_cap = 2; + square_cap = 3; +} + +enum join_type { + miter_join = 1; + bevel_join = 2; + round_join = 3; +} + +enum winding_type { + evenodd = 1; + nonzero = 2; +} + +enum property_type { + null = 1; + constant = 2; + stops = 3; + linear = 4; +} + +message value { + // Exactly one of these values may be present in a valid message + optional string string_value = 1; + optional float float_value = 2; + optional double double_value = 3; + optional int64 int_value = 4; + optional uint64 uint_value = 5; + optional sint64 sint_value = 6; + optional bool bool_value = 7; + + extensions 8 to max; +} + +message bucket { + required string name = 1; + required bucket_type type = 2; + + // Specify what data to pull into this bucket + required string source_name = 3; + required string source_layer = 4; + optional string source_field = 5; + repeated value source_value = 6; + + // Specifies how the geometry for this bucket should be created + optional cap_type cap = 7; + optional join_type join = 8; + optional string font = 9; + optional float font_size = 10; +} + +message layer { + required string name = 1; + optional string bucket_name = 2; + repeated layer child_layer = 3; +} + +message property { + required property_type function = 1; + repeated float value = 2 [ packed = true ]; +} + +message fill_style { + required string layer_name = 1; + optional property hidden = 2; + optional winding_type winding = 3 [ default = nonzero ]; + optional property antialias = 4; + optional fixed32 fill_color = 5 [ default = 0x000000FF ]; // rgba (=> rgb << 8 | 0xFF for opaque!) + optional fixed32 stroke_color = 6; // if none is specified, no stroke will be painted + optional property opacity = 7; // values from 0..1 + optional string image = 8; + // TODO: translate x/y +} + +message stroke_style { + required string layer_name = 1; + optional property hidden = 2; + optional fixed32 color = 3 [ default = 0x000000FF ]; // rgba (=> rgb << 8 | 0xFF for opaque!) + optional property width = 4; + optional property offset = 5; + optional property opacity = 6; // values from 0..1 + // line join + line cap are already defined in the + // TODO: dasharray + // TODO: image/icon + // TODO: translate x/y +} + +message class { + required string name = 1; + repeated fill_style fill = 2; + repeated stroke_style stroke = 3; +} + +// root level object +message style { + repeated bucket bucket = 1; + repeated layer layer = 2; + repeated class class = 3; +} diff --git a/proto/vector_tile.proto b/proto/vector_tile.proto new file mode 100644 index 000000000..1cde2c7aa --- /dev/null +++ b/proto/vector_tile.proto @@ -0,0 +1,109 @@ +// Protocol Version 1 + +package mapboxgl.vector; + +option optimize_for = LITE_RUNTIME; + +enum geom_type { + Unknown = 0; + Point = 1; + LineString = 2; + Polygon = 3; +} + +// Variant type encoding +message value { + // Exactly one of these values may be present in a valid message + optional string string_value = 1; + optional float float_value = 2; + optional double double_value = 3; + optional int64 int_value = 4; + optional uint64 uint_value = 5; + optional sint64 sint_value = 6; + optional bool bool_value = 7; + + extensions 8 to max; +} + +message feature { + optional uint64 id = 1; + + // Tags of this feature. Even numbered values refer to the nth + // value in the keys list on the tile message, odd numbered + // values refer to the nth value in the values list on the tile + // message. + repeated uint32 tags = 2 [ packed = true ]; + + // The type of geometry stored in this feature. + optional geom_type type = 3 [ default = Unknown ]; + + // Contains a stream of commands and parameters (vertices). The + // repeat count is shifted to the left by 3 bits. This means + // that the command has 3 bits (0-15). The repeat count + // indicates how often this command is to be repeated. Defined + // commands are: + // - MoveTo: 1 (2 parameters follow) + // - LineTo: 2 (2 parameters follow) + // - ClosePath: 15 (no parameters follow) + // + // Ex.: MoveTo(3, 6), LineTo(8, 12), LineTo(20, 34), ClosePath + // Encoded as: [ 3 6 18 5 6 12 22 15 ] + // == command type 15 (ClosePath) + // ===== relative LineTo(+12, +22) == LineTo(20, 34) + // === relative LineTo(+5, +6) == LineTo(8, 12) + // == [00010 010] = command type 2 (LineTo), length 2 + // === relative MoveTo(+3, +6) + // = implicit command type 1 (MoveTo), length 1 + // Commands are encoded as uint32 varints, vertex parameters are + // encoded as sint32 varints (zigzag). Vertex parameters are + // also encoded as deltas to the previous position. The original + // position is (0,0) + repeated uint32 geometry = 4 [ packed = true ]; + + // A list of indices to the geometry array that specify a triangulation of + // this geometry. This must only exist if this feature is a polygon. + // These are the valid indices for the example above: + // 0 ==> (3/6) + // 1 ==> (8/12) + // 2 ==> (20/34) + // Indices beyond 2 are invalid, as the total number of vertices is 3. + repeated sint32 triangulation = 5 [ packed = true ]; + + // The total number of vertices encoded in the geometry field. This is can + // be deduced by manually iterating through the geometry field, but we can + // just as well store the number to avoid the overhead on parsing. + optional uint32 vertex_count = 6; +} + +message layer { + // Any compliant implementation must first read the version + // number encoded in this message and choose the correct + // implementation for this version number before proceeding to + // decode other parts of this message. + required uint32 version = 15 [ default = 1 ]; + + required string name = 1; + + // The actual features in this tile. + repeated feature features = 2; + + // Dictionary encoding for keys + repeated string keys = 3; + + // Dictionary encoding for values + repeated value values = 4; + + // The bounding box in this tile spans from 0..4095 units + optional uint32 extent = 5 [ default = 4096 ]; + + // Total vertex count in this layer. + optional uint32 vertex_count = 6; + + extensions 16 to max; +} + +message tile { + repeated layer layers = 3; + + extensions 16 to 8191; +} diff --git a/scripts/android/configure.sh b/scripts/android/configure.sh new file mode 100644 index 000000000..70c8973a8 --- /dev/null +++ b/scripts/android/configure.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +BOOST_VERSION=1.57.0 +LIBPNG_VERSION=1.6.16 +JPEG_VERSION=v9a +SQLITE_VERSION=3.8.8.1 +LIBUV_VERSION=1.4.0 +ZLIB_VERSION=system +NUNICODE_VERSION=1.5.1 +LIBZIP_VERSION=0.11.2 + +export MASON_ANDROID_ABI=${MASON_PLATFORM_VERSION} diff --git a/scripts/android/defaults.mk b/scripts/android/defaults.mk new file mode 100644 index 000000000..29f047c88 --- /dev/null +++ b/scripts/android/defaults.mk @@ -0,0 +1,11 @@ +HEADLESS ?= none +PLATFORM ?= android +ASSET ?= zip +HTTP ?= android +CACHE ?= sqlite + +GYP_FLAVOR_SUFFIX=-android + +HOST_VERSION ?= arm-v7 + +ENV = $(shell MASON_ANDROID_ABI=$(HOST_VERSION) ./scripts/android/toolchain.sh) diff --git a/scripts/android/install.sh b/scripts/android/install.sh new file mode 100755 index 000000000..fe2b81606 --- /dev/null +++ b/scripts/android/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +mapbox_time "checkout_mason" \ +git submodule update --init .mason + +export MASON_PLATFORM=android +export MASON_ANDROID_ABI=${ANDROID_ABI} + +mapbox_time "android_toolchain" \ +./scripts/android/toolchain.sh diff --git a/scripts/android/run.sh b/scripts/android/run.sh new file mode 100755 index 000000000..2ef0c40c9 --- /dev/null +++ b/scripts/android/run.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +# Add Mason to PATH +export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason" +export MASON_PLATFORM=android +export MASON_ANDROID_ABI=${ANDROID_ABI} + +################################################################################ +# Build +################################################################################ + +mapbox_time "checkout_styles" \ +git submodule update --init styles + +mkdir -p ./android/java/MapboxGLAndroidSDKTestApp/src/main/res/raw +echo "${MAPBOX_ACCESS_TOKEN}" > ./android/java/MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt + +mapbox_time "compile_library" \ +make android-lib HOST_VERSION=${ANDROID_ABI} -j${JOBS} BUILDTYPE=${BUILDTYPE} + +mapbox_time "build_apk" \ +make android HOST_VERSION=${ANDROID_ABI} -j${JOBS} BUILDTYPE=${BUILDTYPE} + +################################################################################ +# Deploy +################################################################################ + +if [ ! -z "${AWS_ACCESS_KEY_ID}" ] && [ ! -z "${AWS_SECRET_ACCESS_KEY}" ] ; then + # Install and add awscli to PATH for uploading the results + mapbox_time "install_awscli" \ + pip install --user awscli + export PATH="`python -m site --user-base`/bin:${PATH}" + + mapbox_time_start "deploy_results" + echo "Deploying results..." + + S3_PREFIX=s3://mapbox/mapbox-gl-native/android/build/${TRAVIS_JOB_NUMBER} + APK_OUTPUTS=./android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk + + # Upload either the debug or the release build + if [ ${BUILDTYPE} == "Debug" ] ; then + aws s3 cp \ + ${APK_OUTPUTS}/MapboxGLAndroidSDKTestApp-debug.apk \ + ${S3_PREFIX}/MapboxGLAndroidSDKTestApp-debug.apk + elif [ ${BUILDTYPE} == "Release" ] ; then + aws s3 cp \ + ${APK_OUTPUTS}/MapboxGLAndroidSDKTestApp-release-unsigned.apk \ + ${S3_PREFIX}/MapboxGLAndroidSDKTestApp-release-unsigned.apk + fi + + mapbox_time_finish +fi diff --git a/scripts/android/toolchain.sh b/scripts/android/toolchain.sh new file mode 100755 index 000000000..67cd0aa47 --- /dev/null +++ b/scripts/android/toolchain.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +export MASON_PLATFORM=android +export MASON_ANDROID_ABI=${MASON_ANDROID_ABI:-arm-v7} +export PATH="`pwd`/.mason:${PATH}" +export MASON_DIR="`pwd`/.mason" + +export PATH=`mason env PATH` + +echo MASON_PLATFORM=\"${MASON_PLATFORM}\" +echo MASON_ANDROID_ABI=\"${MASON_ANDROID_ABI}\" +echo CXX=\"`which $(mason env CXX)`\" +echo CC=\"`which $(mason env CC)`\" +echo LD=\"`which $(mason env LD)`\" +echo LINK=\"`which $(mason env CXX)`\" +echo AR=\"`which $(mason env AR)`\" +echo RANLIB=\"`which $(mason env RANLIB)`\" +echo STRIP=\"`which $(mason env STRIP)`\" +echo LDFLAGS=\"`mason env LDFLAGS` \${LDFLAGS:-}\" +echo CFLAGS=\"`mason env CFLAGS` \${CFLAGS:-}\" +echo CXXFLAGS=\"`mason env CXXFLAGS` \${CXXFLAGS:-}\" +echo CPPFLAGS=\"`mason env CPPFLAGS` \${CPPFLAGS:-}\" +echo JNIDIR=\"`mason env JNIDIR`\" diff --git a/scripts/build-shaders.py b/scripts/build-shaders.py new file mode 100755 index 000000000..c1d7f7f28 --- /dev/null +++ b/scripts/build-shaders.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python + +import sys, re, os, errno + + +output_dir = sys.argv[1] +file_names = sys.argv[2:] + + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: raise + +# Load all shaders +shaders = {} +for file_name in file_names: + parts = re.search('/(\w+)\.(vertex|fragment)\.glsl$', file_name) + if parts: + shader_name = parts.group(1) + shader_type = parts.group(2) + if not shader_name in shaders: + shaders[shader_name] = {} + with open(file_name, "r") as f: + shaders[shader_name][shader_type] = f.read() + + +def write_header(): + header = """// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#ifndef MBGL_SHADER_SHADERS +#define MBGL_SHADER_SHADERS + +namespace mbgl { + +struct shader_source { + const char *vertex; + const char *fragment; +}; + +enum { +%s + SHADER_COUNT +}; + +extern const shader_source shaders[SHADER_COUNT]; + +} + +#endif +""" % '\n'.join([' %s_SHADER,' % name.upper() for name in shaders.keys()]) + header_path = os.path.join(output_dir, 'include/mbgl/shader/shaders.hpp') + mkdir_p(os.path.dirname(header_path)) + with open(header_path, 'w') as f: f.write(header) + + +def write_source(shader_platform, prefix, suffix): + if shader_platform == 'gles2' or shader_platform == 'gles3': + # OpenGL ES + preamble = 'precision highp float;'; + else: + # Desktop OpenGL + preamble = '#version 120'; + + shader_lines = [(""" {{ + R"{name}_vert({preamble}\n{vertex}){name}_vert", + R"{name}_frag({preamble}\n{fragment}){name}_frag", + }}, +""").format( + name = shader, + preamble = preamble, + vertex = shaders[shader]['vertex'], + fragment = shaders[shader]['fragment'] +) for shader in shaders] + + source = """// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. +#include +{prefix} +#include + +namespace mbgl {{ + +const shader_source shaders[SHADER_COUNT] = {{ +{shaders} +}}; + +}} +{suffix} +""".format( + prefix = prefix, + suffix = suffix, + shaders = ''.join(shader_lines) +) + + source_path = os.path.join(output_dir, 'src/shader/shaders_' + shader_platform + '.cpp') + mkdir_p(os.path.dirname(source_path)) + with open(source_path, 'w') as f: f.write(source) + +write_header() +write_source('gl', '#ifndef GL_ES_VERSION_2_0', '#endif') +write_source('gles2', '#ifdef GL_ES_VERSION_2_0', '#endif') diff --git a/scripts/build-version.py b/scripts/build-version.py new file mode 100755 index 000000000..0110e6a2e --- /dev/null +++ b/scripts/build-version.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import sys, os, errno, re + + +output_dir = sys.argv[1] + +if len(sys.argv) <= 3: + tag = [0, 0, 0] + rev = sys.argv[2][0:8] +else: + # When they're identical, the git describe can't find a tag and reports the rev instead. + if sys.argv[2] == sys.argv[3]: + tag = [0, 0, 0] + else: + ver = re.sub("[^0-9.]", "", sys.argv[2]) + tag = map(int, ver.split('.')) + rev = sys.argv[3][0:8] + + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: raise + + +header = """// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. +#ifndef MBGL_UTIL_VERSION +#define MBGL_UTIL_VERSION + +#define MBGL_VERSION 0x{major:02x}{minor:02x}{patch:02x} +#define MBGL_VERSION_STRING "{major}.{minor}.{patch}" +#define MBGL_VERSION_MAJOR {major} +#define MBGL_VERSION_MINOR {minor} +#define MBGL_VERSION_PATCH {patch} +#define MBGL_VERSION_REV "{rev}" + +namespace mbgl {{ +namespace version {{ + +extern const int major, minor, patch; +extern const char *revision; +extern const char *string; +extern const unsigned int number; + +}} +}} + +#endif +""".format( + major = tag[0], + minor = tag[1], + patch = tag[2], + rev = rev +) + +header_path = os.path.join(output_dir, 'include/mbgl/util/version.hpp') +mkdir_p(os.path.dirname(header_path)) +with open(header_path, 'w') as f: f.write(header) + diff --git a/scripts/compare_images.sh b/scripts/compare_images.sh new file mode 100755 index 000000000..240772646 --- /dev/null +++ b/scripts/compare_images.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +(cd ./test/suite/ && ./bin/compare_images.py native) diff --git a/scripts/flock.py b/scripts/flock.py new file mode 100755 index 000000000..6ceb585cd --- /dev/null +++ b/scripts/flock.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +import fcntl, os, subprocess, sys, errno + +# from http://stackoverflow.com/a/600612 +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: raise + +def flock(lockfile, cmd_list, verbose = False): + mkdir_p(os.path.dirname(lockfile)) + fd = os.open(lockfile, os.O_RDONLY | os.O_NOCTTY | os.O_CREAT, 0o666) + fcntl.flock(fd, fcntl.LOCK_EX) + if verbose: + print(' '.join(cmd_list)) + return subprocess.call(cmd_list) + +if '__main__' == __name__: + try: + if sys.argv[1] == '-v': + sys.exit(flock(sys.argv[2], sys.argv[3:], True)) + else: + sys.exit(flock(sys.argv[1], sys.argv[2:])) + except KeyboardInterrupt: + sys.exit(1) diff --git a/scripts/ios/add-key.sh b/scripts/ios/add-key.sh new file mode 100755 index 000000000..fe963d38e --- /dev/null +++ b/scripts/ios/add-key.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +# This is all taken from http://www.objc.io/issue-6/travis-ci.html + +# Create a custom keychain +security create-keychain -p travis ios-build.keychain + +# Make the custom keychain default, so xcodebuild will use it for signing +security default-keychain -s ios-build.keychain + +# Unlock the keychain +security unlock-keychain -p travis ios-build.keychain + +# Set keychain timeout to 1 hour for long builds +# see http://www.egeek.me/2013/02/23/jenkins-and-xcode-user-interaction-is-not-allowed/ +security set-keychain-settings -t 3600 -l ~/Library/Keychains/ios-build.keychain + +# Add certificates to keychain and allow codesign to access them +security import ./scripts/ios/apple.crt -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign +security import ./scripts/ios/ios-dist.cer -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign +security import ./scripts/ios/ios-dist.p12 -k ~/Library/Keychains/ios-build.keychain -P $IOS_KEY_PASSWORD -T /usr/bin/codesign + +# Put the provisioning profile in place +mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles +cp "./scripts/ios/$IOS_PROFILE_NAME.mobileprovision" ~/Library/MobileDevice/Provisioning\ Profiles/ diff --git a/scripts/ios/after_failure.sh b/scripts/ios/after_failure.sh new file mode 100755 index 000000000..88a6427f7 --- /dev/null +++ b/scripts/ios/after_failure.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail +set -u + +ls $KIF_SCREENSHOTS/ + +REPO_NAME=$(basename $TRAVIS_REPO_SLUG) + +aws s3 cp $KIF_SCREENSHOTS/ s3://mapbox/$REPO_NAME/ios/tests/$TRAVIS_JOB_NUMBER/ --acl public-read --recursive > /dev/null + +echo http://mapbox.s3.amazonaws.com/$REPO_NAME/ios/tests/$TRAVIS_JOB_NUMBER/index.html diff --git a/scripts/ios/apple.crt b/scripts/ios/apple.crt new file mode 100644 index 000000000..0de099b86 Binary files /dev/null and b/scripts/ios/apple.crt differ diff --git a/scripts/ios/benchmark.sh b/scripts/ios/benchmark.sh new file mode 100755 index 000000000..1c342e653 --- /dev/null +++ b/scripts/ios/benchmark.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail +set -u + +if [ -z "$(which ios-deploy)" ] ; then + npm install -g ios-deploy +fi + +(cd ios/benchmark/assets/tiles && ./download.sh) +(cd ios/benchmark/assets/glyphs && ./download.sh) + +make ibench + +ios-deploy --debug --noninteractive --bundle "gyp/build/Release-iphoneos/Bench GL.app" diff --git a/scripts/ios/configure.sh b/scripts/ios/configure.sh new file mode 100644 index 000000000..0562e0e39 --- /dev/null +++ b/scripts/ios/configure.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +BOOST_VERSION=1.57.0 +SQLITE_VERSION=system +LIBUV_VERSION=0.10.28 +ZLIB_VERSION=system diff --git a/scripts/ios/defaults.mk b/scripts/ios/defaults.mk new file mode 100644 index 000000000..fafc33213 --- /dev/null +++ b/scripts/ios/defaults.mk @@ -0,0 +1,12 @@ +HEADLESS = none +PLATFORM ?= ios +ASSET ?= fs +HTTP ?= nsurl +CACHE ?= sqlite + +HOST_VERSION = all + +PROVISIONING_PROFILE ?= 19324a54-7455-4f0b-8e1c-e6957c718ebc + +export MASON_PLATFORM=$(HOST) +export MASON_PLATFORM_VERSION=$(HOST_VERSION) diff --git a/scripts/ios/install.sh b/scripts/ios/install.sh new file mode 100755 index 000000000..da081254f --- /dev/null +++ b/scripts/ios/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +mapbox_time "checkout_mason" \ +git submodule update --init .mason + +mapbox_time "install_xcpretty" \ +gem install xcpretty --no-rdoc --no-ri --no-document --quiet + +mapbox_time "install_recent_git" \ +brew install git + +mapbox_time "install_awscli" \ +brew install awscli + +mapbox_time "install_appledoc" \ +wget https://github.com/tomaz/appledoc/releases/download/v2.2-963/appledoc.zip && \ +tar xvzf appledoc.zip && \ +cp appledoc /usr/local/bin && \ +cp -Rf Templates/ ~/.appledoc + +mkdir -p ${KIF_SCREENSHOTS} diff --git a/scripts/ios/ios-dist.cer.enc b/scripts/ios/ios-dist.cer.enc new file mode 100644 index 000000000..dfdd0ca99 --- /dev/null +++ b/scripts/ios/ios-dist.cer.enc @@ -0,0 +1,30 @@ +U2FsdGVkX1/Dn0fx6y0q6CHTK5UmCnel5Nw0kQlpeCqrqpWvXnYS//Ep0updcMIQ +xj1hu+baBWjw7ccysFG/zcReSh/xgP6JrW7QKiA/kIQvqOvH0vhtzvDsnAQCB52T +VWVy492mIwFRCBANVTPbdmBbVIeHAkeQcrVkFJJIKOv4dC+CFAw9ArHm8iYrg7FV +FDK3cmrfR/pgvlQ1lQDa1C0vV1k/R5KuhqwDM3xMML1WbuBlR0RRHccs4xJRmRV7 +NuAuWg2Ob+p5gOW4L3+7PnBTBgxUZl2nbukd3oUlAPBOxgwwbgQSJPDvnsw2zmgp +uv2X0Q0/fT9R8VxuoSXYkLkgIlOnVVRpyG4C4ou7HPS8VDiLP5iRWKx2PoTvaBLz +9lNPTXhXu45n2k9L9SbkYk0024u6I8x9EkAmu0wU/rQpdudw4uLO7Pxz7BZHq3/D +frwBMvtQXRogeQcsi3dKmsISrxdSEO1hax6toVnqujPSXKmFOMHXyhqJg/K9DDhs +8GAUUO0cVfAaviofVFBZAXwkOd0SaYWz3WY4qHOZHnFiuGN0MCd2lXe5kVKFXRdE +6ElXMm2+M0YLH+L55MA79hIDjqjv9JXTAAKpLy5wsOkMYEaaXvevdAEhkSW9QzIh +HGUqBED5jqdrNlm7qOPSMWDcB/9FlnizKFsqrZOjquWFQZ4L34t++8FPT0ipxKCI +XkYxBqVesZlHBOLPBYQ2bdJUuYaACkyMtB5eRebEieoWRXTB0aD4otvh6F6MYpiY +4q66GO3faCnPxcZY4OxxwSSuyotBP8qKJcACqf3/Ji0nt42IHOIWJmiwROjBzMQ2 +DgYLtjsi1/b8eXLO5g+6S8o404j8g+2Z2rYXG+Hw6TaxY5bXrAH51fbUNDJP6qFR +X3K3q8YvJlXcKIU6aZi5CDqaJUz6e22FvsOeWVHjdQYB23kk+LWYQY58hvkFUDXd +/Nn2FxGPn80280sF4s8EX77YEXLGLqIo293Yg9F9JBwrq76ObY6DJbRlB4EG0Hx+ +vo0WJhEWHahu2uCfwqMJPDhMTGYcYRdHcNSepJlbj+gFTmH8bdKZGI/g13ZsDYEK +HKP72rtaGQT4JYkS06TC6/Vvi+0+PxXr9SKbODCskN2yJpp0S2wXy8H6IwlpPe1R +v82oCJQAXrcD8wd65TR2Q7fg4akHzI9VX1q8UGjzNt/Y/EsPEVv48PM/zngk/Hat +Ptq6SoOFAj/JqbXOMuW0fidBI7uhq5575lgxaQ+VL4nKdDrdoHZXWJgjG/ZQO1j4 +8o12Z+Fk8tNpMPofJaAf3ebuArAE/IUDK7KKB7UoSwT1XPOFI9gCVtG654i7CAtN +LfkDruwjTcD2XyaVLcVTeDUr2wMMrugE+OS4B/d0nD7jU4hVHTVn5fJxRiAFx+ql +cBG/TIf951aDZ1x7eIj4xhehletdeWTZ2wGT8RJcFPD3LIB1hddeDIFQrkfEP7Gp +IY+VdYo3tZtYcj9x0dXey/n9y0kxZw2w8oAY5iJB7NydeSANL4btPWO8y4KxXta9 +P+HNq01JS78ufYxfIOnOxD8l7YtD6Z6Evr1elzGFJOzRl4nCbPUg+VXekR94Lmf8 +0MBLgyG6xSoRBHvIYK6SRHEc+NuWvyfZGSOKBQVTwvf4/y4+xGcbPZy/YnUX6u+/ +zRWaYPJBdRhTrwAqawz9ZLL65uFYM7jhpZPEYGhOVqFoarNsy0m0gF5HNy8r/s71 +N1DBKUyVzdhR+4JZEHkkAr8JnN108d1uDIkaiI1F+hLCK2m5wnMYlZBMj2pP4kSC +1E7JiIr/EKDiIHE7rOzf3yTYwug0xusBDdNTappMzTRsTCEyJf330k3kS7y0+zoH +lwtG/9HS6qcwPY2h5buxTb6v9xQqmyWNT28Q8qEb3h8b2XS/NUyB9SQvRpkn9oUR diff --git a/scripts/ios/ios-dist.p12.enc b/scripts/ios/ios-dist.p12.enc new file mode 100644 index 000000000..ad6507ef9 --- /dev/null +++ b/scripts/ios/ios-dist.p12.enc @@ -0,0 +1,32 @@ +U2FsdGVkX1/814wN7UBPg6IycBVVPPdPAxznco38K/9rGWfO+wPmcUC3CyBVI0gM +izei5uJZ+P/w4kItEeojiTbSTpe17JD7yL7Rg4AIrjRpVd4uzDsN5hjckhi5VXT1 +65EYTKLMLiwt91+9V7v3hIHPiVdM8e6CNQzqioMXIo41zdP4zSUa9jDnYhF6hfHC +f5n3uVIvxtpnu2//XFV/TeKFcza7+A/sD1qk0NbLqOZaRROufmwmnAV6XW65ZMvS +XGO931TSRwvgiinqI8zyUCys+79WZfPv8SSkvamUsvJF5ZS0ciRZ3mWYE4H7WwK7 ++fm/c0hXobxPSd2HKYnWdodI+6IoMXjtfcrAcpmXxbfec3/K6NfT4AIxeM4tK6Lj +lpU2zvxNDHEt8vfG6CRJK5OKAm36yZ6r3Z0UzThfnNMAmX7/h8QAs1VSJ8olFm3S +Rl0XUpsdHBOAZUUsvO86BkGHg0W80WWwmCqwjzZogNKLpVhERk7MJU6/q9grV6Nt +QGUFYjG5oVmoqeu4J9AwJWOqDJtE1e1rvp5Zh3OVjUTACl2yMQz28c8d+zt3Qb17 +dBv9jhNQc6LtjV7xyp1wo+Hb42l0wA8ExZd1UawqIR64Rs7rcWEdsd1nnTqoDDtK +NLklCqTl1cFbxpgOkcILFuPRjIgYwOQtty/lzPlX+OOggVagLAX/KiehBS6PzSID +ivmwgpCnKJgZkPSknV2GGgAp5XqEjchB87T4Nia40lX4ReDJ95EM3YBBjK/DN7Dh +FgK/ggtaLMhEtVm2NGtkEk8ksn/qQdGF/uFAn53Fz3d5PT6NAdcLkWIe8s41KI00 +tUf+dYNhwh8YXIu19QGxv7F/SwiQ2ALhsBRyA+a/F0T/miXiROUUspBs4jR8bJsH +CeSkpwm8De8s19rKt0WSnjiVJzFY+WcU/xsXU9qn6AshUdXrx0KIHSiFrmXAosN1 +LbDNmAPENTQBXR7F7F2BlE76/BNH2ub/MTHp6KtVU38OWihVAb9E4JkULIgzAolR +gVsNPIkyBB+egWi5tnvIcvzazpomW9qah49AsXjUCy4MM0z7RWD+baahcI3q9w/R +4m9nj3U1Xhxq1GZV1L74R+fjPRfbE/JrMYFWDohzp6/ZMnl+/J10pu3dQ5+PJ2eR +XEsQiU4G4PvEMxACIsTEspuNx6uOow346Tw5hehRhEMhqEMGgDoewgDyf3pB5St+ +HWWrjrZjiBfOpKP4IGEaTzr72pxtKA0gzIsZwZWsLGS+cKINitQ0M3/0zEpGfyj/ +osc776MQL9/tXoChglMtieJkGN5IsBve2U6nJYzsOetizhOVZDEF+TfSHLGOVnyq +HJldHNr8F6a03gHNLsya44g0OeO+W2VzoVjpkRIy7wkINc+dKUXyYsV/ZQ78qhWe +VTKP/43rYEVnQrg9nxhM9xXDEDcNyI3AG6B405sU1NGKGd849V6iyNPEiHlY9VRl +a3a/OURfcpAwgiPQZWQYOu1PeR53GEwXs8WEcpFUA3G7foriWPzhMggjDMB82t/a +6pAuJMqLgvwlsbh9+8tjTPunyWs36oHu6qMQ566WAQGAOMbVp07nYQ42h3ZlBLnd +Jwm8sRdROYPsGdiusMD+tpuyvrSTBx2z0jExpN/OzmLJo5Pf8JRs7FgTZ5qzPVQe +JvMmXJz6vmJPaJOcfdHxzn5K1CGEVS3oeDFOGukP15ZEN7v2aC2yoWstLjGUIIF3 +dh5+g3ly55PliOQX0j1uZKaE2t8O9Pi2mEJUFMP/+BplZyMMTEkTPrPhOADLTM+/ +UweO3ksqrLLal4F5zR+Mpw8KvyB/OaD9IPIaAQEuDbxE6gCqzgl9bDwPRVcRh8hr +rm+TJVZqMExN4IefvMXmvIH0VHxhbtZaz/JIERVFtpGiB1C6lZILGCJWAjFVnGrU +9UqF74uxnzNahBqGezNdBDTziD8A4CkEFVR9SR5XpsVJVylawP8KgUd/vO43D+8n +bScLB4LVEDzgQcFVj1nJ70hAwG+gle8IGYZrgKWEIcBt2+Wdye72dMgApPDtKGIh diff --git a/scripts/ios/ios-in-house.mobileprovision.enc b/scripts/ios/ios-in-house.mobileprovision.enc new file mode 100644 index 000000000..51036a741 --- /dev/null +++ b/scripts/ios/ios-in-house.mobileprovision.enc @@ -0,0 +1,153 @@ +U2FsdGVkX1/xCimmqpQF5NssG6mKnQJtCs71V6elWQzSeSQ+eXtItM/qqvAOtA2h +vaZxXqcyiBUMn5diQZ4ZOG2u4qHoGTkiYYsKI7XURQqOhUC0MFtdGxvRFpW4Q8bR +p593tVorRX3R2PtPw0h2vDluIRb8y/BaoxRWIa12TwA7yipYrP5RcmaLg8k6slGS +PEq7VddJpdAS+W5qawUoDYH9z5ffXhej2d0IFwXCJzFkBf3CdUeKBr8yInMULywG +O0DkvitnnpFu7asADuTDlBgpTqF8JImXIR7OXHDWMDTMGMMN1HQSOzP026ZDFhha +V71pTACLWscMnaoLd8UeZaSFb4j+szT9bV4EOPT5n3bHOu9V6BMCOL6Y5S3CsFRG +4cRIEiY/yS41zCUvumu3WWXJDr6QMOKlmk5WVKA6lKZ5FfEKWbyMAXGqn8c9zbT9 +BxvM151gOL3eqsiC16rIvB8uNOvTVKsFsuVdzZgYQSDs8PC1uS6A5k/KwbqAn6jj +ATkiHCDbGtZoyAV+8bjOei36iyQMjoV2St6eHpDz9F0c9PkCDjjA4A77V7AayHQ8 +s37qY0M8Fer/+zqPCFoUOK0TRdV8oV78ZtzpsGaUOtiVzhxyDkFt2cwaf0VSfZG7 +/+1VR65TQgJ1JYIIY+/4wROBEPOJBVCBJyDsUHWuB9MQQzyC7sg/UD2hliZ/4Irl +2Lo1l13p5JF5ib06zVffi7rsKbI432Lffqa5/zVW1NyjqqAPAo2TOA90u6eLjrVf +Nn7qtZkn/kPCsIE2e4cFEYU5h1OO7af2/f1H+ukzaRJRPHtCMf/W576J7PWnna/N +r3BxgJIoS1/1DPMtQPpHLHo/KnWwmC03yWFqJAXNVawQuw9SG7txCjVvPOtu2AuS +TLZ73hCAcu+JBJVD1l2B7Vt5y3qxdD1ei3WrxC7YlCbn2oyGstSuPs9MvePdpxe3 +vvaHvyAJsmjXD6MuG1diEM1BZ46L3vnDt3BAdGkwcnhS0rggAaVAd6inyLBbjrZi +DuSgiR8ABpuCqGeHB4Y3oVJYzZSuM81X4PXcn/A8Iz5PN1SEq0g/rCrgICjyRaJA +bdsop2/aZzMO2vIOUrr5py+51bRO0hT3P8xbuGUjhY2b3rdtFsXasDM/TywVg5Cr +VGO7lULyj4UZU3weKSBtmMnEqlnducroxckYdVZGD1XegE2pKhydjpJp1I1gyXwh +SX6qPQY4/ABcE9/OA3jLjZctcdbRpDpbzRTlIoUB0eHe6E9of2B0Wq4PxpFTCy25 +PT2yY074SN9QsPlUiE57F/KYKCfwxMicEbZMcrpTs3aX7PqcLZP9YToG/dNI2fc0 +xWmWN5ZcO8fPLG5MMDFCm39lxvk4jIynytcBhJAAvbNX7+HMVRWyWjvf7H0ldZrV +3OQPXXmxu0Sg1RgQSUSZu1zQeSk5Uf879ay3PQY5CCQz9H0nm/Sxf+zN2esqDUEP +0ZpuTb62qsAIIsf/zAeVNu1UtXTlOdWbz4EjofFl2Gr55pMF4BkjO4XxRnVZAl2B +u89H8mv6cM//oA+lt+JbYRv3coPqjv5LZq1iAmm9zvVnbbQEin5h1DwwG1X+iGhz +BuWoUrLI1KuGSLqiaP7yH79N4z3n+HHVx0gdsvc8pJDpFEyFqRWuF1RSmQcI2Dx8 +bkr/vjXn+OO0O9OicZTnAj48+LpfUTTu/uKL9QVQfRYiRWB55nPhvBTcWNMzoPxD +qhFI5Im5TLUNDkilXmCxOoOJ3yeX2IMZdO20FlZIBZEvF3/ECTa7TMLYE6tXtvKb +QW9O99s0G1S/8g6FcIq0h4QO9cwZHKHxCsKHixK4s0yiZyTznUyPQJB+gh/EWlMc +xC/8kT9RBiSmU9Ym7vNlyVX1Xxt2mutIb1SAgnxYKik/06b7HktDX0eibNYwtT1e +/RJxwk4OEocbNftGMEdiFvk56cvrMjEov61QYOPAfIUCnpUTC/DMHCbYuUD8mguO +gpjWk3MD50OKjVK6CrQoxjFNxFuSxNxqHtEQ6w9nrrgi4LaVaFxluBeiaolRrGwW +418ZbZYDf4hq/zcEH8kPDd0kfAW9/FwPwqh6nDhlJJnHHgIN65keLu/Ls7pnVs+N +VVjGIdIVLH0BufECIQVT4E/1kPSwoqiScBkCVPIWS9O238P2/qPRDt2g0o+LclMm +R0GOKkn5Oe+KzyLdqF0gB6ZoJVD5mUTMcykrN027HI02q1ctRXFbOJQLE+aa085W +wAVw/J37Fuw1SGkCmIFZtL++z1grb14CIzS5HsIrCoM67JGEYjZxabTIilCWUt63 +mv6BJR6I985//nFPbPMpjT2K06zLdIdgm2qTYVbU9lXAZ2m1fcHmiHkEBaDYlv3N +dKkmkA8cJPCl6wyYQhzwc7I1B1HCcWtI0Lx0BTYZ9G2ND7/2hFBmJcP2a8V2xQx2 +2p/Gnd2YvphqvPRDfTbUTtpCirUaWD223Pq9w4aV1mDytcoBmnBgl4BID2RpcS/8 +nTsjSObs+Fu1ieskW7AMog3lOrjXntg4HqBUi6biAp+RASyAIaDskb2eWvbUloxg +FEIeG6GK/odD4fWHBmLCUJbgtYaDpqs4s5hkfC+edxj4UUBJNjKnp9awArOyBvXx +M5tlBi9fQ/6Y4nyKdcNFculLyLsxKMJNrOzR6Q+WOw6IKL7A8uue0le+YyDdACbn +4xtqn9R6c28nUCEGz4qkJmARoNxapAu3fMYuhp2CYgyQsW2yUq3lsJg/Vc1Dqu5a +EcrtYf27BpPlLqyS0YM0gyV027YBDNBnJRO0Rmq5ryF4N1vzoC6C8Y3XHea8p11L +vhLy3TXK6nn1pv1PKBceCvvfjz9ZC+GkPohmuXRwY3Kt8QBt2Ua5I1AHpYUseleR +GfiqetHAfM4Wr3qcgc/gjK07cSdrW7qA85laKxpTGJlJ15IAt4SRH8TRzjiU2YLe +ZgdMe1zW5YjCAxG7QvtFcmTUoXY/JIytiycyafM76mu0hKErAmrsV4Nt+7PuO2qB +49hI67sjM62owHVKdyEA7Km6k4dnl1sznQtHCTnqC53YhY1JlMMGJ9q3uue8WUnO +theDFbFc6aTtDShXMvmWmgETBfE8L4sbgLdEpbyBGgE7xGgYeNNw2tBWr7wTEjMe +qqfP3ZGDNQb55QPpbUwUCFoEQUe9GGAw1gkV5E8buklVL3nWbzuVwEUqcYNfYyAh +ZbNXMfdq9Wh15X/gJKiCIyEGkS2zI1MS4ctbcIE87MizhukpHBk8EYTW8Ddma2Ry +zNMxzkTBgzFYNA0YEYkYS9U8ZXqsG5HlIJ06G5sSSbjY4wH8seTeCXgtOQ0ovWL6 +nlwJm9uo+/Xt947Swtwruf7YmtQaje0rUpfGnQB+EBlY8mN4nfMuw9pRYzxXymgk +hWNpstD06IvtQTD1WAL55YThjXTFfR42fgrsOBEHD6C5R/TKVczDynYFbJkBZg2q +4Nq9AI05XiJdoZVScWj1eTfl5e9H/NDf4DgL6LdDjZGADuA6Xyl1X1ufS6bwek52 +CUb7bDFGpZPaWM+wKfk8hYnJqM3pSOMSf99mWvVtXM+kXvQZr1PNQpkp/oMBiOWi +oDVylF75cwtfn5mN+yo/psNcSY8a7qBhaZ48+5Wni1ocOpQIwaG4a42hyK9sOmrv +/plu+Y+CaMYC0pEae4tG9VGb3LYgEfEE8uYLSoLS9h7Y/8QWFHRnlbNAFYUh4VTF +MihsugXr2WJJlmmqxnYUoe2XbRnXho9sQk+Dkrc7krccBqfM5dmreuQp+p2TwB9+ +2940DUvpHiOR6tISNzOjDi9vbxZi6BWpyKP9uvAdWO46U/ZLDv9Od2W3x0rQtgkb +C8XcnO7MTffU7fGYSH90HSVWi1wPdMsGpLKgzkRfR9VX4MfNcwjMBk0IRd3MQFup +7tMXUx6vcKWZLpVK3biWenS3TTcTtXznVt8LTdu6LbTriHrsWx/kucDPPxYjUJP3 +O56cgwVHY+AsSoilRP/oRS3Vz+fiqppU6bAxrgkt+5InU6AHg0KcJTwNXcqZYZ7f +LPuwdI6fPVSxsZqje/sAcwhLhi5+uuCkJXJF/wIUoncG3pmZzoZg4naLj2K/y2f/ +DNGzEX07v3aRHWy6hRWrkmeWg5HtfW7+nDGGTd+UqQbFif+y9xGCJ6i+TCowih5R +/h/12z4GJojCrJjmymroJtbJ5oxOru3MpvwgZen51s4ZZsmPmn4gmKJqIgAvWQrx +2EeVYeKMgMBI6bax4FLx/NqOFBVTp3BGy4Q1PqCwWIJe6Mjd0hAPA1osDd/vdJqP +/cIuAGNiO0BVcLyJ2KOOEiGEpQysA9lUK4X8LikAbSAanhSslS5ReGUOEd7L6mCs +Sr3xnHgjgbg3MmaNyfgRNOhUa0/b/jYMin+32eZDVnuC7o8wG+jWBbHisQILjy2+ +gbYhu3FnEXW6+j0uoxn2FHcNUli6V7sAz9+BjiF3FoE8fgZPCdacIQ7e4N2LroxY +QfUC6409qUd5Vrd61hWEVZMRTIYqS4ubdDv2vTAIkC1HlLCUZ2iC05ibsu18FpLt +6UtFC4oDgedazPYiAtiMrOopzoppCA49h8/1J4Y8jZti7XtJ8pQFC/gBEIbGz01i +6Bzubr56E48+0RPPm4zXkPZdNMzIsGA7/awedoFOAy+/HRfc+i2uuK4oR3Eo7D+w +MvgwbJdqTLnqpjbxyo2hYwYT+34aJK0yR+JaDYTFf2uFbwvoqPXDdo1lkmhgyRuz +bPHTE9soMROkR3HzHjtuRt2hUmnxXCOH1xXJN/eRzj3ieXfEwoxf8pvqssbf+e28 +7WMlDdP6WWq/lJsHhT6A0lsY6CE3WSaUs6qugMzQVBddCK8mYRHYbU5DWRMID/L0 +bqiePCe01uz9rbLHvEYJf4KP7C2CvHFL56G9nTU6jC8AlZXWltha/pAxgspPRB3t +UvdHVkCN5ErrQEOjE732NHTZbQgy1fWi0dOvO6isSmN9zJb+M8VBkTdf0qvmcdSY +P1iNV6eyVltk7maYWCRlVZj5jTgSc44mows4TyqXe8UCwu61dbIVFw8yBumLyJtu +bpJhujPe+Sut3pZ3uSUm2bDtxM8/2iaglT9aJmn+g46dPdkItp+87qLlscZiDLVJ +0p/9AhMJuXG01C7luAFhCHUQaZnZ0b51l3SyYKH6g44dcyAv5LQyVVJ+gLFKzpsp +VyUmhBFigk3Jbjv0XMF+vZ+zU0+/4T9eg1RnPMRdM7iUnzswtBdrILMBYkbkgnsF +hXGTpK4JGk6+kIzoVQFCP4KnOMzHAoY7kpx1oOW1/ss/OnqBrRd35msLIuxb033r +tPTRS3iLo3eUIG3j54WtcQyaMlVi2DuSaXrVeDeGlFkNaJq1Ztukc4mEdklrvsLS +BASmILUytZfJa36VtfYI3WEX8wpxzamWuDIUIjAbbFi76dDkZo2m34IBl4HsS1ze +3RWxVE7BoBRjXo3eSUYIKvXvC8ixz1YJKPqFTZdArrrfJhrZGO10Gda7ez23YHm3 +Q72SIQhZOT9qN21Pz7q4LQV5clbY2l3wDARNfk03LCdOSqKAlT5C/A5q7Lhx2kVW +qT7ISL+CLwAhBAus60231xNoj8uz7OqQbGOmoWd5x+ultyqRtFwX+zpvWp/ppY4+ +9MLvW42tzIpxzjFcFmoN9Db+Bk2vs1iWsNrdMqU4c1bz6qUocP4GBnxWTgHgGcbG +6eZYGKOPUFCs/PR/hkPeqk5qgdkDsnUuIH6OoVftyJD3s0e8AZ7ZzCb9/XwpfFlR +xXLH8XXjp6suIbx2nY4hvY+5HkajlMKe9i1tF/nkSfP459UGGEyvDNbOpBzcr8WV +hrDOYumR/JEiWpEdvC2yZrmk8gbO23/TzcFnP1DTY8F71UgXqZJhoHIwlxGMrvjv +l9OaBz8Xr4q3p8pmfevyqx404B+tmPsk9+t74pQM9XcKNLl48EMzcAWlCI9C6jLl +0+uZjKMbad9abVeK0+YscPUkZXiyXVsWJkx5rAvzTNIBjZ/9B3kFxsm/FvuDnGYt +5wj1VeL4TQuFep+T3aS7Mjoew0y7DO0ODf7e2BrSOPx3OdvM6wSxlgqP7ZKO74Lc +0EuwiMhD0rVPY9QJmXL3RDd6+xA1FhGZ798rhNQn6Y00awpXvOw4OwDkTCI78fyO +/eGYga8z8VXvdpnolsbJNmSNcEeEpCSh/ho+qD2JFaQ39z8aPogdeqPw7UueuELt +4FDMR3MFglJ0MLW+9Um7L7qZMxu3sGUBkLcOiY4hfZH76oJSSGUZGER9JRt5iBtV +zjlH88XFyavKoTzEh6qdPdNy9dXBsveIsgQ0SalVWHCCa6Eri0dBshNxM7Baj/Hp +RdOyxhMssmr2sWyIUBcux/vN705GttAbIDA8pWVB0SgDlaXYI/xtw5S+tL6YV4zj +NQAnauZtuyf33qabwfeQHZCxjdyMmt+8tv+AgW0ayh/69OhaaDxBzhAeWfY80pbH +G0Sf2cAR5jRR5Y4iBic2PMSgNW3LFsic9CQRGSdfZpqYCn9AdLwap/c/fyBLusGL +fobmSey3+MhnPbGAwqBfT0Tpo3gDsbO8StB8p9OQEaCYnTZJ9xAVkpWqEtr9VUBA +yIUPjsz0PvDOHdyzTse+b3mnkatlIFwSl4ynXirBlXE8/3bcyH61VW+mxpFGxdn8 +kOwnMZh0z0KrHdv3TWrG6PSoyjrBuTvj51F3Xy+XH3KTBns8d4CqtNhqIKxjPOFV +OIKEvVAO76SvdIKOpinAuPBH05EiShtMf8/SvQu6Bbv6f5yMSzQkTFCj3Jm4GOpw +3T0+m+kwJdquZwNSPKLlTbDWjLXxCnlVxLA7PWSZgy5tu9b7k1rfULJgm1k++/n4 +l0I9DL3HZ63ZnEXD1DAHxNolsMJqcAtFVLH93KJhODPh/HmGoD9c1QYVlRVJI84x +AgsVyff3OlJ3ccQdLr669FNK46t8EmPJaBG2pzoAS17AJjb6deSC274xDAQ9cf/m +eWKbVQvHSIJ48O9nIwuPzeqVOYmAaeOXaU1w18lJEopR1JNkOdibptUzGUgrzdl6 +rbJ7cqeqNNEJ6x/l+M8VHnJL4SFH9jvQ/B7+uRIaF27BbFwho60ayyyCzaH5AZaR +m1XF1YLkTaxXnERX7zny34OdI5xNsZ7M90WVbtCWxEuA4qhr3Zgi4y45ZnxzBdNr +cRiF3gsI2tN0dHFViTAUmikVlE1drpZm+C1IGHPq4S+vXOLHj6XODggsKxJXnfFv +LT8ydmZ4NySHMHpOUer4kTHuI/QGZ1zTlC6L93Ipo8bLOkTjKroa5QvtlkfErtnj +vlynae2ciqKX/qnqZF7eZeMQHyekHpxWQyrKU5pKaTkKky8N3vUw5Q+HMLuDqi1g +UcOPeyfq90GTVyuhrvK2sFZNh8J5gnYteBZz7atx9fvnNlx73S0Mc7t2rjzBlJN9 +Wz4Hu9wvyQVMFgt1Z+HnhFeJAbkytwxgipu/JJS2s6HREtrfnQEuGtUpLGmUEwrE +5SAb6HD4mjsVpLbjzo9i4YkgDJOS4IZhWM5iR2Q8N4107jadn2a6Vwrb8GBZOspI +0vLUgabllcU4K9eINud5ETZS4vT516RKriXqM5Xbr2BeZSU6P6R9ji5NDn1ylNx4 +WDn8bmZRtIxOcAaV/W3XbvmIpXrelcRTDQHqk/WtoJkvb6wrC60gp0uPLJJanMcV +NsUyF9goUkF3TFXVAj0jknbBjiCApYynBqpFy52wVEXSFuHLUxK8d5QND2SGP5Ib +WXbnaPE8r5JyOhY0u9KFidx3JbOPfA8K9wxzkUa1NCoBNp9CyyLQhQmO7ALBGHcZ +5MM3rVR/0gwd0s9Qt5g4F/pBtKedla0wJMWaM90bhIwASD2PKxyGiKzQMYlE9HiQ +AqgvGBM4yeXmIgdu8itIjk0teKJi4AdZE/oXDV6OkzT57Cm0M/7dKkWnHB0eYHFA +CFMnJr56N9SJF8skkX4of7412xWXAMd4ERDqq3UyQ2r4qq1aYPVxAGw76PR+px/Q +ZrjNm7hCDxevXZN8g/Nbvb+gtqSDTjKzOjKq8bUPVxZZxEdIR3/ZYf4bKu+kHZQs +9RM8uYuqipQOpJl/ftLOOLLGPgFONXA7sH3P8yF3tFyHjMEmuq5Ac6x3aVIe/tAc +3anzmVGcdmVMrZj24PPn8STf4RfWzIRlPaNn6I0EYoJWUpLhTgpOWGDodUtZEcC7 +WoaMcSum3gpvQyR/eROwq5jtvMPNCdO3nEjB11gLL3n7uWeeDqdeVwVJPVurU5Gb +BpDRi0sTf3qaldStkNp00aBBb5f5P0Ezq0ynVO5+4x31gQaCzrgp9r387gHiEkDb +A/lDdKJl3LINMgIz+RieWTQgzKVl9rNgaxSUeEmzPXxaYLE/Ds/cN1RmLB6kAaH9 +9KImQP1gz/0kE96tpL+0jfcqXcZlofSHWivBJ9/Nolgd4FK+3/vHqKgahswIdndj +/LfN2X+PpQOwJ0vpYf8vL5bUUNgtoDE87kKZiZE/JaXAB/k0DmtuQfQa7MCZGGFa +SMFIGlqlDjiXBzgPK9iOJPrlBpQmIwp56LLeVE29ye80bvPh+GV0VeJe5tC+7AJf +pnN/iwc6a31lQXMZVjKdtRCrDmK/Ceb3G66+np0OfIjfERsU+fSbJN5tUIb0X0oo +9okBhrBElmN6K2TG2LNd9vcM/n+ulz34H7yQn/g7hgZQqAGwcVCcXVOxpjxfqhyo +fv9nj95K4IBm2LgWFJQNlhv5WpQmtw9iaHKYLEtT+Djl9YA2s2W6fHR6loTMwPV7 +7YcFBpP6XWk0IbHjchvnoBokChpRpUdfKc0xhzee7tkTwckdVBJgRENoVLaIw1RG +RcucR7fzKHjxuXWJ1Qc8H5Qn8vDuRjncCqhSof2XL87qwlT6xUQ4x8iv8MORIwp9 +SvjF0a2fGWCqqvyRIl3ZemrxRWj909tX1MK2Verux0wNJKuTBoT94gouW+yH3NdU +5LA8NMtEpJYrBBPlh6zQ1di2b1MAaNxji2nYWaen//TR/vU+tSYtped10H+BrPNB +zXtu1MiFMhWn6ZtflwHGhRimdyDfIU5iyTgnq2FX8T4fY7sYawWtd9xl2xS6WrRm +UnJfuCKhQcwg9xWbNe/Hk9ak1rEjd8vEo5JXpD5KpTLm2j9zVSZCvWvjRorIMqxQ +CxCPbZAE9uctq6/M8f/zKKLwAVGQP3oB8HWPzcx6/YMy38x4t5SfPzA9yUB0zgsT +LRj8ksKSq1icH1z0016HRKM+34KmTX0gQNImAAzxBY8r0XIAh422qkXdb8+86Mry +bshEKsNqO5OhSGhz+oHidZDprepqh7KhuO1rqPFYAEd2JvMGEIcnZRc1VeLMrSlf +pI6Pu/yPWOu7U4GAfHugN1Lt/Yot16ls8/PXR8m3//Wq7MED2wGMbokiIKmPnSL/ +ThIb+v2nu9lib9ixbqycnDmR6hhJhQYdSKNOEh0EXfsynll9XxQCnBUqCSUKdlfc +vHikP+ACyhaLxuRRLQFi2nU1MyJayeBCl0G3N6bkIY2dA7oIXiUSb1uSUtV2Mp8y +8Mrj0ZrBgCJcqKKTxf7GGHWFZ+WhTBGDyigSA8mBMLtO4cX2XCWvXv6w+c8YQJ60 +zm+lxYRemjw9ND1HnPQpQjYsJqgm8HA5GyqWQOxMun6dqYy+Ev1/CRhXYCnxa3cz +B3LpUR8cI2H8JSxHdl3SSKb63oGY91gaSaFU5CXp+tQBTpqCeqnqmsIJm/bipvls +mCKBZzE+OCJOYS4bO4/Lbg== diff --git a/scripts/ios/package.sh b/scripts/ios/package.sh new file mode 100755 index 000000000..56bd325eb --- /dev/null +++ b/scripts/ios/package.sh @@ -0,0 +1,138 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail +set -u + +NAME=Mapbox +OUTPUT=build/ios/pkg +IOS_SDK_VERSION=`xcrun --sdk iphoneos --show-sdk-version` +LIBUV_VERSION=0.10.28 + +if [[ ${#} -eq 0 ]]; then # e.g. "make ipackage" + BUILD_FOR_DEVICE=true + GCC_GENERATE_DEBUGGING_SYMBOLS="YES" +elif [[ ${1} == "sim" ]]; then # e.g. "make ipackage-sim" + BUILD_FOR_DEVICE=false + GCC_GENERATE_DEBUGGING_SYMBOLS="YES" +else # e.g. "make ipackage-strip" + BUILD_FOR_DEVICE=true + GCC_GENERATE_DEBUGGING_SYMBOLS="NO" +fi + +function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; } +function finish { >&2 echo -en "\033[0m"; } +trap finish EXIT + + +rm -rf ${OUTPUT} +mkdir -p "${OUTPUT}"/static + + +step "Recording library version..." +VERSION="${OUTPUT}"/static/version.txt +echo -n "https://github.com/mapbox/mapbox-gl-native/commit/" > ${VERSION} +HASH=`git log | head -1 | awk '{ print $2 }' | cut -c 1-10` && true +echo -n "mapbox-gl-native " +echo ${HASH} +echo ${HASH} >> ${VERSION} + + +step "Creating build files..." +export MASON_PLATFORM=ios +export BUILDTYPE=${BUILDTYPE:-Release} +export HOST=ios +make Xcode/ios + +if [[ "${BUILD_FOR_DEVICE}" == true ]]; then + step "Building iOS device targets..." + xcodebuild -sdk iphoneos${IOS_SDK_VERSION} \ + ARCHS="arm64 armv7 armv7s" \ + ONLY_ACTIVE_ARCH=NO \ + GCC_GENERATE_DEBUGGING_SYMBOLS=${GCC_GENERATE_DEBUGGING_SYMBOLS} \ + -project ./build/ios-all/mbgl.xcodeproj \ + -configuration ${BUILDTYPE} \ + -target everything \ + -jobs ${JOBS} | xcpretty -c +fi + +step "Building iOS Simulator targets..." +xcodebuild -sdk iphonesimulator${IOS_SDK_VERSION} \ + ARCHS="x86_64 i386" \ + ONLY_ACTIVE_ARCH=NO \ + GCC_GENERATE_DEBUGGING_SYMBOLS=${GCC_GENERATE_DEBUGGING_SYMBOLS} \ + -project ./build/ios-all/mbgl.xcodeproj \ + -configuration ${BUILDTYPE} \ + -target everything \ + -jobs ${JOBS} | xcpretty -c + + +step "Building static library..." +LIBS=(core.a platform-ios.a asset-fs.a cache-sqlite.a http-nsurl.a) +if [[ "${BUILD_FOR_DEVICE}" == true ]]; then + libtool -static -no_warning_for_no_symbols \ + -o ${OUTPUT}/static/lib${NAME}.a \ + ${LIBS[@]/#/build/${BUILDTYPE}-iphoneos/libmbgl-} \ + ${LIBS[@]/#/build/${BUILDTYPE}-iphonesimulator/libmbgl-} \ + `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libuv.a` +else + libtool -static -no_warning_for_no_symbols \ + -o ${OUTPUT}/static/lib${NAME}.a \ + ${LIBS[@]/#/build/${BUILDTYPE}-iphonesimulator/libmbgl-} \ + `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libuv.a` +fi +echo "Created ${OUTPUT}/static/lib${NAME}.a" + + +step "Copying Headers..." +mkdir -p "${OUTPUT}/static/Headers" +for i in `ls -R include/mbgl/ios | grep -vi private`; do + cp -pv include/mbgl/ios/$i "${OUTPUT}/static/Headers" +done + +step "Setting up dummy source file for CocoaPods 0.37.0..." +echo "// https://github.com/mapbox/mapbox-gl-native/issues/1426" > "${OUTPUT}/static/MGLDummy.m" + + +# Manually create resource bundle. We don't use a GYP target here because of +# complications between faked GYP bundles-as-executables, device build +# dependencies, and code signing. +step "Copying Resources..." +cp -pv LICENSE.md "${OUTPUT}/static" +mkdir -p "${OUTPUT}/static/${NAME}.bundle" +cp -pv platform/ios/resources/* "${OUTPUT}/static/${NAME}.bundle" +mkdir -p "${OUTPUT}/static/${NAME}.bundle/styles" +cp -pv styles/styles/{dark,emerald,light,mapbox-streets,satellite}-v7.json "${OUTPUT}/static/${NAME}.bundle/styles" + +step "Creating API Docs..." +if [ -z `which appledoc` ]; then + echo "Unable to find appledoc. See https://github.com/mapbox/mapbox-gl-native#manually" + exit 1 +fi +DOCS_OUTPUT="${OUTPUT}/static/Docs" +git fetch --tags +DOCS_VERSION=$( git tag --sort -v:refname | grep -v '\-rc.' | sed -n '1p' | sed 's/^v//' ) +rm -rf /tmp/mbgl +mkdir -p /tmp/mbgl/ +README=/tmp/mbgl/README.md +cat ios/docs/pod-README.md > ${README} +echo >> ${README} +echo -n "#" >> ${README} +cat CHANGELOG.md >> ${README} +# Copy headers to a temporary location where we can substitute macros that appledoc doesn't understand. +cp -r "${OUTPUT}/static/Headers" /tmp/mbgl +perl \ + -pi \ + -e 's/NS_(?:(MUTABLE)_)?(ARRAY|SET|DICTIONARY)_OF\(\s*(.+?)\s*\)/NS\L\u$1\u$2\E <$3>/g' \ + /tmp/mbgl/Headers/*.h +appledoc \ + --output ${DOCS_OUTPUT} \ + --project-name "Mapbox iOS SDK ${DOCS_VERSION}" \ + --project-company Mapbox \ + --create-html \ + --no-create-docset \ + --no-install-docset \ + --company-id com.mapbox \ + --index-desc ${README} \ + /tmp/mbgl/Headers +cp ${README} "${OUTPUT}/static" diff --git a/scripts/ios/publish.sh b/scripts/ios/publish.sh new file mode 100755 index 000000000..61270fb45 --- /dev/null +++ b/scripts/ios/publish.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail +set -u + +# +# iOS release tag format is `vX.Y.Z`; `X.Y.Z` gets passed in +# In the case of symbolicated builds, we also append the `style`. +# +PUBLISH_VERSION="$1" + +if [[ ${#} -eq 2 ]]; then + PUBLISH_STYLE="-$2" +else + PUBLISH_STYLE="" +fi + +# +# zip +# +cd build/ios/pkg/static +ZIP=mapbox-ios-sdk-${PUBLISH_VERSION}${PUBLISH_STYLE}.zip +rm -f ../${ZIP} +zip -r ../${ZIP} * +# +# upload +# +REPO_NAME=$(basename $TRAVIS_REPO_SLUG) +aws s3 cp ../${ZIP} s3://mapbox/$REPO_NAME/ios/builds/ --acl public-read > /dev/null +echo http://mapbox.s3.amazonaws.com/$REPO_NAME/ios/builds/${ZIP} diff --git a/scripts/ios/remove-key.sh b/scripts/ios/remove-key.sh new file mode 100755 index 000000000..56b769ac2 --- /dev/null +++ b/scripts/ios/remove-key.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +security delete-keychain ios-build.keychain +rm -f "~/Library/MobileDevice/Provisioning Profiles/$IOS_PROFILE_NAME.mobileprovision" diff --git a/scripts/ios/run.sh b/scripts/ios/run.sh new file mode 100755 index 000000000..c23b485e2 --- /dev/null +++ b/scripts/ios/run.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail +set -u + +source ./scripts/ios/setup.sh + +BUILDTYPE=${BUILDTYPE:-Release} + +PUBLISH_TAG=($(git show -s --format=%B | sed -n 's/.*\[publish \([a-z]\{1,\}\)-v\([0-9a-z.\-]\{1,\}\)\].*/\1 \2/p')) +PUBLISH_PLATFORM=${PUBLISH_TAG[0],-} +PUBLISH_VERSION=${PUBLISH_TAG[1],-} + + +################################################################################ +# Build +################################################################################ + +if [[ ${PUBLISH_PLATFORM} = 'ios' ]]; then + # default, with debug symbols + mapbox_time "package_ios_symbols" \ + make ipackage + + mapbox_time "deploy_ios_symbols" + ./scripts/ios/publish.sh "${PUBLISH_VERSION}" symbols + + # no debug symbols, for smaller distribution + mapbox_time "package_ios_stripped" \ + make ipackage-strip + + mapbox_time "deploy_ios_stripped" + ./scripts/ios/publish.sh "${PUBLISH_VERSION}" +else + # build & test iOS + mapbox_time "run_ios_tests" \ + make itest +fi diff --git a/scripts/ios/setup.sh b/scripts/ios/setup.sh new file mode 100644 index 000000000..d115cf902 --- /dev/null +++ b/scripts/ios/setup.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# This script is sourced; do not set -e or -o pipefail here. + +# Ensure mason is on the PATH +export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason" diff --git a/scripts/ios/test.sh b/scripts/ios/test.sh new file mode 100755 index 000000000..170aa0f64 --- /dev/null +++ b/scripts/ios/test.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail +set -u + +xctool \ + -project ./test/ios/ios-tests.xcodeproj \ + -scheme 'Mapbox GL Tests' \ + -sdk iphonesimulator8.4 \ + test diff --git a/scripts/linux/after_script.sh b/scripts/linux/after_script.sh new file mode 100755 index 000000000..c38af0a79 --- /dev/null +++ b/scripts/linux/after_script.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +if [ ! -z "${AWS_ACCESS_KEY_ID}" ] && [ ! -z "${AWS_SECRET_ACCESS_KEY}" ] ; then + # Install and add awscli to PATH for uploading the results + mapbox_time "install_awscli" \ + pip install --user awscli + export PATH="`python -m site --user-base`/bin:${PATH}" + + mapbox_time_start "deploy_results" + (cd ./test/suite/ && ./bin/deploy_results.sh) + mapbox_time_finish +fi diff --git a/scripts/linux/configure.sh b/scripts/linux/configure.sh new file mode 100644 index 000000000..1099a6550 --- /dev/null +++ b/scripts/linux/configure.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +BOOST_VERSION=1.57.0 +BOOST_LIBPROGRAM_OPTIONS_VERSION=1.57.0 +LIBCURL_VERSION=system +GLFW_VERSION=3.1 +LIBPNG_VERSION=1.6.16 +JPEG_VERSION=v9a +SQLITE_VERSION=3.8.8.1 +LIBUV_VERSION=0.10.28 +ZLIB_VERSION=system +NUNICODE_VERSION=1.5.1 +LIBZIP_VERSION=0.11.2 + +function print_opengl_flags { + CONFIG+=" 'opengl_cflags%': $(quote_flags $(pkg-config gl x11 --cflags)),"$LN + CONFIG+=" 'opengl_ldflags%': $(quote_flags $(pkg-config gl x11 --libs)),"$LN +} diff --git a/scripts/linux/defaults.mk b/scripts/linux/defaults.mk new file mode 100644 index 000000000..126c8f99a --- /dev/null +++ b/scripts/linux/defaults.mk @@ -0,0 +1,5 @@ +HEADLESS ?= glx +PLATFORM ?= linux +ASSET ?= fs +HTTP ?= curl +CACHE ?= sqlite diff --git a/scripts/linux/install.sh b/scripts/linux/install.sh new file mode 100755 index 000000000..a254d312e --- /dev/null +++ b/scripts/linux/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +mapbox_time "checkout_mason" \ +git submodule update --init .mason + +PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason" \ +mapbox_time "install_mesa" \ +mason install mesa 10.4.3 diff --git a/scripts/linux/run.sh b/scripts/linux/run.sh new file mode 100755 index 000000000..42d2a16d9 --- /dev/null +++ b/scripts/linux/run.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +source ./scripts/linux/setup.sh + +BUILDTYPE=${BUILDTYPE:-Release} + +################################################################################ +# Build +################################################################################ + +mapbox_time "checkout_styles" \ +git submodule update --init styles + +mapbox_time "compile_program" \ +make linux -j${JOBS} BUILDTYPE=${BUILDTYPE} + +mapbox_time "compile_render_binary" \ +make render -j${JOBS} BUILDTYPE=${BUILDTYPE} + +mapbox_time "compile_tests" \ +make test -j${JOBS} BUILDTYPE=${BUILDTYPE} + +################################################################################ +# Test +################################################################################ + +mapbox_time "checkout_test_suite" \ +git submodule update --init test/suite + +mapbox_time "run_tests" \ +make test-* BUILDTYPE=${BUILDTYPE} + +mapbox_time "compare_results" \ +./scripts/compare_images.sh diff --git a/scripts/linux/setup.sh b/scripts/linux/setup.sh new file mode 100755 index 000000000..af0eafb5c --- /dev/null +++ b/scripts/linux/setup.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# This script is sourced; do not set -e or -o pipefail here. + +# Ensure mason is on the PATH +export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason" + +# Set the core file limit to unlimited so a core file is generated upon crash +ulimit -c unlimited -S + +################################################################################ +# X Server setup +################################################################################ + +# Start the mock X server +if [ -f /etc/init.d/xvfb ] ; then + mapbox_time "start_xvfb" \ + sh -e /etc/init.d/xvfb start + sleep 2 # sometimes, xvfb takes some time to start up +fi + +# Make sure we're connecting to xvfb +export DISPLAY=:99.0 + +# Make sure we're loading the 10.4.3 libs we installed manually +export LD_LIBRARY_PATH="`mason prefix mesa 10.4.3`/lib:${LD_LIBRARY_PATH:-}" + +mapbox_time "glxinfo" \ +glxinfo diff --git a/scripts/main.mk b/scripts/main.mk new file mode 100644 index 000000000..d61a61e03 --- /dev/null +++ b/scripts/main.mk @@ -0,0 +1,130 @@ +ifeq (,$(V)) + QUIET = @ +endif + +# Determine host platform +HOST ?= $(BUILD) + +# Defines host defaults +include scripts/$(HOST)/defaults.mk + +HOST_VERSION ?= $(BUILD_VERSION) + +# Optionally include version-specific host defaults +-include scripts/$(HOST)/$(HOST_VERSION)/defaults.mk + +export MASON_PLATFORM=$(HOST) +export MASON_PLATFORM_VERSION=$(HOST_VERSION) + +HOST_SLUG = $(HOST)-$(HOST_VERSION) +CONFIGURE_FILES = scripts/$(HOST)/configure.sh +ifneq (,$(wildcard scripts/$(HOST)/$(HOST_VERSION)/configure.sh)) + CONFIGURE_FILES += scripts/$(HOST)/$(HOST_VERSION)/configure.sh +endif + + +# Text formatting +TEXT_BOLD = \033[1m +COLOR_GREEN = \033[32m +COLOR_CYAN = \033[36m +COLOR_PINK = \033[35m +FORMAT_END = \033[0m + +default: ; + +#### Dependencies ############################################################## + +SUBMODULES += .mason/mason.sh +.mason/mason.sh: + ./scripts/flock.py .git/Submodule.lock git submodule update --init .mason + +SUBMODULES += styles/styles +styles/styles: + ./scripts/flock.py .git/Submodule.lock git submodule update --init styles + +SUBMODULES += src/mbgl/util/geojsonvt/geojsonvt.hpp +src/mbgl/util/geojsonvt/geojsonvt.hpp: + ./scripts/flock.py .git/Submodule.lock git submodule update --init src/mbgl/util/geojsonvt + +SUBMODULES += test/suite/package.json +test/suite/package.json: + ./scripts/flock.py .git/Submodule.lock git submodule update --init test/suite + +ifeq ($(HOST),ios) +SUBMODULES += platform/ios/vendor/SMCalloutView/SMCalloutView.h +platform/ios/vendor/SMCalloutView/SMCalloutView.h: + ./scripts/flock.py .git/Submodule.lock git submodule update --init platform/ios/vendor/SMCalloutView + +SUBMODULES += test/ios/KIF/KIF.xcodeproj +test/ios/KIF/KIF.xcodeproj: + ./scripts/flock.py .git/Submodule.lock git submodule update --init test/ios/KIF +endif + +# Wildcard targets get removed after build by default, but we want to preserve the config. +.PRECIOUS: config/%.gypi +config/%.gypi: $(SUBMODULES) configure $(CONFIGURE_FILES) + @printf "$(TEXT_BOLD)$(COLOR_GREEN)* Recreating project...$(FORMAT_END)\n" + $(QUIET)$(ENV) ./scripts/flock.py build/Configure.lock ./configure config/$*.gypi + + +#### Build files ############################################################### + +GYP_FLAGS += -Dhost=$(HOST) +GYP_FLAGS += -Iconfig/$(HOST_SLUG).gypi +GYP_FLAGS += -Dplatform_lib=$(PLATFORM) +GYP_FLAGS += -Dhttp_lib=$(HTTP) +GYP_FLAGS += -Dasset_lib=$(ASSET) +GYP_FLAGS += -Dcache_lib=$(CACHE) +GYP_FLAGS += -Dheadless_lib=$(HEADLESS) +GYP_FLAGS += -Dtest=$(BUILD_TEST) +GYP_FLAGS += -Drender=$(BUILD_RENDER) +GYP_FLAGS += --depth=. +GYP_FLAGS += -Goutput_dir=. +GYP_FLAGS += --generator-output=./build/$(HOST_SLUG) + +.PHONY: Makefile/__project__ +Makefile/__project__: print-env $(SUBMODULES) config/$(HOST_SLUG).gypi + @printf "$(TEXT_BOLD)$(COLOR_GREEN)* Recreating project...$(FORMAT_END)\n" + $(QUIET)$(ENV) deps/run_gyp gyp/$(HOST).gyp $(GYP_FLAGS) -f make$(GYP_FLAVOR_SUFFIX) + +.PHONY: Xcode/__project__ +Xcode/__project__: print-env $(SUBMODULES) config/$(HOST_SLUG).gypi + @printf "$(TEXT_BOLD)$(COLOR_GREEN)* Recreating project...$(FORMAT_END)\n" + $(QUIET)$(ENV) deps/run_gyp gyp/$(HOST).gyp $(GYP_FLAGS) -f xcode$(GYP_FLAVOR_SUFFIX) + +#### Build individual targets ################################################## + +Makefile/%: Makefile/__project__ + @printf "$(TEXT_BOLD)$(COLOR_GREEN)* Building target $*...$(FORMAT_END)\n" + $(QUIET)$(ENV) $(MAKE) -C build/$(HOST_SLUG) BUILDTYPE=$(BUILDTYPE) $* + +Xcode/%: Xcode/__project__ + @printf "$(TEXT_BOLD)$(COLOR_GREEN)* Building target $*...$(FORMAT_END)\n" + $(QUIET)$(ENV) set -o pipefail && xcodebuild \ + $(XCODEBUILD_ARGS) \ + -project ./build/$(HOST_SLUG)/gyp/$(HOST).xcodeproj \ + -configuration $(BUILDTYPE) \ + -target $* \ + -jobs $(JOBS) \ + $(XCPRETTY) + +#### Run tests ################################################################# + +test-%: Makefile/test + ./scripts/run_tests.sh "build/$(HOST_SLUG)/$(BUILDTYPE)/test" --gtest_filter=$* + +#### Helper targets ############################################################ + +.PHONY: print-env +print-env: $(SUBMODULES) + @printf "$(COLOR_PINK)build:$(FORMAT_END) $(BUILD)/$(BUILD_VERSION)\n" + @printf "$(COLOR_PINK)host:$(FORMAT_END) $(HOST)/$(HOST_VERSION)\n" + @printf "$(COLOR_PINK)libs:$(FORMAT_END) " + @printf "headless=$(COLOR_CYAN)%s$(FORMAT_END) " $(HEADLESS) + @printf "platform=$(COLOR_CYAN)%s$(FORMAT_END) " $(PLATFORM) + @printf "asset=$(COLOR_CYAN)%s$(FORMAT_END) " $(ASSET) + @printf "http=$(COLOR_CYAN)%s$(FORMAT_END) " $(HTTP) + @printf "cache=$(COLOR_CYAN)%s$(FORMAT_END)\n" $(CACHE) + +# Never remove intermediate files +.SECONDARY: diff --git a/scripts/osx/configure.sh b/scripts/osx/configure.sh new file mode 100644 index 000000000..fc3c5f464 --- /dev/null +++ b/scripts/osx/configure.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +BOOST_VERSION=1.57.0 +BOOST_LIBPROGRAM_OPTIONS_VERSION=1.57.0 +LIBCURL_VERSION=system +GLFW_VERSION=3.1 +LIBPNG_VERSION=1.6.16 +JPEG_VERSION=v9a +SQLITE_VERSION=3.8.8.1 +LIBUV_VERSION=0.10.28 +ZLIB_VERSION=system +NUNICODE_VERSION=1.5.1 +LIBZIP_VERSION=0.11.2 diff --git a/scripts/osx/defaults.mk b/scripts/osx/defaults.mk new file mode 100644 index 000000000..f148f66d8 --- /dev/null +++ b/scripts/osx/defaults.mk @@ -0,0 +1,5 @@ +HEADLESS ?= cgl +PLATFORM ?= osx +ASSET ?= fs +HTTP ?= nsurl +CACHE ?= sqlite diff --git a/scripts/osx/install.sh b/scripts/osx/install.sh new file mode 100755 index 000000000..d6d9c065c --- /dev/null +++ b/scripts/osx/install.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +mapbox_time "checkout_mason" \ +git submodule update --init .mason + +mapbox_time "install_xcpretty" \ +gem install xcpretty --no-rdoc --no-ri --no-document --quiet diff --git a/scripts/osx/run.sh b/scripts/osx/run.sh new file mode 100755 index 000000000..86a729152 --- /dev/null +++ b/scripts/osx/run.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +source ./scripts/osx/setup.sh + +BUILDTYPE=${BUILDTYPE:-Release} + +################################################################################ +# Build +################################################################################ + +mapbox_time "checkout_styles" \ +git submodule update --init styles + +mapbox_time "checkout_geojsonvt" \ +git submodule update --init src/mbgl/util/geojsonvt + +mapbox_time "compile_program" \ +make xosx -j${JOBS} BUILDTYPE=${BUILDTYPE} + +mapbox_time "compile_render_binary" \ +make xrender -j${JOBS} BUILDTYPE=${BUILDTYPE} + +mapbox_time "compile_tests" \ +make xtest -j${JOBS} BUILDTYPE=${BUILDTYPE} diff --git a/scripts/osx/setup.sh b/scripts/osx/setup.sh new file mode 100755 index 000000000..502d61d44 --- /dev/null +++ b/scripts/osx/setup.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# This script is sourced; do not set -e or -o pipefail here. + +# Ensure mason is on the PATH +export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason" + +# Set the core file limit to unlimited so a core file is generated upon crash +ulimit -c unlimited -S diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh new file mode 100755 index 000000000..692269e4f --- /dev/null +++ b/scripts/run_tests.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +if [ `uname -s` = 'Darwin' ]; then HOST=${HOST:-osx} ; else HOST=${HOST:-linux} ; fi + +CMD=$@ +shift + +# allow writing core files +ulimit -c unlimited -S +echo 'ulimit -c: '`ulimit -c` +if [ -f /proc/sys/kernel/core_pattern ]; then + echo '/proc/sys/kernel/core_pattern: '`cat /proc/sys/kernel/core_pattern` +fi + +if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then + sysctl kernel.core_pattern +fi + +# install test server dependencies +if [ ! -d "test/node_modules/express" ]; then + (cd test; npm install express@4.11.1) +fi + +if which -s 'gdb'; then + gdb -batch -return-child-result -ex 'set print thread-events off' \ + -ex 'run' -ex 'thread apply all bt' --args ${CMD} ; +else + ${CMD} ; +fi diff --git a/scripts/travis_helper.sh b/scripts/travis_helper.sh new file mode 100755 index 000000000..5a765b131 --- /dev/null +++ b/scripts/travis_helper.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +# This script is sourced, so do not set -e or -o pipefail here. Doing so would +# bleed into Travis' wrapper script, which messes with their workflow, e.g. +# preventing after_failure scripts to be triggered. + +case `uname -s` in + 'Darwin') JOBS=$((`sysctl -n hw.ncpu` + 2)) ;; + 'Linux') JOBS=$((`nproc` + 2)) ;; + *) JOBS=2 ;; +esac + +ANSI_CLEAR="\e[0m" + +function mapbox_time_start { + local name=$1 + mapbox_timer_name=$name + + mapbox_fold start $name + + mapbox_timer_id=$(printf %08x $(( RANDOM * RANDOM ))) + eval "mapbox_start_time_$mapbox_timer_id=$(mapbox_nanoseconds)" + echo -en "travis_time:start:$mapbox_timer_id\n" +} + +function mapbox_time_finish { + local name=${1:-$mapbox_timer_name} + local timer_id=${2:-$mapbox_timer_id} + local timer_start="mapbox_start_time_$timer_id" + eval local start_time=\${$timer_start} + local end_time=$(mapbox_nanoseconds) + local duration=$(($end_time-$start_time)) + echo -en "travis_time:end:$timer_id:start=$start_time,finish=$end_time,duration=$duration\n" + + mapbox_fold end $name +} + +function mapbox_time { + local name=$1 ; shift + mapbox_time_start $name + local timer_id=$mapbox_timer_id + echo "\$ $@" + $@ + mapbox_time_finish $name $timer_id +} + +function mapbox_fold { + local action=$1 + local name=$2 + echo -en "travis_fold:${action}:${name}\r${ANSI_CLEAR}" +} + +function mapbox_nanoseconds { + local cmd="date" + local format="+%s%N" + local os=$(uname) + + if hash gdate > /dev/null 2>&1; then + cmd="gdate" # use gdate if available + elif [[ "$os" = Darwin ]]; then + format="+%s000000000" # fallback to second precision on darwin (does not support %N) + fi + + $cmd -u $format +} + +export JOBS +export ANSI_CLEAR +export -f mapbox_fold +export -f mapbox_nanoseconds +export -f mapbox_time +export -f mapbox_time_start +export -f mapbox_time_finish diff --git a/scripts/valgrind.sup b/scripts/valgrind.sup new file mode 100644 index 000000000..fcde049d9 --- /dev/null +++ b/scripts/valgrind.sup @@ -0,0 +1,91 @@ +{ + Valgrind gets confused with buffers managed by the graphics driver + Memcheck:Leak + ... + obj:/usr/*/dri/r600_dri.so + ... +} +{ + GLFW _glfwCreateCursor() + Memcheck:Leak + match-leak-kinds: reachable + ... + obj:/usr/*/libX11.so.6.3.0 + ... + fun:_glfwCreateCursor + ... +} +{ + GLFW _glfwPlatform*() + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:_glfwPlatform* + ... +} +{ + Buffer managed by OpenGL? + Memcheck:Cond + ... + fun:_ZN4mbgl*Uniform* + ... + fun:_ZN8GLFWView10invalidateEv + ... +} +{ + Buffer managed by OpenGL? + Memcheck:Cond + fun:_ZNSt7__equalILb0EE5equalIPKfS3_EEbT_S4_T0_ + ... + fun:_ZN4mbgl7Painter11renderLayerERKNS_10StyleLayerEPKNS_4Tile2IDEPKSt5arrayIfLm16EE +} +{ + Valgrind doesn't like our make_unique (C++14 polyfill) + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + ... + fun:_ZN4mbgl4util11make_unique* + ... +} +{ + dlopen doing its magic + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:_dl_open + ... +} +{ + X11 false positive + Memcheck:Leak + match-leak-kinds: reachable + ... + obj:/usr/*/libX11.so.6.3.0 + ... + fun:_XrmInitParseInfo + ... +} +{ + OpenSSL false positive + Memcheck:Leak + ... + fun:CRYPTO_malloc + ... +} +{ + OpenSSL false positive + Memcheck:Leak + ... + fun:CRYPTO_realloc + ... +} +{ + Libcurl false positive + Memcheck:Leak + fun:malloc + ... + obj:/usr/*/libcurl.so.4.3.0 + fun:curl_multi_socket_action + ... +} diff --git a/scripts/xcpretty.sh b/scripts/xcpretty.sh new file mode 100755 index 000000000..c39f58822 --- /dev/null +++ b/scripts/xcpretty.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +FN=$(which xcpretty) ; [ ! -z ${FN} ] && echo "| ${FN}" diff --git a/src/clipper/clipper.cpp b/src/clipper/clipper.cpp new file mode 100755 index 000000000..f5d8cd3c9 --- /dev/null +++ b/src/clipper/clipper.cpp @@ -0,0 +1,4612 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 6.1.3a * +* Date : 22 January 2014 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2014 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Attributions: * +* The code in this library is an extension of Bala Vatti's clipping algorithm: * +* "A generic solution to polygon clipping" * +* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * +* http://portal.acm.org/citation.cfm?id=129906 * +* * +* Computer graphics and geometric modeling: implementation and algorithms * +* By Max K. Agoston * +* Springer; 1 edition (January 4, 2005) * +* http://books.google.com/books?q=vatti+clipping+agoston * +* * +* See also: * +* "Polygon Offsetting by Computing Winding Numbers" * +* Paper no. DETC2005-85513 pp. 565-575 * +* ASME 2005 International Design Engineering Technical Conferences * +* and Computers and Information in Engineering Conference (IDETC/CIE2005) * +* September 24-28, 2005 , Long Beach, California, USA * +* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * +* * +*******************************************************************************/ + +/******************************************************************************* +* * +* This is a translation of the Delphi Clipper library and the naming style * +* used has retained a Delphi flavour. * +* * +*******************************************************************************/ + +#include "clipper.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic ignored "-Wshadow" + +namespace ClipperLib { + +#ifdef use_int32 + static cInt const loRange = 46340; + static cInt const hiRange = 46340; +#else + static cInt const loRange = 0x3FFFFFFF; + static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; + typedef unsigned long long ulong64; +#endif + +static double const pi = 3.141592653589793238; +static double const two_pi = pi *2; +static double const def_arc_tolerance = 0.25; + +enum Direction { dRightToLeft, dLeftToRight }; + +static int const Unassigned = -1; //edge not currently 'owning' a solution +static int const Skip = -2; //edge that would otherwise close a path + +#define HORIZONTAL (-1.0E+40) +#define TOLERANCE (1.0e-20) +#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) + +struct TEdge { + IntPoint Bot; + IntPoint Curr; + IntPoint Top; + IntPoint Delta; + double Dx; + PolyType PolyTyp; + EdgeSide Side; + int WindDelta; //1 or -1 depending on winding direction + int WindCnt; + int WindCnt2; //winding count of the opposite polytype + int OutIdx; + TEdge *Next; + TEdge *Prev; + TEdge *NextInLML; + TEdge *NextInAEL; + TEdge *PrevInAEL; + TEdge *NextInSEL; + TEdge *PrevInSEL; +}; + +struct IntersectNode { + TEdge *Edge1; + TEdge *Edge2; + IntPoint Pt; +}; + +struct LocalMinima { + cInt Y; + TEdge *LeftBound; + TEdge *RightBound; + LocalMinima *Next; +}; + +struct OutPt; + +struct OutRec { + int Idx; + bool IsHole; + bool IsOpen; + OutRec *FirstLeft; //see comments in clipper.pas + PolyNode *PolyNd; + OutPt *Pts; + OutPt *BottomPt; +}; + +struct OutPt { + int Idx; + IntPoint Pt; + OutPt *Next; + OutPt *Prev; +}; + +struct Join { + OutPt *OutPt1; + OutPt *OutPt2; + IntPoint OffPt; +}; + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +inline cInt Round(double val) +{ + if ((val < 0)) return static_cast(val - 0.5); + else return static_cast(val + 0.5); +} +//------------------------------------------------------------------------------ + +inline cInt Abs(cInt val) +{ + return val < 0 ? -val : val; +} + +//------------------------------------------------------------------------------ +// PolyTree methods ... +//------------------------------------------------------------------------------ + +void PolyTree::Clear() +{ + for (PolyNodes::size_type i = 0; i < AllNodes.size(); ++i) + delete AllNodes[i]; + AllNodes.resize(0); + Childs.resize(0); +} +//------------------------------------------------------------------------------ + +PolyNode* PolyTree::GetFirst() const +{ + if (!Childs.empty()) + return Childs[0]; + else + return 0; +} +//------------------------------------------------------------------------------ + +int PolyTree::Total() const +{ + return (int)AllNodes.size(); +} + +//------------------------------------------------------------------------------ +// PolyNode methods ... +//------------------------------------------------------------------------------ + +PolyNode::PolyNode(): Childs(), Parent(0), Index(0), m_IsOpen(false) +{ +} +//------------------------------------------------------------------------------ + +int PolyNode::ChildCount() const +{ + return (int)Childs.size(); +} +//------------------------------------------------------------------------------ + +void PolyNode::AddChild(PolyNode& child) +{ + unsigned cnt = (unsigned)Childs.size(); + Childs.push_back(&child); + child.Parent = this; + child.Index = cnt; +} +//------------------------------------------------------------------------------ + +PolyNode* PolyNode::GetNext() const +{ + if (!Childs.empty()) + return Childs[0]; + else + return GetNextSiblingUp(); +} +//------------------------------------------------------------------------------ + +PolyNode* PolyNode::GetNextSiblingUp() const +{ + if (!Parent) //protects against PolyTree.GetNextSiblingUp() + return 0; + else if (Index == Parent->Childs.size() - 1) + return Parent->GetNextSiblingUp(); + else + return Parent->Childs[Index + 1]; +} +//------------------------------------------------------------------------------ + +bool PolyNode::IsHole() const +{ + bool result = true; + PolyNode* node = Parent; + while (node) + { + result = !result; + node = node->Parent; + } + return result; +} +//------------------------------------------------------------------------------ + +bool PolyNode::IsOpen() const +{ + return m_IsOpen; +} +//------------------------------------------------------------------------------ + +#ifndef use_int32 + +//------------------------------------------------------------------------------ +// Int128 class (enables safe math on signed 64bit integers) +// eg Int128 val1((cInt)9223372036854775807); //ie 2^63 -1 +// Int128 val2((cInt)9223372036854775807); +// Int128 val3 = val1 * val2; +// val3.AsString => "85070591730234615847396907784232501249" (8.5e+37) +//------------------------------------------------------------------------------ + +class Int128 +{ + public: + + cUInt lo; + cInt hi; + + Int128(cInt _lo = 0) + { + lo = (cUInt)_lo; + if (_lo < 0) hi = -1; else hi = 0; + } + + + Int128(const Int128 &val): lo(val.lo), hi(val.hi){} + + Int128(const cInt& _hi, const ulong64& _lo): lo(_lo), hi(_hi){} + + Int128& operator = (const cInt &val) + { + lo = (ulong64)val; + if (val < 0) hi = -1; else hi = 0; + return *this; + } + + bool operator == (const Int128 &val) const + {return (hi == val.hi && lo == val.lo);} + + bool operator != (const Int128 &val) const + { return !(*this == val);} + + bool operator > (const Int128 &val) const + { + if (hi != val.hi) + return hi > val.hi; + else + return lo > val.lo; + } + + bool operator < (const Int128 &val) const + { + if (hi != val.hi) + return hi < val.hi; + else + return lo < val.lo; + } + + bool operator >= (const Int128 &val) const + { return !(*this < val);} + + bool operator <= (const Int128 &val) const + { return !(*this > val);} + + Int128& operator += (const Int128 &rhs) + { + hi += rhs.hi; + lo += rhs.lo; + if (lo < rhs.lo) hi++; + return *this; + } + + Int128 operator + (const Int128 &rhs) const + { + Int128 result(*this); + result+= rhs; + return result; + } + + Int128& operator -= (const Int128 &rhs) + { + *this += -rhs; + return *this; + } + + Int128 operator - (const Int128 &rhs) const + { + Int128 result(*this); + result -= rhs; + return result; + } + + Int128 operator-() const //unary negation + { + if (lo == 0) + return Int128(-hi,0); + else + return Int128(~hi,~lo +1); + } + + Int128 operator/ (const Int128 &rhs) const + { + if (rhs.lo == 0 && rhs.hi == 0) + throw "Int128 operator/: divide by zero"; + + bool negate = (rhs.hi < 0) != (hi < 0); + Int128 dividend = *this; + Int128 divisor = rhs; + if (dividend.hi < 0) dividend = -dividend; + if (divisor.hi < 0) divisor = -divisor; + + if (divisor < dividend) + { + Int128 result = Int128(0); + Int128 cntr = Int128(1); + while (divisor.hi >= 0 && !(divisor > dividend)) + { + divisor.hi <<= 1; + if ((cInt)divisor.lo < 0) divisor.hi++; + divisor.lo <<= 1; + + cntr.hi <<= 1; + if ((cInt)cntr.lo < 0) cntr.hi++; + cntr.lo <<= 1; + } + divisor.lo >>= 1; + if ((divisor.hi & 1) == 1) + divisor.lo |= 0x8000000000000000LL; + divisor.hi = (ulong64)divisor.hi >> 1; + + cntr.lo >>= 1; + if ((cntr.hi & 1) == 1) + cntr.lo |= 0x8000000000000000LL; + cntr.hi >>= 1; + + while (cntr.hi != 0 || cntr.lo != 0) + { + if (!(dividend < divisor)) + { + dividend -= divisor; + result.hi |= cntr.hi; + result.lo |= cntr.lo; + } + divisor.lo >>= 1; + if ((divisor.hi & 1) == 1) + divisor.lo |= 0x8000000000000000LL; + divisor.hi >>= 1; + + cntr.lo >>= 1; + if ((cntr.hi & 1) == 1) + cntr.lo |= 0x8000000000000000LL; + cntr.hi >>= 1; + } + if (negate) result = -result; + return result; + } + else if (rhs.hi == this->hi && rhs.lo == this->lo) + return Int128(negate ? -1: 1); + else + return Int128(0); + } + + double AsDouble() const + { + const double shift64 = 18446744073709551616.0; //2^64 + if (hi < 0) + { + cUInt lo_ = ~lo + 1; + if (lo_ == 0) return (double)hi * shift64; + else return -(double)(lo_ + ~hi * shift64); + } + else + return (double)(lo + hi * shift64); + } + +}; +//------------------------------------------------------------------------------ + +Int128 Int128Mul (cInt lhs, cInt rhs) +{ + bool negate = (lhs < 0) != (rhs < 0); + + if (lhs < 0) lhs = -lhs; + ulong64 int1Hi = ulong64(lhs) >> 32; + ulong64 int1Lo = ulong64(lhs & 0xFFFFFFFF); + + if (rhs < 0) rhs = -rhs; + ulong64 int2Hi = ulong64(rhs) >> 32; + ulong64 int2Lo = ulong64(rhs & 0xFFFFFFFF); + + //nb: see comments in clipper.pas + ulong64 a = int1Hi * int2Hi; + ulong64 b = int1Lo * int2Lo; + ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi; + + Int128 tmp; + tmp.hi = cInt(a + (c >> 32)); + tmp.lo = cInt(c << 32); + tmp.lo += cInt(b); + if (tmp.lo < b) tmp.hi++; + if (negate) tmp = -tmp; + return tmp; +} +#endif + +//------------------------------------------------------------------------------ +// Miscellaneous global functions +//------------------------------------------------------------------------------ + +bool Orientation(const Path &poly) +{ + return Area(poly) >= 0; +} +//------------------------------------------------------------------------------ + +double Area(const Path &poly) +{ + int size = (int)poly.size(); + if (size < 3) return 0; + + double a = 0; + for (int i = 0, j = size -1; i < size; ++i) + { + a += ((double)poly[j].X + poly[i].X) * ((double)poly[j].Y - poly[i].Y); + j = i; + } + return -a * 0.5; +} +//------------------------------------------------------------------------------ + +double Area(const OutRec &outRec) +{ + OutPt *op = outRec.Pts; + if (!op) return 0; + double a = 0; + do { + a += (double)(op->Prev->Pt.X + op->Pt.X) * (double)(op->Prev->Pt.Y - op->Pt.Y); + op = op->Next; + } while (op != outRec.Pts); + return a * 0.5; +} +//------------------------------------------------------------------------------ + +bool PointIsVertex(const IntPoint &Pt, OutPt *pp) +{ + OutPt *pp2 = pp; + do + { + if (pp2->Pt == Pt) return true; + pp2 = pp2->Next; + } + while (pp2 != pp); + return false; +} +//------------------------------------------------------------------------------ + +int PointInPolygon (const IntPoint &pt, const Path &path) +{ + //returns 0 if false, +1 if true, -1 if pt ON polygon boundary + //http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf + int result = 0; + size_t cnt = path.size(); + if (cnt < 3) return 0; + IntPoint ip = path[0]; + for(size_t i = 1; i <= cnt; ++i) + { + IntPoint ipNext = (i == cnt ? path[0] : path[i]); + if (ipNext.Y == pt.Y) + { + if ((ipNext.X == pt.X) || (ip.Y == pt.Y && + ((ipNext.X > pt.X) == (ip.X < pt.X)))) return -1; + } + if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y)) + { + if (ip.X >= pt.X) + { + if (ipNext.X > pt.X) result = 1 - result; + else + { + double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - + (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; + } + } else + { + if (ipNext.X > pt.X) + { + double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - + (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; + } + } + } + ip = ipNext; + } + return result; +} +//------------------------------------------------------------------------------ + +int PointInPolygon (const IntPoint &pt, OutPt *op) +{ + //returns 0 if false, +1 if true, -1 if pt ON polygon boundary + //http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf + int result = 0; + OutPt* startOp = op; + for(;;) + { + if (op->Next->Pt.Y == pt.Y) + { + if ((op->Next->Pt.X == pt.X) || (op->Pt.Y == pt.Y && + ((op->Next->Pt.X > pt.X) == (op->Pt.X < pt.X)))) return -1; + } + if ((op->Pt.Y < pt.Y) != (op->Next->Pt.Y < pt.Y)) + { + if (op->Pt.X >= pt.X) + { + if (op->Next->Pt.X > pt.X) result = 1 - result; + else + { + double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - + (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; + } + } else + { + if (op->Next->Pt.X > pt.X) + { + double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - + (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; + } + } + } + op = op->Next; + if (startOp == op) break; + } + return result; +} +//------------------------------------------------------------------------------ + +bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2) +{ + OutPt* op = OutPt1; + do + { + int res = PointInPolygon(op->Pt, OutPt2); + if (res >= 0) return res != 0; + op = op->Next; + } + while (op != OutPt1); + return true; +} +//---------------------------------------------------------------------- + +bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range) +{ +#ifndef use_int32 + if (UseFullInt64Range) + return Int128Mul(e1.Delta.Y, e2.Delta.X) == Int128Mul(e1.Delta.X, e2.Delta.Y); + else +#endif + return e1.Delta.Y * e2.Delta.X == e1.Delta.X * e2.Delta.Y; +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, + const IntPoint pt3, bool UseFullInt64Range) +{ +#ifndef use_int32 + if (UseFullInt64Range) + return Int128Mul(pt1.Y-pt2.Y, pt2.X-pt3.X) == Int128Mul(pt1.X-pt2.X, pt2.Y-pt3.Y); + else +#endif + return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y); +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, + const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range) +{ +#ifndef use_int32 + if (UseFullInt64Range) + return Int128Mul(pt1.Y-pt2.Y, pt3.X-pt4.X) == Int128Mul(pt1.X-pt2.X, pt3.Y-pt4.Y); + else +#endif + return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y); +} +//------------------------------------------------------------------------------ + +inline bool IsHorizontal(TEdge &e) +{ + return e.Delta.Y == 0; +} +//------------------------------------------------------------------------------ + +inline double GetDx(const IntPoint pt1, const IntPoint pt2) +{ + return (pt1.Y == pt2.Y) ? + HORIZONTAL : (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y); +} +//--------------------------------------------------------------------------- + +inline void SetDx(TEdge &e) +{ + e.Delta.X = (e.Top.X - e.Bot.X); + e.Delta.Y = (e.Top.Y - e.Bot.Y); + + if (e.Delta.Y == 0) e.Dx = HORIZONTAL; + else e.Dx = (double)(e.Delta.X) / e.Delta.Y; +} +//--------------------------------------------------------------------------- + +inline void SwapSides(TEdge &Edge1, TEdge &Edge2) +{ + EdgeSide Side = Edge1.Side; + Edge1.Side = Edge2.Side; + Edge2.Side = Side; +} +//------------------------------------------------------------------------------ + +inline void SwapPolyIndexes(TEdge &Edge1, TEdge &Edge2) +{ + int OutIdx = Edge1.OutIdx; + Edge1.OutIdx = Edge2.OutIdx; + Edge2.OutIdx = OutIdx; +} +//------------------------------------------------------------------------------ + +inline cInt TopX(TEdge &edge, const cInt currentY) +{ + return ( currentY == edge.Top.Y ) ? + edge.Top.X : edge.Bot.X + Round(edge.Dx *(currentY - edge.Bot.Y)); +} +//------------------------------------------------------------------------------ + +bool IntersectPoint(TEdge &Edge1, TEdge &Edge2, + IntPoint &ip, bool UseFullInt64Range) +{ +#ifdef use_xyz + ip.Z = 0; +#endif + double b1, b2; + //nb: with very large coordinate values, it's possible for SlopesEqual() to + //return false but for the edge.Dx value be equal due to double precision rounding. + if (SlopesEqual(Edge1, Edge2, UseFullInt64Range) || Edge1.Dx == Edge2.Dx) + { + if (Edge2.Bot.Y > Edge1.Bot.Y) ip = Edge2.Bot; + else ip = Edge1.Bot; + return false; + } + else if (Edge1.Delta.X == 0) + { + ip.X = Edge1.Bot.X; + if (IsHorizontal(Edge2)) + ip.Y = Edge2.Bot.Y; + else + { + b2 = Edge2.Bot.Y - (Edge2.Bot.X / Edge2.Dx); + ip.Y = Round(ip.X / Edge2.Dx + b2); + } + } + else if (Edge2.Delta.X == 0) + { + ip.X = Edge2.Bot.X; + if (IsHorizontal(Edge1)) + ip.Y = Edge1.Bot.Y; + else + { + b1 = Edge1.Bot.Y - (Edge1.Bot.X / Edge1.Dx); + ip.Y = Round(ip.X / Edge1.Dx + b1); + } + } + else + { + b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx; + b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx; + double q = (b2-b1) / (Edge1.Dx - Edge2.Dx); + ip.Y = Round(q); + if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) + ip.X = Round(Edge1.Dx * q + b1); + else + ip.X = Round(Edge2.Dx * q + b2); + } + + if (ip.Y < Edge1.Top.Y || ip.Y < Edge2.Top.Y) + { + if (Edge1.Top.Y > Edge2.Top.Y) + ip.Y = Edge1.Top.Y; + else + ip.Y = Edge2.Top.Y; + if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) + ip.X = TopX(Edge1, ip.Y); + else + ip.X = TopX(Edge2, ip.Y); + } + return true; +} +//------------------------------------------------------------------------------ + +void ReversePolyPtLinks(OutPt *pp) +{ + if (!pp) return; + OutPt *pp1, *pp2; + pp1 = pp; + do { + pp2 = pp1->Next; + pp1->Next = pp1->Prev; + pp1->Prev = pp2; + pp1 = pp2; + } while( pp1 != pp ); +} +//------------------------------------------------------------------------------ + +void DisposeOutPts(OutPt*& pp) +{ + if (pp == 0) return; + pp->Prev->Next = 0; + while( pp ) + { + OutPt *tmpPp = pp; + pp = pp->Next; + delete tmpPp; + } +} +//------------------------------------------------------------------------------ + +inline void InitEdge(TEdge* e, TEdge* eNext, TEdge* ePrev, const IntPoint& Pt) +{ + std::memset(e, 0, sizeof(TEdge)); + e->Next = eNext; + e->Prev = ePrev; + e->Curr = Pt; + e->OutIdx = Unassigned; +} +//------------------------------------------------------------------------------ + +void InitEdge2(TEdge& e, PolyType Pt) +{ + if (e.Curr.Y >= e.Next->Curr.Y) + { + e.Bot = e.Curr; + e.Top = e.Next->Curr; + } else + { + e.Top = e.Curr; + e.Bot = e.Next->Curr; + } + SetDx(e); + e.PolyTyp = Pt; +} +//------------------------------------------------------------------------------ + +TEdge* RemoveEdge(TEdge* e) +{ + //removes e from double_linked_list (but without removing from memory) + e->Prev->Next = e->Next; + e->Next->Prev = e->Prev; + TEdge* result = e->Next; + e->Prev = 0; //flag as removed (see ClipperBase.Clear) + return result; +} +//------------------------------------------------------------------------------ + +inline void ReverseHorizontal(TEdge &e) +{ + //swap horizontal edges' Top and Bottom x's so they follow the natural + //progression of the bounds - ie so their xbots will align with the + //adjoining lower edge. [Helpful in the ProcessHorizontal() method.] + cInt tmp = e.Top.X; + e.Top.X = e.Bot.X; + e.Bot.X = tmp; +#ifdef use_xyz + tmp = e.Top.Z; + e.Top.Z = e.Bot.Z; + e.Bot.Z = tmp; +#endif +} +//------------------------------------------------------------------------------ + +void SwapPoints(IntPoint &pt1, IntPoint &pt2) +{ + IntPoint tmp = pt1; + pt1 = pt2; + pt2 = tmp; +} +//------------------------------------------------------------------------------ + +bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a, + IntPoint pt2b, IntPoint &pt1, IntPoint &pt2) +{ + //precondition: segments are Collinear. + if (Abs(pt1a.X - pt1b.X) > Abs(pt1a.Y - pt1b.Y)) + { + if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b); + if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b); + if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a; + if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b; + return pt1.X < pt2.X; + } else + { + if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b); + if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b); + if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a; + if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b; + return pt1.Y > pt2.Y; + } +} +//------------------------------------------------------------------------------ + +bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2) +{ + OutPt *p = btmPt1->Prev; + while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Prev; + double dx1p = std::fabs(GetDx(btmPt1->Pt, p->Pt)); + p = btmPt1->Next; + while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Next; + double dx1n = std::fabs(GetDx(btmPt1->Pt, p->Pt)); + + p = btmPt2->Prev; + while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Prev; + double dx2p = std::fabs(GetDx(btmPt2->Pt, p->Pt)); + p = btmPt2->Next; + while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next; + double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt)); + return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); +} +//------------------------------------------------------------------------------ + +OutPt* GetBottomPt(OutPt *pp) +{ + OutPt* dups = 0; + OutPt* p = pp->Next; + while (p != pp) + { + if (p->Pt.Y > pp->Pt.Y) + { + pp = p; + dups = 0; + } + else if (p->Pt.Y == pp->Pt.Y && p->Pt.X <= pp->Pt.X) + { + if (p->Pt.X < pp->Pt.X) + { + dups = 0; + pp = p; + } else + { + if (p->Next != pp && p->Prev != pp) dups = p; + } + } + p = p->Next; + } + if (dups) + { + //there appears to be at least 2 vertices at BottomPt so ... + while (dups != p) + { + if (!FirstIsBottomPt(p, dups)) pp = dups; + dups = dups->Next; + while (dups->Pt != pp->Pt) dups = dups->Next; + } + } + return pp; +} +//------------------------------------------------------------------------------ + +bool FindSegment(OutPt* &pp, bool UseFullInt64Range, + IntPoint &pt1, IntPoint &pt2) +{ + //OutPt1 & OutPt2 => the overlap segment (if the function returns true) + if (!pp) return false; + OutPt* pp2 = pp; + IntPoint pt1a = pt1, pt2a = pt2; + do + { + if (SlopesEqual(pt1a, pt2a, pp->Pt, pp->Prev->Pt, UseFullInt64Range) && + SlopesEqual(pt1a, pt2a, pp->Pt, UseFullInt64Range) && + GetOverlapSegment(pt1a, pt2a, pp->Pt, pp->Prev->Pt, pt1, pt2)) + return true; + pp = pp->Next; + } + while (pp != pp2); + return false; +} +//------------------------------------------------------------------------------ + +bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1, + const IntPoint pt2, const IntPoint pt3) +{ + if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) + return false; + else if (pt1.X != pt3.X) + return (pt2.X > pt1.X) == (pt2.X < pt3.X); + else + return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y); +} +//------------------------------------------------------------------------------ + +OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint Pt) +{ + if (p1 == p2) throw "JoinError"; + OutPt* result = new OutPt; + result->Pt = Pt; + if (p2 == p1->Next) + { + p1->Next = result; + p2->Prev = result; + result->Next = p2; + result->Prev = p1; + } else + { + p2->Next = result; + p1->Prev = result; + result->Next = p1; + result->Prev = p2; + } + return result; +} +//------------------------------------------------------------------------------ + +bool HorzSegmentsOverlap(const IntPoint& pt1a, const IntPoint& pt1b, + const IntPoint& pt2a, const IntPoint& pt2b) +{ + //precondition: both segments are horizontal + if ((pt1a.X > pt2a.X) == (pt1a.X < pt2b.X)) return true; + else if ((pt1b.X > pt2a.X) == (pt1b.X < pt2b.X)) return true; + else if ((pt2a.X > pt1a.X) == (pt2a.X < pt1b.X)) return true; + else if ((pt2b.X > pt1a.X) == (pt2b.X < pt1b.X)) return true; + else if ((pt1a.X == pt2a.X) && (pt1b.X == pt2b.X)) return true; + else if ((pt1a.X == pt2b.X) && (pt1b.X == pt2a.X)) return true; + else return false; +} + + +//------------------------------------------------------------------------------ +// ClipperBase class methods ... +//------------------------------------------------------------------------------ + +ClipperBase::ClipperBase() //constructor +{ + m_MinimaList = 0; + m_CurrentLM = 0; + m_UseFullRange = false; +} +//------------------------------------------------------------------------------ + +ClipperBase::~ClipperBase() //destructor +{ + Clear(); +} +//------------------------------------------------------------------------------ + +void RangeTest(const IntPoint& Pt, bool& useFullRange) +{ + if (useFullRange) + { + if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange) + throw "Coordinate outside allowed range"; + } + else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange) + { + useFullRange = true; + RangeTest(Pt, useFullRange); + } +} +//------------------------------------------------------------------------------ + +TEdge* FindNextLocMin(TEdge* E) +{ + for (;;) + { + while (E->Bot != E->Prev->Bot || E->Curr == E->Top) E = E->Next; + if (!IsHorizontal(*E) && !IsHorizontal(*E->Prev)) break; + while (IsHorizontal(*E->Prev)) E = E->Prev; + TEdge* E2 = E; + while (IsHorizontal(*E)) E = E->Next; + if (E->Top.Y == E->Prev->Bot.Y) continue; //ie just an intermediate horz. + if (E2->Prev->Bot.X < E->Bot.X) E = E2; + break; + } + return E; +} +//------------------------------------------------------------------------------ + +TEdge* ClipperBase::ProcessBound(TEdge* E, bool IsClockwise) +{ + TEdge *EStart = E, *Result = E; + TEdge *Horz = 0; + cInt StartX; + if (IsHorizontal(*E)) + { + //it's possible for adjacent overlapping horz edges to start heading left + //before finishing right, so ... + if (IsClockwise) StartX = E->Prev->Bot.X; + else StartX = E->Next->Bot.X; + if (E->Bot.X != StartX) ReverseHorizontal(*E); + } + + if (Result->OutIdx != Skip) + { + if (IsClockwise) + { + while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip) + Result = Result->Next; + if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip) + { + //nb: at the top of a bound, horizontals are added to the bound + //only when the preceding edge attaches to the horizontal's left vertex + //unless a Skip edge is encountered when that becomes the top divide + Horz = Result; + while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev; + if (Horz->Prev->Top.X == Result->Next->Top.X) + { + if (!IsClockwise) Result = Horz->Prev; + } + else if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev; + } + while (E != Result) + { + E->NextInLML = E->Next; + if (IsHorizontal(*E) && E != EStart && + E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); + E = E->Next; + } + if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X) + ReverseHorizontal(*E); + Result = Result->Next; //move to the edge just beyond current bound + } else + { + while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip) + Result = Result->Prev; + if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip) + { + Horz = Result; + while (IsHorizontal(*Horz->Next)) Horz = Horz->Next; + if (Horz->Next->Top.X == Result->Prev->Top.X) + { + if (!IsClockwise) Result = Horz->Next; + } + else if (Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next; + } + + while (E != Result) + { + E->NextInLML = E->Prev; + if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X) + ReverseHorizontal(*E); + E = E->Prev; + } + if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X) + ReverseHorizontal(*E); + Result = Result->Prev; //move to the edge just beyond current bound + } + } + + if (Result->OutIdx == Skip) + { + //if edges still remain in the current bound beyond the skip edge then + //create another LocMin and call ProcessBound once more + E = Result; + if (IsClockwise) + { + while (E->Top.Y == E->Next->Bot.Y) E = E->Next; + //don't include top horizontals when parsing a bound a second time, + //they will be contained in the opposite bound ... + while (E != Result && IsHorizontal(*E)) E = E->Prev; + } else + { + while (E->Top.Y == E->Prev->Bot.Y) E = E->Prev; + while (E != Result && IsHorizontal(*E)) E = E->Next; + } + if (E == Result) + { + if (IsClockwise) Result = E->Next; + else Result = E->Prev; + } else + { + //there are more edges in the bound beyond result starting with E + if (IsClockwise) + E = Result->Next; + else + E = Result->Prev; + LocalMinima* locMin = new LocalMinima; + locMin->Next = 0; + locMin->Y = E->Bot.Y; + locMin->LeftBound = 0; + locMin->RightBound = E; + locMin->RightBound->WindDelta = 0; + Result = ProcessBound(locMin->RightBound, IsClockwise); + InsertLocalMinima(locMin); + } + } + return Result; +} +//------------------------------------------------------------------------------ + +bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) +{ +#ifdef use_lines + if (!Closed && PolyTyp == ptClip) + throw clipperException("AddPath: Open paths must be subject."); +#else + if (!Closed) + throw clipperException("AddPath: Open paths have been disabled."); +#endif + + int highI = (int)pg.size() -1; + if (Closed) while (highI > 0 && (pg[highI] == pg[0])) --highI; + while (highI > 0 && (pg[highI] == pg[highI -1])) --highI; + if ((Closed && highI < 2) || (!Closed && highI < 1)) return false; + + //create a new edge array ... + TEdge *edges = new TEdge [highI +1]; + + bool IsFlat = true; + //1. Basic (first) edge initialization ... + try + { + edges[1].Curr = pg[1]; + RangeTest(pg[0], m_UseFullRange); + RangeTest(pg[highI], m_UseFullRange); + InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]); + InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]); + for (int i = highI - 1; i >= 1; --i) + { + RangeTest(pg[i], m_UseFullRange); + InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]); + } + } + catch(...) + { + delete [] edges; + throw; //range test fails + } + TEdge *eStart = &edges[0]; + + //2. Remove duplicate vertices, and (when closed) collinear edges ... + TEdge *E = eStart, *eLoopStop = eStart; + for (;;) + { + if ((E->Curr == E->Next->Curr)) + { + if (E == E->Next) break; + if (E == eStart) eStart = E->Next; + E = RemoveEdge(E); + eLoopStop = E; + continue; + } + if (E->Prev == E->Next) + break; //only two vertices + else if (Closed && + SlopesEqual(E->Prev->Curr, E->Curr, E->Next->Curr, m_UseFullRange) && + (!m_PreserveCollinear || + !Pt2IsBetweenPt1AndPt3(E->Prev->Curr, E->Curr, E->Next->Curr))) + { + //Collinear edges are allowed for open paths but in closed paths + //the default is to merge adjacent collinear edges into a single edge. + //However, if the PreserveCollinear property is enabled, only overlapping + //collinear edges (ie spikes) will be removed from closed paths. + if (E == eStart) eStart = E->Next; + E = RemoveEdge(E); + E = E->Prev; + eLoopStop = E; + continue; + } + E = E->Next; + if (E == eLoopStop) break; + } + + if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next))) + { + delete [] edges; + return false; + } + + if (!Closed) + { + m_HasOpenPaths = true; + eStart->Prev->OutIdx = Skip; + } + + //3. Do second stage of edge initialization ... + E = eStart; + do + { + InitEdge2(*E, PolyTyp); + E = E->Next; + if (IsFlat && E->Curr.Y != eStart->Curr.Y) IsFlat = false; + } + while (E != eStart); + + //4. Finally, add edge bounds to LocalMinima list ... + + //Totally flat paths must be handled differently when adding them + //to LocalMinima list to avoid endless loops etc ... + if (IsFlat) + { + if (Closed) + { + delete [] edges; + return false; + } + E->Prev->OutIdx = Skip; + if (E->Prev->Bot.X < E->Prev->Top.X) ReverseHorizontal(*E->Prev); + LocalMinima* locMin = new LocalMinima(); + locMin->Next = 0; + locMin->Y = E->Bot.Y; + locMin->LeftBound = 0; + locMin->RightBound = E; + locMin->RightBound->Side = esRight; + locMin->RightBound->WindDelta = 0; + while (E->Next->OutIdx != Skip) + { + E->NextInLML = E->Next; + if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); + E = E->Next; + } + InsertLocalMinima(locMin); + m_edges.push_back(edges); + return true; + } + + m_edges.push_back(edges); + bool clockwise; + TEdge* EMin = 0; + for (;;) + { + E = FindNextLocMin(E); + if (E == EMin) break; + else if (!EMin) EMin = E; + + //E and E.Prev now share a local minima (left aligned if horizontal). + //Compare their slopes to find which starts which bound ... + LocalMinima* locMin = new LocalMinima; + locMin->Next = 0; + locMin->Y = E->Bot.Y; + if (E->Dx < E->Prev->Dx) + { + locMin->LeftBound = E->Prev; + locMin->RightBound = E; + clockwise = false; //Q.nextInLML = Q.prev + } else + { + locMin->LeftBound = E; + locMin->RightBound = E->Prev; + clockwise = true; //Q.nextInLML = Q.next + } + locMin->LeftBound->Side = esLeft; + locMin->RightBound->Side = esRight; + + if (!Closed) locMin->LeftBound->WindDelta = 0; + else if (locMin->LeftBound->Next == locMin->RightBound) + locMin->LeftBound->WindDelta = -1; + else locMin->LeftBound->WindDelta = 1; + locMin->RightBound->WindDelta = -locMin->LeftBound->WindDelta; + + E = ProcessBound(locMin->LeftBound, clockwise); + TEdge* E2 = ProcessBound(locMin->RightBound, !clockwise); + + if (locMin->LeftBound->OutIdx == Skip) + locMin->LeftBound = 0; + else if (locMin->RightBound->OutIdx == Skip) + locMin->RightBound = 0; + InsertLocalMinima(locMin); + if (!clockwise) E = E2; + } + return true; +} +//------------------------------------------------------------------------------ + +bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed) +{ + bool result = false; + for (Paths::size_type i = 0; i < ppg.size(); ++i) + if (AddPath(ppg[i], PolyTyp, Closed)) result = true; + return result; +} +//------------------------------------------------------------------------------ + +void ClipperBase::InsertLocalMinima(LocalMinima *newLm) +{ + if( ! m_MinimaList ) + { + m_MinimaList = newLm; + } + else if( newLm->Y >= m_MinimaList->Y ) + { + newLm->Next = m_MinimaList; + m_MinimaList = newLm; + } else + { + LocalMinima* tmpLm = m_MinimaList; + while( tmpLm->Next && ( newLm->Y < tmpLm->Next->Y ) ) + tmpLm = tmpLm->Next; + newLm->Next = tmpLm->Next; + tmpLm->Next = newLm; + } +} +//------------------------------------------------------------------------------ + +void ClipperBase::Clear() +{ + DisposeLocalMinimaList(); + for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) + { + //for each edge array in turn, find the first used edge and + //check for and remove any hiddenPts in each edge in the array. + TEdge* edges = m_edges[i]; + delete [] edges; + } + m_edges.clear(); + m_UseFullRange = false; + m_HasOpenPaths = false; +} +//------------------------------------------------------------------------------ + +void ClipperBase::Reset() +{ + m_CurrentLM = m_MinimaList; + if( !m_CurrentLM ) return; //ie nothing to process + + //reset all edges ... + LocalMinima* lm = m_MinimaList; + while( lm ) + { + TEdge* e = lm->LeftBound; + if (e) + { + e->Curr = e->Bot; + e->Side = esLeft; + e->OutIdx = Unassigned; + } + + e = lm->RightBound; + if (e) + { + e->Curr = e->Bot; + e->Side = esRight; + e->OutIdx = Unassigned; + } + lm = lm->Next; + } +} +//------------------------------------------------------------------------------ + +void ClipperBase::DisposeLocalMinimaList() +{ + while( m_MinimaList ) + { + LocalMinima* tmpLm = m_MinimaList->Next; + delete m_MinimaList; + m_MinimaList = tmpLm; + } + m_CurrentLM = 0; +} +//------------------------------------------------------------------------------ + +void ClipperBase::PopLocalMinima() +{ + if( ! m_CurrentLM ) return; + m_CurrentLM = m_CurrentLM->Next; +} +//------------------------------------------------------------------------------ + +IntRect ClipperBase::GetBounds() +{ + IntRect result; + LocalMinima* lm = m_MinimaList; + if (!lm) + { + result.left = result.top = result.right = result.bottom = 0; + return result; + } + result.left = lm->LeftBound->Bot.X; + result.top = lm->LeftBound->Bot.Y; + result.right = lm->LeftBound->Bot.X; + result.bottom = lm->LeftBound->Bot.Y; + while (lm) + { + if (lm->LeftBound->Bot.Y > result.bottom) + result.bottom = lm->LeftBound->Bot.Y; + TEdge* e = lm->LeftBound; + for (;;) { + TEdge* bottomE = e; + while (e->NextInLML) + { + if (e->Bot.X < result.left) result.left = e->Bot.X; + if (e->Bot.X > result.right) result.right = e->Bot.X; + e = e->NextInLML; + } + if (e->Bot.X < result.left) result.left = e->Bot.X; + if (e->Bot.X > result.right) result.right = e->Bot.X; + if (e->Top.X < result.left) result.left = e->Top.X; + if (e->Top.X > result.right) result.right = e->Top.X; + if (e->Top.Y < result.top) result.top = e->Top.Y; + + if (bottomE == lm->LeftBound) e = lm->RightBound; + else break; + } + lm = lm->Next; + } + return result; +} + +//------------------------------------------------------------------------------ +// TClipper methods ... +//------------------------------------------------------------------------------ + +Clipper::Clipper(int initOptions) : ClipperBase() //constructor +{ + m_ActiveEdges = 0; + m_SortedEdges = 0; + m_ExecuteLocked = false; + m_UseFullRange = false; + m_ReverseOutput = ((initOptions & ioReverseSolution) != 0); + m_StrictSimple = ((initOptions & ioStrictlySimple) != 0); + m_PreserveCollinear = ((initOptions & ioPreserveCollinear) != 0); + m_HasOpenPaths = false; +#ifdef use_xyz + m_ZFill = 0; +#endif +} +//------------------------------------------------------------------------------ + +Clipper::~Clipper() //destructor +{ + Clear(); + m_Scanbeam.clear(); +} +//------------------------------------------------------------------------------ + +#ifdef use_xyz +void Clipper::ZFillFunction(TZFillCallback zFillFunc) +{ + m_ZFill = zFillFunc; +} +//------------------------------------------------------------------------------ +#endif + +void Clipper::Reset() +{ + ClipperBase::Reset(); + m_Scanbeam.clear(); + m_ActiveEdges = 0; + m_SortedEdges = 0; + LocalMinima* lm = m_MinimaList; + while (lm) + { + InsertScanbeam(lm->Y); + lm = lm->Next; + } +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, Paths &solution, + PolyFillType subjFillType, PolyFillType clipFillType) +{ + if( m_ExecuteLocked ) return false; + if (m_HasOpenPaths) + throw clipperException("Error: PolyTree struct is need for open path clipping."); + m_ExecuteLocked = true; + solution.resize(0); + m_SubjFillType = subjFillType; + m_ClipFillType = clipFillType; + m_ClipType = clipType; + m_UsingPolyTree = false; + bool succeeded = ExecuteInternal(); + if (succeeded) BuildResult(solution); + DisposeAllOutRecs(); + m_ExecuteLocked = false; + return succeeded; +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, PolyTree& polytree, + PolyFillType subjFillType, PolyFillType clipFillType) +{ + if( m_ExecuteLocked ) return false; + m_ExecuteLocked = true; + m_SubjFillType = subjFillType; + m_ClipFillType = clipFillType; + m_ClipType = clipType; + m_UsingPolyTree = true; + bool succeeded = ExecuteInternal(); + if (succeeded) BuildResult2(polytree); + DisposeAllOutRecs(); + m_ExecuteLocked = false; + return succeeded; +} +//------------------------------------------------------------------------------ + +void Clipper::FixHoleLinkage(OutRec &outrec) +{ + //skip OutRecs that (a) contain outermost polygons or + //(b) already have the correct owner/child linkage ... + if (!outrec.FirstLeft || + (outrec.IsHole != outrec.FirstLeft->IsHole && + outrec.FirstLeft->Pts)) return; + + OutRec* orfl = outrec.FirstLeft; + while (orfl && ((orfl->IsHole == outrec.IsHole) || !orfl->Pts)) + orfl = orfl->FirstLeft; + outrec.FirstLeft = orfl; +} +//------------------------------------------------------------------------------ + +bool Clipper::ExecuteInternal() +{ + bool succeeded = true; + try { + Reset(); + if (!m_CurrentLM) return false; + cInt botY = PopScanbeam(); + do { + InsertLocalMinimaIntoAEL(botY); + ClearGhostJoins(); + ProcessHorizontals(false); + if (m_Scanbeam.empty()) break; + cInt topY = PopScanbeam(); + succeeded = ProcessIntersections(botY, topY); + if (!succeeded) break; + ProcessEdgesAtTopOfScanbeam(topY); + botY = topY; + } while (!m_Scanbeam.empty() || m_CurrentLM); + } + catch(...) + { + succeeded = false; + } + + if (succeeded) + { + //fix orientations ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec *outRec = m_PolyOuts[i]; + if (!outRec->Pts || outRec->IsOpen) continue; + if ((outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0)) + ReversePolyPtLinks(outRec->Pts); + } + + if (!m_Joins.empty()) JoinCommonEdges(); + + //unfortunately FixupOutPolygon() must be done after JoinCommonEdges() + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec *outRec = m_PolyOuts[i]; + if (outRec->Pts && !outRec->IsOpen) + FixupOutPolygon(*outRec); + } + + if (m_StrictSimple) DoSimplePolygons(); + } + + ClearJoins(); + ClearGhostJoins(); + return succeeded; +} +//------------------------------------------------------------------------------ + +void Clipper::InsertScanbeam(const cInt Y) +{ + m_Scanbeam.insert(Y); +} +//------------------------------------------------------------------------------ + +cInt Clipper::PopScanbeam() +{ + cInt Y = *m_Scanbeam.begin(); + m_Scanbeam.erase(m_Scanbeam.begin()); + return Y; +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeAllOutRecs(){ + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + DisposeOutRec(i); + m_PolyOuts.clear(); +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeOutRec(PolyOutList::size_type index) +{ + OutRec *outRec = m_PolyOuts[index]; + if (outRec->Pts) DisposeOutPts(outRec->Pts); + delete outRec; + m_PolyOuts[index] = 0; +} +//------------------------------------------------------------------------------ + +void Clipper::SetWindingCount(TEdge &edge) +{ + TEdge *e = edge.PrevInAEL; + //find the edge of the same polytype that immediately preceeds 'edge' in AEL + while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL; + if (!e) + { + edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta); + edge.WindCnt2 = 0; + e = m_ActiveEdges; //ie get ready to calc WindCnt2 + } + else if (edge.WindDelta == 0 && m_ClipType != ctUnion) + { + edge.WindCnt = 1; + edge.WindCnt2 = e->WindCnt2; + e = e->NextInAEL; //ie get ready to calc WindCnt2 + } + else if (IsEvenOddFillType(edge)) + { + //EvenOdd filling ... + if (edge.WindDelta == 0) + { + //are we inside a subj polygon ... + bool Inside = true; + TEdge *e2 = e->PrevInAEL; + while (e2) + { + if (e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0) + Inside = !Inside; + e2 = e2->PrevInAEL; + } + edge.WindCnt = (Inside ? 0 : 1); + } + else + { + edge.WindCnt = edge.WindDelta; + } + edge.WindCnt2 = e->WindCnt2; + e = e->NextInAEL; //ie get ready to calc WindCnt2 + } + else + { + //nonZero, Positive or Negative filling ... + if (e->WindCnt * e->WindDelta < 0) + { + //prev edge is 'decreasing' WindCount (WC) toward zero + //so we're outside the previous polygon ... + if (Abs(e->WindCnt) > 1) + { + //outside prev poly but still inside another. + //when reversing direction of prev poly use the same WC + if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; + //otherwise continue to 'decrease' WC ... + else edge.WindCnt = e->WindCnt + edge.WindDelta; + } + else + //now outside all polys of same polytype so set own WC ... + edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta); + } else + { + //prev edge is 'increasing' WindCount (WC) away from zero + //so we're inside the previous polygon ... + if (edge.WindDelta == 0) + edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1); + //if wind direction is reversing prev then use same WC + else if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; + //otherwise add to WC ... + else edge.WindCnt = e->WindCnt + edge.WindDelta; + } + edge.WindCnt2 = e->WindCnt2; + e = e->NextInAEL; //ie get ready to calc WindCnt2 + } + + //update WindCnt2 ... + if (IsEvenOddAltFillType(edge)) + { + //EvenOdd filling ... + while (e != &edge) + { + if (e->WindDelta != 0) + edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0); + e = e->NextInAEL; + } + } else + { + //nonZero, Positive or Negative filling ... + while ( e != &edge ) + { + edge.WindCnt2 += e->WindDelta; + e = e->NextInAEL; + } + } +} +//------------------------------------------------------------------------------ + +bool Clipper::IsEvenOddFillType(const TEdge& edge) const +{ + if (edge.PolyTyp == ptSubject) + return m_SubjFillType == pftEvenOdd; else + return m_ClipFillType == pftEvenOdd; +} +//------------------------------------------------------------------------------ + +bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const +{ + if (edge.PolyTyp == ptSubject) + return m_ClipFillType == pftEvenOdd; else + return m_SubjFillType == pftEvenOdd; +} +//------------------------------------------------------------------------------ + +bool Clipper::IsContributing(const TEdge& edge) const +{ + PolyFillType pft, pft2; + if (edge.PolyTyp == ptSubject) + { + pft = m_SubjFillType; + pft2 = m_ClipFillType; + } else + { + pft = m_ClipFillType; + pft2 = m_SubjFillType; + } + + switch(pft) + { + case pftEvenOdd: + //return false if a subj line has been flagged as inside a subj polygon + if (edge.WindDelta == 0 && edge.WindCnt != 1) return false; + break; + case pftNonZero: + if (Abs(edge.WindCnt) != 1) return false; + break; + case pftPositive: + if (edge.WindCnt != 1) return false; + break; + default: //pftNegative + if (edge.WindCnt != -1) return false; + } + + switch(m_ClipType) + { + case ctIntersection: + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 != 0); + case pftPositive: + return (edge.WindCnt2 > 0); + default: + return (edge.WindCnt2 < 0); + } + break; + case ctUnion: + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 == 0); + case pftPositive: + return (edge.WindCnt2 <= 0); + default: + return (edge.WindCnt2 >= 0); + } + break; + case ctDifference: + if (edge.PolyTyp == ptSubject) + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 == 0); + case pftPositive: + return (edge.WindCnt2 <= 0); + default: + return (edge.WindCnt2 >= 0); + } + else + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 != 0); + case pftPositive: + return (edge.WindCnt2 > 0); + default: + return (edge.WindCnt2 < 0); + } + break; + case ctXor: + if (edge.WindDelta == 0) //XOr always contributing unless open + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 == 0); + case pftPositive: + return (edge.WindCnt2 <= 0); + default: + return (edge.WindCnt2 >= 0); + } + else + return true; + break; + default: + return true; + } +} +//------------------------------------------------------------------------------ + +OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) +{ + OutPt* result; + TEdge *e, *prevE; + if (IsHorizontal(*e2) || ( e1->Dx > e2->Dx )) + { + result = AddOutPt(e1, Pt); + e2->OutIdx = e1->OutIdx; + e1->Side = esLeft; + e2->Side = esRight; + e = e1; + if (e->PrevInAEL == e2) + prevE = e2->PrevInAEL; + else + prevE = e->PrevInAEL; + } else + { + result = AddOutPt(e2, Pt); + e1->OutIdx = e2->OutIdx; + e1->Side = esRight; + e2->Side = esLeft; + e = e2; + if (e->PrevInAEL == e1) + prevE = e1->PrevInAEL; + else + prevE = e->PrevInAEL; + } + + if (prevE && prevE->OutIdx >= 0 && + (TopX(*prevE, Pt.Y) == TopX(*e, Pt.Y)) && + SlopesEqual(*e, *prevE, m_UseFullRange) && + (e->WindDelta != 0) && (prevE->WindDelta != 0)) + { + OutPt* outPt = AddOutPt(prevE, Pt); + AddJoin(result, outPt, e->Top); + } + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) +{ + AddOutPt( e1, Pt ); + if (e2->WindDelta == 0) AddOutPt(e2, Pt); + if( e1->OutIdx == e2->OutIdx ) + { + e1->OutIdx = Unassigned; + e2->OutIdx = Unassigned; + } + else if (e1->OutIdx < e2->OutIdx) + AppendPolygon(e1, e2); + else + AppendPolygon(e2, e1); +} +//------------------------------------------------------------------------------ + +void Clipper::AddEdgeToSEL(TEdge *edge) +{ + //SEL pointers in PEdge are reused to build a list of horizontal edges. + //However, we don't need to worry about order with horizontal edge processing. + if( !m_SortedEdges ) + { + m_SortedEdges = edge; + edge->PrevInSEL = 0; + edge->NextInSEL = 0; + } + else + { + edge->NextInSEL = m_SortedEdges; + edge->PrevInSEL = 0; + m_SortedEdges->PrevInSEL = edge; + m_SortedEdges = edge; + } +} +//------------------------------------------------------------------------------ + +void Clipper::CopyAELToSEL() +{ + TEdge* e = m_ActiveEdges; + m_SortedEdges = e; + while ( e ) + { + e->PrevInSEL = e->PrevInAEL; + e->NextInSEL = e->NextInAEL; + e = e->NextInAEL; + } +} +//------------------------------------------------------------------------------ + +void Clipper::AddJoin(OutPt *op1, OutPt *op2, const IntPoint OffPt) +{ + Join* j = new Join; + j->OutPt1 = op1; + j->OutPt2 = op2; + j->OffPt = OffPt; + m_Joins.push_back(j); +} +//------------------------------------------------------------------------------ + +void Clipper::ClearJoins() +{ + for (JoinList::size_type i = 0; i < m_Joins.size(); i++) + delete m_Joins[i]; + m_Joins.resize(0); +} +//------------------------------------------------------------------------------ + +void Clipper::ClearGhostJoins() +{ + for (JoinList::size_type i = 0; i < m_GhostJoins.size(); i++) + delete m_GhostJoins[i]; + m_GhostJoins.resize(0); +} +//------------------------------------------------------------------------------ + +void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt) +{ + Join* j = new Join; + j->OutPt1 = op; + j->OutPt2 = 0; + j->OffPt = OffPt; + m_GhostJoins.push_back(j); +} +//------------------------------------------------------------------------------ + +void Clipper::InsertLocalMinimaIntoAEL(const cInt botY) +{ + while( m_CurrentLM && ( m_CurrentLM->Y == botY ) ) + { + TEdge* lb = m_CurrentLM->LeftBound; + TEdge* rb = m_CurrentLM->RightBound; + PopLocalMinima(); + OutPt *Op1 = 0; + if (!lb) + { + //nb: don't insert LB into either AEL or SEL + InsertEdgeIntoAEL(rb, 0); + SetWindingCount(*rb); + if (IsContributing(*rb)) + Op1 = AddOutPt(rb, rb->Bot); + } + else if (!rb) + { + InsertEdgeIntoAEL(lb, 0); + SetWindingCount(*lb); + if (IsContributing(*lb)) + Op1 = AddOutPt(lb, lb->Bot); + InsertScanbeam(lb->Top.Y); + } + else + { + InsertEdgeIntoAEL(lb, 0); + InsertEdgeIntoAEL(rb, lb); + SetWindingCount( *lb ); + rb->WindCnt = lb->WindCnt; + rb->WindCnt2 = lb->WindCnt2; + if (IsContributing(*lb)) + Op1 = AddLocalMinPoly(lb, rb, lb->Bot); + InsertScanbeam(lb->Top.Y); + } + + if (rb) + { + if(IsHorizontal(*rb)) AddEdgeToSEL(rb); + else InsertScanbeam( rb->Top.Y ); + } + + if (!lb || !rb) continue; + + //if any output polygons share an edge, they'll need joining later ... + if (Op1 && IsHorizontal(*rb) && + m_GhostJoins.size() > 0 && (rb->WindDelta != 0)) + { + for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i) + { + Join* jr = m_GhostJoins[i]; + //if the horizontal Rb and a 'ghost' horizontal overlap, then convert + //the 'ghost' join to a real join ready for later ... + if (HorzSegmentsOverlap(jr->OutPt1->Pt, jr->OffPt, rb->Bot, rb->Top)) + AddJoin(jr->OutPt1, Op1, jr->OffPt); + } + } + + if (lb->OutIdx >= 0 && lb->PrevInAEL && + lb->PrevInAEL->Curr.X == lb->Bot.X && + lb->PrevInAEL->OutIdx >= 0 && + SlopesEqual(*lb->PrevInAEL, *lb, m_UseFullRange) && + (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0)) + { + OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot); + AddJoin(Op1, Op2, lb->Top); + } + + if(lb->NextInAEL != rb) + { + + if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 && + SlopesEqual(*rb->PrevInAEL, *rb, m_UseFullRange) && + (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0)) + { + OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot); + AddJoin(Op1, Op2, rb->Top); + } + + TEdge* e = lb->NextInAEL; + if (e) + { + while( e != rb ) + { + //nb: For calculating winding counts etc, IntersectEdges() assumes + //that param1 will be to the Right of param2 ABOVE the intersection ... + IntersectEdges(rb , e , lb->Curr); //order important here + e = e->NextInAEL; + } + } + } + + } +} +//------------------------------------------------------------------------------ + +void Clipper::DeleteFromAEL(TEdge *e) +{ + TEdge* AelPrev = e->PrevInAEL; + TEdge* AelNext = e->NextInAEL; + if( !AelPrev && !AelNext && (e != m_ActiveEdges) ) return; //already deleted + if( AelPrev ) AelPrev->NextInAEL = AelNext; + else m_ActiveEdges = AelNext; + if( AelNext ) AelNext->PrevInAEL = AelPrev; + e->NextInAEL = 0; + e->PrevInAEL = 0; +} +//------------------------------------------------------------------------------ + +void Clipper::DeleteFromSEL(TEdge *e) +{ + TEdge* SelPrev = e->PrevInSEL; + TEdge* SelNext = e->NextInSEL; + if( !SelPrev && !SelNext && (e != m_SortedEdges) ) return; //already deleted + if( SelPrev ) SelPrev->NextInSEL = SelNext; + else m_SortedEdges = SelNext; + if( SelNext ) SelNext->PrevInSEL = SelPrev; + e->NextInSEL = 0; + e->PrevInSEL = 0; +} +//------------------------------------------------------------------------------ + +#ifdef use_xyz + +void Clipper::SetZ(IntPoint& pt, TEdge& e) +{ + pt.Z = 0; + if (m_ZFill) + { + //put the 'preferred' point as first parameter ... + if (e.OutIdx < 0) + (*m_ZFill)(e.Bot, e.Top, pt); //outside a path so presume entering + else + (*m_ZFill)(e.Top, e.Bot, pt); //inside a path so presume exiting + } +} +//------------------------------------------------------------------------------ +#endif + +void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, + const IntPoint &Pt, bool protect) +{ + //e1 will be to the Left of e2 BELOW the intersection. Therefore e1 is before + //e2 in AEL except when e1 is being inserted at the intersection point ... + bool e1stops = !protect && !e1->NextInLML && + e1->Top.X == Pt.X && e1->Top.Y == Pt.Y; + bool e2stops = !protect && !e2->NextInLML && + e2->Top.X == Pt.X && e2->Top.Y == Pt.Y; + bool e1Contributing = ( e1->OutIdx >= 0 ); + bool e2Contributing = ( e2->OutIdx >= 0 ); + +#ifdef use_lines + //if either edge is on an OPEN path ... + if (e1->WindDelta == 0 || e2->WindDelta == 0) + { + //ignore subject-subject open path intersections UNLESS they + //are both open paths, AND they are both 'contributing maximas' ... + if (e1->WindDelta == 0 && e2->WindDelta == 0) + { + if ((e1stops || e2stops) && e1Contributing && e2Contributing) + AddLocalMaxPoly(e1, e2, Pt); + } + + //if intersecting a subj line with a subj poly ... + else if (e1->PolyTyp == e2->PolyTyp && + e1->WindDelta != e2->WindDelta && m_ClipType == ctUnion) + { + if (e1->WindDelta == 0) + { + if (e2Contributing) + { + AddOutPt(e1, Pt); + if (e1Contributing) e1->OutIdx = Unassigned; + } + } + else + { + if (e1Contributing) + { + AddOutPt(e2, Pt); + if (e2Contributing) e2->OutIdx = Unassigned; + } + } + } + else if (e1->PolyTyp != e2->PolyTyp) + { + //toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ... + if ((e1->WindDelta == 0) && std::abs(e2->WindCnt) == 1 && + (m_ClipType != ctUnion || e2->WindCnt2 == 0)) + { + AddOutPt(e1, Pt); + if (e1Contributing) e1->OutIdx = Unassigned; + } + else if ((e2->WindDelta == 0) && (std::abs(e1->WindCnt) == 1) && + (m_ClipType != ctUnion || e1->WindCnt2 == 0)) + { + AddOutPt(e2, Pt); + if (e2Contributing) e2->OutIdx = Unassigned; + } + } + + if (e1stops) + if (e1->OutIdx < 0) DeleteFromAEL(e1); + else throw clipperException("Error intersecting polylines"); + if (e2stops) + if (e2->OutIdx < 0) DeleteFromAEL(e2); + else throw clipperException("Error intersecting polylines"); + return; + } +#endif + + //update winding counts... + //assumes that e1 will be to the Right of e2 ABOVE the intersection + if ( e1->PolyTyp == e2->PolyTyp ) + { + if ( IsEvenOddFillType( *e1) ) + { + int oldE1WindCnt = e1->WindCnt; + e1->WindCnt = e2->WindCnt; + e2->WindCnt = oldE1WindCnt; + } else + { + if (e1->WindCnt + e2->WindDelta == 0 ) e1->WindCnt = -e1->WindCnt; + else e1->WindCnt += e2->WindDelta; + if ( e2->WindCnt - e1->WindDelta == 0 ) e2->WindCnt = -e2->WindCnt; + else e2->WindCnt -= e1->WindDelta; + } + } else + { + if (!IsEvenOddFillType(*e2)) e1->WindCnt2 += e2->WindDelta; + else e1->WindCnt2 = ( e1->WindCnt2 == 0 ) ? 1 : 0; + if (!IsEvenOddFillType(*e1)) e2->WindCnt2 -= e1->WindDelta; + else e2->WindCnt2 = ( e2->WindCnt2 == 0 ) ? 1 : 0; + } + + PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; + if (e1->PolyTyp == ptSubject) + { + e1FillType = m_SubjFillType; + e1FillType2 = m_ClipFillType; + } else + { + e1FillType = m_ClipFillType; + e1FillType2 = m_SubjFillType; + } + if (e2->PolyTyp == ptSubject) + { + e2FillType = m_SubjFillType; + e2FillType2 = m_ClipFillType; + } else + { + e2FillType = m_ClipFillType; + e2FillType2 = m_SubjFillType; + } + + cInt e1Wc, e2Wc; + switch (e1FillType) + { + case pftPositive: e1Wc = e1->WindCnt; break; + case pftNegative: e1Wc = -e1->WindCnt; break; + default: e1Wc = Abs(e1->WindCnt); + } + switch(e2FillType) + { + case pftPositive: e2Wc = e2->WindCnt; break; + case pftNegative: e2Wc = -e2->WindCnt; break; + default: e2Wc = Abs(e2->WindCnt); + } + + if ( e1Contributing && e2Contributing ) + { + if ( e1stops || e2stops || + (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || + (e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) ) + AddLocalMaxPoly(e1, e2, Pt); + else + { + AddOutPt(e1, Pt); + AddOutPt(e2, Pt); + SwapSides( *e1 , *e2 ); + SwapPolyIndexes( *e1 , *e2 ); + } + } + else if ( e1Contributing ) + { + if (e2Wc == 0 || e2Wc == 1) + { + AddOutPt(e1, Pt); + SwapSides(*e1, *e2); + SwapPolyIndexes(*e1, *e2); + } + } + else if ( e2Contributing ) + { + if (e1Wc == 0 || e1Wc == 1) + { + AddOutPt(e2, Pt); + SwapSides(*e1, *e2); + SwapPolyIndexes(*e1, *e2); + } + } + else if ( (e1Wc == 0 || e1Wc == 1) && + (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops ) + { + //neither edge is currently contributing ... + + cInt e1Wc2, e2Wc2; + switch (e1FillType2) + { + case pftPositive: e1Wc2 = e1->WindCnt2; break; + case pftNegative : e1Wc2 = -e1->WindCnt2; break; + default: e1Wc2 = Abs(e1->WindCnt2); + } + switch (e2FillType2) + { + case pftPositive: e2Wc2 = e2->WindCnt2; break; + case pftNegative: e2Wc2 = -e2->WindCnt2; break; + default: e2Wc2 = Abs(e2->WindCnt2); + } + + if (e1->PolyTyp != e2->PolyTyp) + AddLocalMinPoly(e1, e2, Pt); + else if (e1Wc == 1 && e2Wc == 1) + switch( m_ClipType ) { + case ctIntersection: + if (e1Wc2 > 0 && e2Wc2 > 0) + AddLocalMinPoly(e1, e2, Pt); + break; + case ctUnion: + if ( e1Wc2 <= 0 && e2Wc2 <= 0 ) + AddLocalMinPoly(e1, e2, Pt); + break; + case ctDifference: + if (((e1->PolyTyp == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || + ((e1->PolyTyp == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) + AddLocalMinPoly(e1, e2, Pt); + break; + case ctXor: + AddLocalMinPoly(e1, e2, Pt); + } + else + SwapSides( *e1, *e2 ); + } + + if( (e1stops != e2stops) && + ( (e1stops && (e1->OutIdx >= 0)) || (e2stops && (e2->OutIdx >= 0)) ) ) + { + SwapSides( *e1, *e2 ); + SwapPolyIndexes( *e1, *e2 ); + } + + //finally, delete any non-contributing maxima edges ... + if( e1stops ) DeleteFromAEL( e1 ); + if( e2stops ) DeleteFromAEL( e2 ); +} +//------------------------------------------------------------------------------ + +void Clipper::SetHoleState(TEdge *e, OutRec *outrec) +{ + bool IsHole = false; + TEdge *e2 = e->PrevInAEL; + while (e2) + { + if (e2->OutIdx >= 0 && e2->WindDelta != 0) + { + IsHole = !IsHole; + if (! outrec->FirstLeft) + outrec->FirstLeft = m_PolyOuts[e2->OutIdx]; + } + e2 = e2->PrevInAEL; + } + if (IsHole) outrec->IsHole = true; +} +//------------------------------------------------------------------------------ + +OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2) +{ + //work out which polygon fragment has the correct hole state ... + if (!outRec1->BottomPt) + outRec1->BottomPt = GetBottomPt(outRec1->Pts); + if (!outRec2->BottomPt) + outRec2->BottomPt = GetBottomPt(outRec2->Pts); + OutPt *OutPt1 = outRec1->BottomPt; + OutPt *OutPt2 = outRec2->BottomPt; + if (OutPt1->Pt.Y > OutPt2->Pt.Y) return outRec1; + else if (OutPt1->Pt.Y < OutPt2->Pt.Y) return outRec2; + else if (OutPt1->Pt.X < OutPt2->Pt.X) return outRec1; + else if (OutPt1->Pt.X > OutPt2->Pt.X) return outRec2; + else if (OutPt1->Next == OutPt1) return outRec2; + else if (OutPt2->Next == OutPt2) return outRec1; + else if (FirstIsBottomPt(OutPt1, OutPt2)) return outRec1; + else return outRec2; +} +//------------------------------------------------------------------------------ + +bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2) +{ + do + { + outRec1 = outRec1->FirstLeft; + if (outRec1 == outRec2) return true; + } while (outRec1); + return false; +} +//------------------------------------------------------------------------------ + +OutRec* Clipper::GetOutRec(int Idx) +{ + OutRec* outrec = m_PolyOuts[Idx]; + while (outrec != m_PolyOuts[outrec->Idx]) + outrec = m_PolyOuts[outrec->Idx]; + return outrec; +} +//------------------------------------------------------------------------------ + +void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) +{ + //get the start and ends of both output polygons ... + OutRec *outRec1 = m_PolyOuts[e1->OutIdx]; + OutRec *outRec2 = m_PolyOuts[e2->OutIdx]; + + OutRec *holeStateRec; + if (Param1RightOfParam2(outRec1, outRec2)) + holeStateRec = outRec2; + else if (Param1RightOfParam2(outRec2, outRec1)) + holeStateRec = outRec1; + else + holeStateRec = GetLowermostRec(outRec1, outRec2); + + //get the start and ends of both output polygons and + //join e2 poly onto e1 poly and delete pointers to e2 ... + + OutPt* p1_lft = outRec1->Pts; + OutPt* p1_rt = p1_lft->Prev; + OutPt* p2_lft = outRec2->Pts; + OutPt* p2_rt = p2_lft->Prev; + + EdgeSide Side; + //join e2 poly onto e1 poly and delete pointers to e2 ... + if( e1->Side == esLeft ) + { + if( e2->Side == esLeft ) + { + //z y x a b c + ReversePolyPtLinks(p2_lft); + p2_lft->Next = p1_lft; + p1_lft->Prev = p2_lft; + p1_rt->Next = p2_rt; + p2_rt->Prev = p1_rt; + outRec1->Pts = p2_rt; + } else + { + //x y z a b c + p2_rt->Next = p1_lft; + p1_lft->Prev = p2_rt; + p2_lft->Prev = p1_rt; + p1_rt->Next = p2_lft; + outRec1->Pts = p2_lft; + } + Side = esLeft; + } else + { + if( e2->Side == esRight ) + { + //a b c z y x + ReversePolyPtLinks(p2_lft); + p1_rt->Next = p2_rt; + p2_rt->Prev = p1_rt; + p2_lft->Next = p1_lft; + p1_lft->Prev = p2_lft; + } else + { + //a b c x y z + p1_rt->Next = p2_lft; + p2_lft->Prev = p1_rt; + p1_lft->Prev = p2_rt; + p2_rt->Next = p1_lft; + } + Side = esRight; + } + + outRec1->BottomPt = 0; + if (holeStateRec == outRec2) + { + if (outRec2->FirstLeft != outRec1) + outRec1->FirstLeft = outRec2->FirstLeft; + outRec1->IsHole = outRec2->IsHole; + } + outRec2->Pts = 0; + outRec2->BottomPt = 0; + outRec2->FirstLeft = outRec1; + + int OKIdx = e1->OutIdx; + int ObsoleteIdx = e2->OutIdx; + + e1->OutIdx = Unassigned; //nb: safe because we only get here via AddLocalMaxPoly + e2->OutIdx = Unassigned; + + TEdge* e = m_ActiveEdges; + while( e ) + { + if( e->OutIdx == ObsoleteIdx ) + { + e->OutIdx = OKIdx; + e->Side = Side; + break; + } + e = e->NextInAEL; + } + + outRec2->Idx = outRec1->Idx; +} +//------------------------------------------------------------------------------ + +OutRec* Clipper::CreateOutRec() +{ + OutRec* result = new OutRec; + result->IsHole = false; + result->IsOpen = false; + result->FirstLeft = 0; + result->Pts = 0; + result->BottomPt = 0; + result->PolyNd = 0; + m_PolyOuts.push_back(result); + result->Idx = (int)m_PolyOuts.size()-1; + return result; +} +//------------------------------------------------------------------------------ + +OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt) +{ + bool ToFront = (e->Side == esLeft); + if( e->OutIdx < 0 ) + { + OutRec *outRec = CreateOutRec(); + outRec->IsOpen = (e->WindDelta == 0); + OutPt* newOp = new OutPt; + outRec->Pts = newOp; + newOp->Idx = outRec->Idx; + newOp->Pt = pt; + newOp->Next = newOp; + newOp->Prev = newOp; + if (!outRec->IsOpen) + SetHoleState(e, outRec); +#ifdef use_xyz + if (pt == e->Bot) newOp->Pt = e->Bot; + else if (pt == e->Top) newOp->Pt = e->Top; + else SetZ(newOp->Pt, *e); +#endif + e->OutIdx = outRec->Idx; //nb: do this after SetZ ! + return newOp; + } else + { + OutRec *outRec = m_PolyOuts[e->OutIdx]; + //OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most' + OutPt* op = outRec->Pts; + + if (ToFront && (pt == op->Pt)) return op; + else if (!ToFront && (pt == op->Prev->Pt)) return op->Prev; + + OutPt* newOp = new OutPt; + newOp->Idx = outRec->Idx; + newOp->Pt = pt; + newOp->Next = op; + newOp->Prev = op->Prev; + newOp->Prev->Next = newOp; + op->Prev = newOp; + if (ToFront) outRec->Pts = newOp; +#ifdef use_xyz + if (pt == e->Bot) newOp->Pt = e->Bot; + else if (pt == e->Top) newOp->Pt = e->Top; + else SetZ(newOp->Pt, *e); +#endif + return newOp; + } +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessHorizontals(bool IsTopOfScanbeam) +{ + TEdge* horzEdge = m_SortedEdges; + while(horzEdge) + { + DeleteFromSEL(horzEdge); + ProcessHorizontal(horzEdge, IsTopOfScanbeam); + horzEdge = m_SortedEdges; + } +} +//------------------------------------------------------------------------------ + +inline bool IsMinima(TEdge *e) +{ + return e && (e->Prev->NextInLML != e) && (e->Next->NextInLML != e); +} +//------------------------------------------------------------------------------ + +inline bool IsMaxima(TEdge *e, const cInt Y) +{ + return e && e->Top.Y == Y && !e->NextInLML; +} +//------------------------------------------------------------------------------ + +inline bool IsIntermediate(TEdge *e, const cInt Y) +{ + return e->Top.Y == Y && e->NextInLML; +} +//------------------------------------------------------------------------------ + +TEdge *GetMaximaPair(TEdge *e) +{ + TEdge* result = 0; + if ((e->Next->Top == e->Top) && !e->Next->NextInLML) + result = e->Next; + else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML) + result = e->Prev; + + if (result && (result->OutIdx == Skip || + //result is false if both NextInAEL & PrevInAEL are nil & not horizontal ... + (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result)))) + return 0; + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2) +{ + //check that one or other edge hasn't already been removed from AEL ... + if (Edge1->NextInAEL == Edge1->PrevInAEL || + Edge2->NextInAEL == Edge2->PrevInAEL) return; + + if( Edge1->NextInAEL == Edge2 ) + { + TEdge* Next = Edge2->NextInAEL; + if( Next ) Next->PrevInAEL = Edge1; + TEdge* Prev = Edge1->PrevInAEL; + if( Prev ) Prev->NextInAEL = Edge2; + Edge2->PrevInAEL = Prev; + Edge2->NextInAEL = Edge1; + Edge1->PrevInAEL = Edge2; + Edge1->NextInAEL = Next; + } + else if( Edge2->NextInAEL == Edge1 ) + { + TEdge* Next = Edge1->NextInAEL; + if( Next ) Next->PrevInAEL = Edge2; + TEdge* Prev = Edge2->PrevInAEL; + if( Prev ) Prev->NextInAEL = Edge1; + Edge1->PrevInAEL = Prev; + Edge1->NextInAEL = Edge2; + Edge2->PrevInAEL = Edge1; + Edge2->NextInAEL = Next; + } + else + { + TEdge* Next = Edge1->NextInAEL; + TEdge* Prev = Edge1->PrevInAEL; + Edge1->NextInAEL = Edge2->NextInAEL; + if( Edge1->NextInAEL ) Edge1->NextInAEL->PrevInAEL = Edge1; + Edge1->PrevInAEL = Edge2->PrevInAEL; + if( Edge1->PrevInAEL ) Edge1->PrevInAEL->NextInAEL = Edge1; + Edge2->NextInAEL = Next; + if( Edge2->NextInAEL ) Edge2->NextInAEL->PrevInAEL = Edge2; + Edge2->PrevInAEL = Prev; + if( Edge2->PrevInAEL ) Edge2->PrevInAEL->NextInAEL = Edge2; + } + + if( !Edge1->PrevInAEL ) m_ActiveEdges = Edge1; + else if( !Edge2->PrevInAEL ) m_ActiveEdges = Edge2; +} +//------------------------------------------------------------------------------ + +void Clipper::SwapPositionsInSEL(TEdge *Edge1, TEdge *Edge2) +{ + if( !( Edge1->NextInSEL ) && !( Edge1->PrevInSEL ) ) return; + if( !( Edge2->NextInSEL ) && !( Edge2->PrevInSEL ) ) return; + + if( Edge1->NextInSEL == Edge2 ) + { + TEdge* Next = Edge2->NextInSEL; + if( Next ) Next->PrevInSEL = Edge1; + TEdge* Prev = Edge1->PrevInSEL; + if( Prev ) Prev->NextInSEL = Edge2; + Edge2->PrevInSEL = Prev; + Edge2->NextInSEL = Edge1; + Edge1->PrevInSEL = Edge2; + Edge1->NextInSEL = Next; + } + else if( Edge2->NextInSEL == Edge1 ) + { + TEdge* Next = Edge1->NextInSEL; + if( Next ) Next->PrevInSEL = Edge2; + TEdge* Prev = Edge2->PrevInSEL; + if( Prev ) Prev->NextInSEL = Edge1; + Edge1->PrevInSEL = Prev; + Edge1->NextInSEL = Edge2; + Edge2->PrevInSEL = Edge1; + Edge2->NextInSEL = Next; + } + else + { + TEdge* Next = Edge1->NextInSEL; + TEdge* Prev = Edge1->PrevInSEL; + Edge1->NextInSEL = Edge2->NextInSEL; + if( Edge1->NextInSEL ) Edge1->NextInSEL->PrevInSEL = Edge1; + Edge1->PrevInSEL = Edge2->PrevInSEL; + if( Edge1->PrevInSEL ) Edge1->PrevInSEL->NextInSEL = Edge1; + Edge2->NextInSEL = Next; + if( Edge2->NextInSEL ) Edge2->NextInSEL->PrevInSEL = Edge2; + Edge2->PrevInSEL = Prev; + if( Edge2->PrevInSEL ) Edge2->PrevInSEL->NextInSEL = Edge2; + } + + if( !Edge1->PrevInSEL ) m_SortedEdges = Edge1; + else if( !Edge2->PrevInSEL ) m_SortedEdges = Edge2; +} +//------------------------------------------------------------------------------ + +TEdge* GetNextInAEL(TEdge *e, Direction dir) +{ + return dir == dLeftToRight ? e->NextInAEL : e->PrevInAEL; +} +//------------------------------------------------------------------------------ + +void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right) +{ + if (HorzEdge.Bot.X < HorzEdge.Top.X) + { + Left = HorzEdge.Bot.X; + Right = HorzEdge.Top.X; + Dir = dLeftToRight; + } else + { + Left = HorzEdge.Top.X; + Right = HorzEdge.Bot.X; + Dir = dRightToLeft; + } +} +//------------------------------------------------------------------------ + +void Clipper::PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam) +{ + //get the last Op for this horizontal edge + //the point may be anywhere along the horizontal ... + OutPt* outPt = m_PolyOuts[horzEdge->OutIdx]->Pts; + if (horzEdge->Side != esLeft) outPt = outPt->Prev; + + //First, match up overlapping horizontal edges (eg when one polygon's + //intermediate horz edge overlaps an intermediate horz edge of another, or + //when one polygon sits on top of another) ... + //for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i) + //{ + // Join* j = m_GhostJoins[i]; + // if (HorzSegmentsOverlap(j->OutPt1->Pt, j->OffPt, horzEdge->Bot, horzEdge->Top)) + // AddJoin(j->OutPt1, outPt, j->OffPt); + //} + + //Also, since horizontal edges at the top of one SB are often removed from + //the AEL before we process the horizontal edges at the bottom of the next, + //we need to create 'ghost' Join records of 'contrubuting' horizontals that + //we can compare with horizontals at the bottom of the next SB. + if (isTopOfScanbeam) + { + if (outPt->Pt == horzEdge->Top) + AddGhostJoin(outPt, horzEdge->Bot); + else + AddGhostJoin(outPt, horzEdge->Top); + } +} +//------------------------------------------------------------------------------ + +/******************************************************************************* +* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or * +* Bottom of a scanbeam) are processed as if layered. The order in which HEs * +* are processed doesn't matter. HEs intersect with other HE Bot.Xs only [#] * +* (or they could intersect with Top.Xs only, ie EITHER Bot.Xs OR Top.Xs), * +* and with other non-horizontal edges [*]. Once these intersections are * +* processed, intermediate HEs then 'promote' the Edge above (NextInLML) into * +* the AEL. These 'promoted' edges may in turn intersect [%] with other HEs. * +*******************************************************************************/ + +void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam) +{ + Direction dir; + cInt horzLeft, horzRight; + + GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); + + TEdge* eLastHorz = horzEdge, *eMaxPair = 0; + while (eLastHorz->NextInLML && IsHorizontal(*eLastHorz->NextInLML)) + eLastHorz = eLastHorz->NextInLML; + if (!eLastHorz->NextInLML) + eMaxPair = GetMaximaPair(eLastHorz); + + for (;;) + { + bool IsLastHorz = (horzEdge == eLastHorz); + TEdge* e = GetNextInAEL(horzEdge, dir); + while(e) + { + //Break if we've got to the end of an intermediate horizontal edge ... + //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal. + if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML && + e->Dx < horzEdge->NextInLML->Dx) break; + + TEdge* eNext = GetNextInAEL(e, dir); //saves eNext for later + + if ((dir == dLeftToRight && e->Curr.X <= horzRight) || + (dir == dRightToLeft && e->Curr.X >= horzLeft)) + { + if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0) + PrepareHorzJoins(horzEdge, isTopOfScanbeam); + //so far we're still in range of the horizontal Edge but make sure + //we're at the last of consec. horizontals when matching with eMaxPair + if(e == eMaxPair && IsLastHorz) + { + if (dir == dLeftToRight) + IntersectEdges(horzEdge, e, e->Top); + else + IntersectEdges(e, horzEdge, e->Top); + if (eMaxPair->OutIdx >= 0) throw clipperException("ProcessHorizontal error"); + return; + } + else if(dir == dLeftToRight) + { + IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y); + IntersectEdges(horzEdge, e, Pt, true); + } + else + { + IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y); + IntersectEdges( e, horzEdge, Pt, true); + } + SwapPositionsInAEL( horzEdge, e ); + } + else if( (dir == dLeftToRight && e->Curr.X >= horzRight) || + (dir == dRightToLeft && e->Curr.X <= horzLeft) ) break; + e = eNext; + } //end while + + if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0) + PrepareHorzJoins(horzEdge, isTopOfScanbeam); + + if (horzEdge->NextInLML && IsHorizontal(*horzEdge->NextInLML)) + { + UpdateEdgeIntoAEL(horzEdge); + if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot); + GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); + } else + break; + } //end for (;;) + + if(horzEdge->NextInLML) + { + if(horzEdge->OutIdx >= 0) + { + OutPt* op1 = AddOutPt( horzEdge, horzEdge->Top); + UpdateEdgeIntoAEL(horzEdge); + if (horzEdge->WindDelta == 0) return; + //nb: HorzEdge is no longer horizontal here + TEdge* ePrev = horzEdge->PrevInAEL; + TEdge* eNext = horzEdge->NextInAEL; + if (ePrev && ePrev->Curr.X == horzEdge->Bot.X && + ePrev->Curr.Y == horzEdge->Bot.Y && ePrev->WindDelta != 0 && + (ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y && + SlopesEqual(*horzEdge, *ePrev, m_UseFullRange))) + { + OutPt* op2 = AddOutPt(ePrev, horzEdge->Bot); + AddJoin(op1, op2, horzEdge->Top); + } + else if (eNext && eNext->Curr.X == horzEdge->Bot.X && + eNext->Curr.Y == horzEdge->Bot.Y && eNext->WindDelta != 0 && + eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y && + SlopesEqual(*horzEdge, *eNext, m_UseFullRange)) + { + OutPt* op2 = AddOutPt(eNext, horzEdge->Bot); + AddJoin(op1, op2, horzEdge->Top); + } + } + else + UpdateEdgeIntoAEL(horzEdge); + } + else if (eMaxPair) + { + if (eMaxPair->OutIdx >= 0) + { + if (dir == dLeftToRight) + IntersectEdges(horzEdge, eMaxPair, horzEdge->Top); + else + IntersectEdges(eMaxPair, horzEdge, horzEdge->Top); + if (eMaxPair->OutIdx >= 0) + throw clipperException("ProcessHorizontal error"); + } else + { + DeleteFromAEL(horzEdge); + DeleteFromAEL(eMaxPair); + } + } else + { + if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top); + DeleteFromAEL(horzEdge); + } +} +//------------------------------------------------------------------------------ + +void Clipper::UpdateEdgeIntoAEL(TEdge *&e) +{ + if( !e->NextInLML ) throw + clipperException("UpdateEdgeIntoAEL: invalid call"); + + e->NextInLML->OutIdx = e->OutIdx; + TEdge* AelPrev = e->PrevInAEL; + TEdge* AelNext = e->NextInAEL; + if (AelPrev) AelPrev->NextInAEL = e->NextInLML; + else m_ActiveEdges = e->NextInLML; + if (AelNext) AelNext->PrevInAEL = e->NextInLML; + e->NextInLML->Side = e->Side; + e->NextInLML->WindDelta = e->WindDelta; + e->NextInLML->WindCnt = e->WindCnt; + e->NextInLML->WindCnt2 = e->WindCnt2; + e = e->NextInLML; + e->Curr = e->Bot; + e->PrevInAEL = AelPrev; + e->NextInAEL = AelNext; + if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y); +} +//------------------------------------------------------------------------------ + +bool Clipper::ProcessIntersections(const cInt botY, const cInt topY) +{ + if( !m_ActiveEdges ) return true; + try { + BuildIntersectList(botY, topY); + size_t IlSize = m_IntersectList.size(); + if (IlSize == 0) return true; + if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList(); + else return false; + } + catch(...) + { + m_SortedEdges = 0; + DisposeIntersectNodes(); + throw clipperException("ProcessIntersections error"); + } + m_SortedEdges = 0; + return true; +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeIntersectNodes() +{ + for (size_t i = 0; i < m_IntersectList.size(); ++i ) + delete m_IntersectList[i]; + m_IntersectList.clear(); +} +//------------------------------------------------------------------------------ + +void Clipper::BuildIntersectList(const cInt botY, const cInt topY) +{ + if ( !m_ActiveEdges ) return; + + //prepare for sorting ... + TEdge* e = m_ActiveEdges; + m_SortedEdges = e; + while( e ) + { + e->PrevInSEL = e->PrevInAEL; + e->NextInSEL = e->NextInAEL; + e->Curr.X = TopX( *e, topY ); + e = e->NextInAEL; + } + + //bubblesort ... + bool isModified; + do + { + isModified = false; + e = m_SortedEdges; + while( e->NextInSEL ) + { + TEdge *eNext = e->NextInSEL; + IntPoint Pt; + if(e->Curr.X > eNext->Curr.X) + { + if (!IntersectPoint(*e, *eNext, Pt, m_UseFullRange) && e->Curr.X > eNext->Curr.X +1) + throw clipperException("Intersection error"); + if (Pt.Y > botY) + { + Pt.Y = botY; + if (std::fabs(e->Dx) > std::fabs(eNext->Dx)) + Pt.X = TopX(*eNext, botY); else + Pt.X = TopX(*e, botY); + } + + IntersectNode * newNode = new IntersectNode; + newNode->Edge1 = e; + newNode->Edge2 = eNext; + newNode->Pt = Pt; + m_IntersectList.push_back(newNode); + + SwapPositionsInSEL(e, eNext); + isModified = true; + } + else + e = eNext; + } + if( e->PrevInSEL ) e->PrevInSEL->NextInSEL = 0; + else break; + } + while ( isModified ); + m_SortedEdges = 0; //important +} +//------------------------------------------------------------------------------ + + +void Clipper::ProcessIntersectList() +{ + for (size_t i = 0; i < m_IntersectList.size(); ++i) + { + IntersectNode* iNode = m_IntersectList[i]; + { + IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt, true); + SwapPositionsInAEL( iNode->Edge1 , iNode->Edge2 ); + } + delete iNode; + } + m_IntersectList.clear(); +} +//------------------------------------------------------------------------------ + +bool IntersectListSort(IntersectNode* node1, IntersectNode* node2) +{ + return node2->Pt.Y < node1->Pt.Y; +} +//------------------------------------------------------------------------------ + +inline bool EdgesAdjacent(const IntersectNode &inode) +{ + return (inode.Edge1->NextInSEL == inode.Edge2) || + (inode.Edge1->PrevInSEL == inode.Edge2); +} +//------------------------------------------------------------------------------ + +bool Clipper::FixupIntersectionOrder() +{ + //pre-condition: intersections are sorted Bottom-most first. + //Now it's crucial that intersections are made only between adjacent edges, + //so to ensure this the order of intersections may need adjusting ... + CopyAELToSEL(); + std::sort(m_IntersectList.begin(), m_IntersectList.end(), IntersectListSort); + size_t cnt = m_IntersectList.size(); + for (size_t i = 0; i < cnt; ++i) + { + if (!EdgesAdjacent(*m_IntersectList[i])) + { + size_t j = i + 1; + while (j < cnt && !EdgesAdjacent(*m_IntersectList[j])) j++; + if (j == cnt) return false; + std::swap(m_IntersectList[i], m_IntersectList[j]); + } + SwapPositionsInSEL(m_IntersectList[i]->Edge1, m_IntersectList[i]->Edge2); + } + return true; +} +//------------------------------------------------------------------------------ + +void Clipper::DoMaxima(TEdge *e) +{ + TEdge* eMaxPair = GetMaximaPair(e); + if (!eMaxPair) + { + if (e->OutIdx >= 0) + AddOutPt(e, e->Top); + DeleteFromAEL(e); + return; + } + + TEdge* eNext = e->NextInAEL; + while(eNext && eNext != eMaxPair) + { + IntersectEdges(e, eNext, e->Top, true); + SwapPositionsInAEL(e, eNext); + eNext = e->NextInAEL; + } + + if(e->OutIdx == Unassigned && eMaxPair->OutIdx == Unassigned) + { + DeleteFromAEL(e); + DeleteFromAEL(eMaxPair); + } + else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 ) + { + IntersectEdges( e, eMaxPair, e->Top); + } +#ifdef use_lines + else if (e->WindDelta == 0) + { + if (e->OutIdx >= 0) + { + AddOutPt(e, e->Top); + e->OutIdx = Unassigned; + } + DeleteFromAEL(e); + + if (eMaxPair->OutIdx >= 0) + { + AddOutPt(eMaxPair, e->Top); + eMaxPair->OutIdx = Unassigned; + } + DeleteFromAEL(eMaxPair); + } +#endif + else throw clipperException("DoMaxima error"); +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY) +{ + TEdge* e = m_ActiveEdges; + while( e ) + { + //1. process maxima, treating them as if they're 'bent' horizontal edges, + // but exclude maxima with horizontal edges. nb: e can't be a horizontal. + bool IsMaximaEdge = IsMaxima(e, topY); + + if(IsMaximaEdge) + { + TEdge* eMaxPair = GetMaximaPair(e); + IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair)); + } + + if(IsMaximaEdge) + { + TEdge* ePrev = e->PrevInAEL; + DoMaxima(e); + if( !ePrev ) e = m_ActiveEdges; + else e = ePrev->NextInAEL; + } + else + { + //2. promote horizontal edges, otherwise update Curr.X and Curr.Y ... + if (IsIntermediate(e, topY) && IsHorizontal(*e->NextInLML)) + { + UpdateEdgeIntoAEL(e); + if (e->OutIdx >= 0) + AddOutPt(e, e->Bot); + AddEdgeToSEL(e); + } + else + { + e->Curr.X = TopX( *e, topY ); + e->Curr.Y = topY; + } + + if (m_StrictSimple) + { + TEdge* ePrev = e->PrevInAEL; + if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) && + (ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0)) + { + OutPt* op = AddOutPt(ePrev, e->Curr); + OutPt* op2 = AddOutPt(e, e->Curr); + AddJoin(op, op2, e->Curr); //StrictlySimple (type-3) join + } + } + + e = e->NextInAEL; + } + } + + //3. Process horizontals at the Top of the scanbeam ... + ProcessHorizontals(true); + + //4. Promote intermediate vertices ... + e = m_ActiveEdges; + while(e) + { + if(IsIntermediate(e, topY)) + { + OutPt* op = 0; + if( e->OutIdx >= 0 ) + op = AddOutPt(e, e->Top); + UpdateEdgeIntoAEL(e); + + //if output polygons share an edge, they'll need joining later ... + TEdge* ePrev = e->PrevInAEL; + TEdge* eNext = e->NextInAEL; + if (ePrev && ePrev->Curr.X == e->Bot.X && + ePrev->Curr.Y == e->Bot.Y && op && + ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y && + SlopesEqual(*e, *ePrev, m_UseFullRange) && + (e->WindDelta != 0) && (ePrev->WindDelta != 0)) + { + OutPt* op2 = AddOutPt(ePrev, e->Bot); + AddJoin(op, op2, e->Top); + } + else if (eNext && eNext->Curr.X == e->Bot.X && + eNext->Curr.Y == e->Bot.Y && op && + eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y && + SlopesEqual(*e, *eNext, m_UseFullRange) && + (e->WindDelta != 0) && (eNext->WindDelta != 0)) + { + OutPt* op2 = AddOutPt(eNext, e->Bot); + AddJoin(op, op2, e->Top); + } + } + e = e->NextInAEL; + } +} +//------------------------------------------------------------------------------ + +void Clipper::FixupOutPolygon(OutRec &outrec) +{ + //FixupOutPolygon() - removes duplicate points and simplifies consecutive + //parallel edges by removing the middle vertex. + OutPt *lastOK = 0; + outrec.BottomPt = 0; + OutPt *pp = outrec.Pts; + + for (;;) + { + if (pp->Prev == pp || pp->Prev == pp->Next ) + { + DisposeOutPts(pp); + outrec.Pts = 0; + return; + } + + //test for duplicate points and collinear edges ... + if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) || + (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) && + (!m_PreserveCollinear || + !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt)))) + { + lastOK = 0; + OutPt *tmp = pp; + pp->Prev->Next = pp->Next; + pp->Next->Prev = pp->Prev; + pp = pp->Prev; + delete tmp; + } + else if (pp == lastOK) break; + else + { + if (!lastOK) lastOK = pp; + pp = pp->Next; + } + } + outrec.Pts = pp; +} +//------------------------------------------------------------------------------ + +int PointCount(OutPt *Pts) +{ + if (!Pts) return 0; + int result = 0; + OutPt* p = Pts; + do + { + result++; + p = p->Next; + } + while (p != Pts); + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::BuildResult(Paths &polys) +{ + polys.reserve(m_PolyOuts.size()); + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + if (!m_PolyOuts[i]->Pts) continue; + Path pg; + OutPt* p = m_PolyOuts[i]->Pts->Prev; + int cnt = PointCount(p); + if (cnt < 2) continue; + pg.reserve(cnt); + for (int j = 0; j < cnt; ++j) + { + pg.push_back(p->Pt); + p = p->Prev; + } + polys.push_back(pg); + } +} +//------------------------------------------------------------------------------ + +void Clipper::BuildResult2(PolyTree& polytree) +{ + polytree.Clear(); + polytree.AllNodes.reserve(m_PolyOuts.size()); + //add each output polygon/contour to polytree ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) + { + OutRec* outRec = m_PolyOuts[i]; + int cnt = PointCount(outRec->Pts); + if ((outRec->IsOpen && cnt < 2) || (!outRec->IsOpen && cnt < 3)) continue; + FixHoleLinkage(*outRec); + PolyNode* pn = new PolyNode(); + //nb: polytree takes ownership of all the PolyNodes + polytree.AllNodes.push_back(pn); + outRec->PolyNd = pn; + pn->Parent = 0; + pn->Index = 0; + pn->Contour.reserve(cnt); + OutPt *op = outRec->Pts->Prev; + for (int j = 0; j < cnt; j++) + { + pn->Contour.push_back(op->Pt); + op = op->Prev; + } + } + + //fixup PolyNode links etc ... + polytree.Childs.reserve(m_PolyOuts.size()); + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) + { + OutRec* outRec = m_PolyOuts[i]; + if (!outRec->PolyNd) continue; + if (outRec->IsOpen) + { + outRec->PolyNd->m_IsOpen = true; + polytree.AddChild(*outRec->PolyNd); + } + else if (outRec->FirstLeft && outRec->FirstLeft->PolyNd) + outRec->FirstLeft->PolyNd->AddChild(*outRec->PolyNd); + else + polytree.AddChild(*outRec->PolyNd); + } +} +//------------------------------------------------------------------------------ + +void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2) +{ + //just swap the contents (because fIntersectNodes is a single-linked-list) + IntersectNode inode = int1; //gets a copy of Int1 + int1.Edge1 = int2.Edge1; + int1.Edge2 = int2.Edge2; + int1.Pt = int2.Pt; + int2.Edge1 = inode.Edge1; + int2.Edge2 = inode.Edge2; + int2.Pt = inode.Pt; +} +//------------------------------------------------------------------------------ + +inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2) +{ + if (e2.Curr.X == e1.Curr.X) + { + if (e2.Top.Y > e1.Top.Y) + return e2.Top.X < TopX(e1, e2.Top.Y); + else return e1.Top.X > TopX(e2, e1.Top.Y); + } + else return e2.Curr.X < e1.Curr.X; +} +//------------------------------------------------------------------------------ + +bool GetOverlap(const cInt a1, const cInt a2, const cInt b1, const cInt b2, + cInt& Left, cInt& Right) +{ + if (a1 < a2) + { + if (b1 < b2) {Left = std::max(a1,b1); Right = std::min(a2,b2);} + else {Left = std::max(a1,b2); Right = std::min(a2,b1);} + } + else + { + if (b1 < b2) {Left = std::max(a2,b1); Right = std::min(a1,b2);} + else {Left = std::max(a2,b2); Right = std::min(a1,b1);} + } + return Left < Right; +} +//------------------------------------------------------------------------------ + +inline void UpdateOutPtIdxs(OutRec& outrec) +{ + OutPt* op = outrec.Pts; + do + { + op->Idx = outrec.Idx; + op = op->Prev; + } + while(op != outrec.Pts); +} +//------------------------------------------------------------------------------ + +void Clipper::InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge) +{ + if(!m_ActiveEdges) + { + edge->PrevInAEL = 0; + edge->NextInAEL = 0; + m_ActiveEdges = edge; + } + else if(!startEdge && E2InsertsBeforeE1(*m_ActiveEdges, *edge)) + { + edge->PrevInAEL = 0; + edge->NextInAEL = m_ActiveEdges; + m_ActiveEdges->PrevInAEL = edge; + m_ActiveEdges = edge; + } + else + { + if(!startEdge) startEdge = m_ActiveEdges; + while(startEdge->NextInAEL && + !E2InsertsBeforeE1(*startEdge->NextInAEL , *edge)) + startEdge = startEdge->NextInAEL; + edge->NextInAEL = startEdge->NextInAEL; + if(startEdge->NextInAEL) startEdge->NextInAEL->PrevInAEL = edge; + edge->PrevInAEL = startEdge; + startEdge->NextInAEL = edge; + } +} +//---------------------------------------------------------------------- + +OutPt* DupOutPt(OutPt* outPt, bool InsertAfter) +{ + OutPt* result = new OutPt; + result->Pt = outPt->Pt; + result->Idx = outPt->Idx; + if (InsertAfter) + { + result->Next = outPt->Next; + result->Prev = outPt; + outPt->Next->Prev = result; + outPt->Next = result; + } + else + { + result->Prev = outPt->Prev; + result->Next = outPt; + outPt->Prev->Next = result; + outPt->Prev = result; + } + return result; +} +//------------------------------------------------------------------------------ + +bool JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b, + const IntPoint Pt, bool DiscardLeft) +{ + Direction Dir1 = (op1->Pt.X > op1b->Pt.X ? dRightToLeft : dLeftToRight); + Direction Dir2 = (op2->Pt.X > op2b->Pt.X ? dRightToLeft : dLeftToRight); + if (Dir1 == Dir2) return false; + + //When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we + //want Op1b to be on the Right. (And likewise with Op2 and Op2b.) + //So, to facilitate this while inserting Op1b and Op2b ... + //when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b, + //otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.) + if (Dir1 == dLeftToRight) + { + while (op1->Next->Pt.X <= Pt.X && + op1->Next->Pt.X >= op1->Pt.X && op1->Next->Pt.Y == Pt.Y) + op1 = op1->Next; + if (DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next; + op1b = DupOutPt(op1, !DiscardLeft); + if (op1b->Pt != Pt) + { + op1 = op1b; + op1->Pt = Pt; + op1b = DupOutPt(op1, !DiscardLeft); + } + } + else + { + while (op1->Next->Pt.X >= Pt.X && + op1->Next->Pt.X <= op1->Pt.X && op1->Next->Pt.Y == Pt.Y) + op1 = op1->Next; + if (!DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next; + op1b = DupOutPt(op1, DiscardLeft); + if (op1b->Pt != Pt) + { + op1 = op1b; + op1->Pt = Pt; + op1b = DupOutPt(op1, DiscardLeft); + } + } + + if (Dir2 == dLeftToRight) + { + while (op2->Next->Pt.X <= Pt.X && + op2->Next->Pt.X >= op2->Pt.X && op2->Next->Pt.Y == Pt.Y) + op2 = op2->Next; + if (DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next; + op2b = DupOutPt(op2, !DiscardLeft); + if (op2b->Pt != Pt) + { + op2 = op2b; + op2->Pt = Pt; + op2b = DupOutPt(op2, !DiscardLeft); + }; + } else + { + while (op2->Next->Pt.X >= Pt.X && + op2->Next->Pt.X <= op2->Pt.X && op2->Next->Pt.Y == Pt.Y) + op2 = op2->Next; + if (!DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next; + op2b = DupOutPt(op2, DiscardLeft); + if (op2b->Pt != Pt) + { + op2 = op2b; + op2->Pt = Pt; + op2b = DupOutPt(op2, DiscardLeft); + }; + }; + + if ((Dir1 == dLeftToRight) == DiscardLeft) + { + op1->Prev = op2; + op2->Next = op1; + op1b->Next = op2b; + op2b->Prev = op1b; + } + else + { + op1->Next = op2; + op2->Prev = op1; + op1b->Prev = op2b; + op2b->Next = op1b; + } + return true; +} +//------------------------------------------------------------------------------ + +bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2) +{ + OutPt *op1 = j->OutPt1, *op1b; + OutPt *op2 = j->OutPt2, *op2b; + + //There are 3 kinds of joins for output polygons ... + //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are a vertices anywhere + //along (horizontal) collinear edges (& Join.OffPt is on the same horizontal). + //2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same + //location at the Bottom of the overlapping segment (& Join.OffPt is above). + //3. StrictSimple joins where edges touch but are not collinear and where + //Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point. + bool isHorizontal = (j->OutPt1->Pt.Y == j->OffPt.Y); + + if (isHorizontal && (j->OffPt == j->OutPt1->Pt) && + (j->OffPt == j->OutPt2->Pt)) + { + //Strictly Simple join ... + op1b = j->OutPt1->Next; + while (op1b != op1 && (op1b->Pt == j->OffPt)) + op1b = op1b->Next; + bool reverse1 = (op1b->Pt.Y > j->OffPt.Y); + op2b = j->OutPt2->Next; + while (op2b != op2 && (op2b->Pt == j->OffPt)) + op2b = op2b->Next; + bool reverse2 = (op2b->Pt.Y > j->OffPt.Y); + if (reverse1 == reverse2) return false; + if (reverse1) + { + op1b = DupOutPt(op1, false); + op2b = DupOutPt(op2, true); + op1->Prev = op2; + op2->Next = op1; + op1b->Next = op2b; + op2b->Prev = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } else + { + op1b = DupOutPt(op1, true); + op2b = DupOutPt(op2, false); + op1->Next = op2; + op2->Prev = op1; + op1b->Prev = op2b; + op2b->Next = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } + } + else if (isHorizontal) + { + //treat horizontal joins differently to non-horizontal joins since with + //them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt + //may be anywhere along the horizontal edge. + op1b = op1; + while (op1->Prev->Pt.Y == op1->Pt.Y && op1->Prev != op1b && op1->Prev != op2) + op1 = op1->Prev; + while (op1b->Next->Pt.Y == op1b->Pt.Y && op1b->Next != op1 && op1b->Next != op2) + op1b = op1b->Next; + if (op1b->Next == op1 || op1b->Next == op2) return false; //a flat 'polygon' + + op2b = op2; + while (op2->Prev->Pt.Y == op2->Pt.Y && op2->Prev != op2b && op2->Prev != op1b) + op2 = op2->Prev; + while (op2b->Next->Pt.Y == op2b->Pt.Y && op2b->Next != op2 && op2b->Next != op1) + op2b = op2b->Next; + if (op2b->Next == op2 || op2b->Next == op1) return false; //a flat 'polygon' + + cInt Left, Right; + //Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges + if (!GetOverlap(op1->Pt.X, op1b->Pt.X, op2->Pt.X, op2b->Pt.X, Left, Right)) + return false; + + //DiscardLeftSide: when overlapping edges are joined, a spike will created + //which needs to be cleaned up. However, we don't want Op1 or Op2 caught up + //on the discard Side as either may still be needed for other joins ... + IntPoint Pt; + bool DiscardLeftSide; + if (op1->Pt.X >= Left && op1->Pt.X <= Right) + { + Pt = op1->Pt; DiscardLeftSide = (op1->Pt.X > op1b->Pt.X); + } + else if (op2->Pt.X >= Left&& op2->Pt.X <= Right) + { + Pt = op2->Pt; DiscardLeftSide = (op2->Pt.X > op2b->Pt.X); + } + else if (op1b->Pt.X >= Left && op1b->Pt.X <= Right) + { + Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.X > op1->Pt.X; + } + else + { + Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.X > op2->Pt.X); + } + j->OutPt1 = op1; j->OutPt2 = op2; + return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide); + } else + { + //nb: For non-horizontal joins ... + // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y + // 2. Jr.OutPt1.Pt > Jr.OffPt.Y + + //make sure the polygons are correctly oriented ... + op1b = op1->Next; + while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Next; + bool Reverse1 = ((op1b->Pt.Y > op1->Pt.Y) || + !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)); + if (Reverse1) + { + op1b = op1->Prev; + while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Prev; + if ((op1b->Pt.Y > op1->Pt.Y) || + !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)) return false; + }; + op2b = op2->Next; + while ((op2b->Pt == op2->Pt) && (op2b != op2))op2b = op2b->Next; + bool Reverse2 = ((op2b->Pt.Y > op2->Pt.Y) || + !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)); + if (Reverse2) + { + op2b = op2->Prev; + while ((op2b->Pt == op2->Pt) && (op2b != op2)) op2b = op2b->Prev; + if ((op2b->Pt.Y > op2->Pt.Y) || + !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)) return false; + } + + if ((op1b == op1) || (op2b == op2) || (op1b == op2b) || + ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false; + + if (Reverse1) + { + op1b = DupOutPt(op1, false); + op2b = DupOutPt(op2, true); + op1->Prev = op2; + op2->Next = op1; + op1b->Next = op2b; + op2b->Prev = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } else + { + op1b = DupOutPt(op1, true); + op2b = DupOutPt(op2, false); + op1->Next = op2; + op2->Prev = op1; + op1b->Prev = op2b; + op2b->Next = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } + } +} +//---------------------------------------------------------------------- + +void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) +{ + + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec* outRec = m_PolyOuts[i]; + if (outRec->Pts && outRec->FirstLeft == OldOutRec) + { + if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts)) + outRec->FirstLeft = NewOutRec; + } + } +} +//---------------------------------------------------------------------- + +void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) +{ + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec* outRec = m_PolyOuts[i]; + if (outRec->FirstLeft == OldOutRec) outRec->FirstLeft = NewOutRec; + } +} +//---------------------------------------------------------------------- + +static OutRec* ParseFirstLeft(OutRec* FirstLeft) +{ + while (FirstLeft && !FirstLeft->Pts) + FirstLeft = FirstLeft->FirstLeft; + return FirstLeft; +} +//------------------------------------------------------------------------------ + +void Clipper::JoinCommonEdges() +{ + for (JoinList::size_type i = 0; i < m_Joins.size(); i++) + { + Join* join = m_Joins[i]; + + OutRec *outRec1 = GetOutRec(join->OutPt1->Idx); + OutRec *outRec2 = GetOutRec(join->OutPt2->Idx); + + if (!outRec1->Pts || !outRec2->Pts) continue; + + //get the polygon fragment with the correct hole state (FirstLeft) + //before calling JoinPoints() ... + OutRec *holeStateRec; + if (outRec1 == outRec2) holeStateRec = outRec1; + else if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2; + else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1; + else holeStateRec = GetLowermostRec(outRec1, outRec2); + + if (!JoinPoints(join, outRec1, outRec2)) continue; + + if (outRec1 == outRec2) + { + //instead of joining two polygons, we've just created a new one by + //splitting one polygon into two. + outRec1->Pts = join->OutPt1; + outRec1->BottomPt = 0; + outRec2 = CreateOutRec(); + outRec2->Pts = join->OutPt2; + + //update all OutRec2.Pts Idx's ... + UpdateOutPtIdxs(*outRec2); + + //We now need to check every OutRec.FirstLeft pointer. If it points + //to OutRec1 it may need to point to OutRec2 instead ... + if (m_UsingPolyTree) + for (PolyOutList::size_type j = 0; j < m_PolyOuts.size() - 1; j++) + { + OutRec* oRec = m_PolyOuts[j]; + if (!oRec->Pts || ParseFirstLeft(oRec->FirstLeft) != outRec1 || + oRec->IsHole == outRec1->IsHole) continue; + if (Poly2ContainsPoly1(oRec->Pts, join->OutPt2)) + oRec->FirstLeft = outRec2; + } + + if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts)) + { + //outRec2 is contained by outRec1 ... + outRec2->IsHole = !outRec1->IsHole; + outRec2->FirstLeft = outRec1; + + //fixup FirstLeft pointers that may need reassigning to OutRec1 + if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); + + if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0)) + ReversePolyPtLinks(outRec2->Pts); + + } else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts)) + { + //outRec1 is contained by outRec2 ... + outRec2->IsHole = outRec1->IsHole; + outRec1->IsHole = !outRec2->IsHole; + outRec2->FirstLeft = outRec1->FirstLeft; + outRec1->FirstLeft = outRec2; + + //fixup FirstLeft pointers that may need reassigning to OutRec1 + if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2); + + if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0)) + ReversePolyPtLinks(outRec1->Pts); + } + else + { + //the 2 polygons are completely separate ... + outRec2->IsHole = outRec1->IsHole; + outRec2->FirstLeft = outRec1->FirstLeft; + + //fixup FirstLeft pointers that may need reassigning to OutRec2 + if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2); + } + + } else + { + //joined 2 polygons together ... + + outRec2->Pts = 0; + outRec2->BottomPt = 0; + outRec2->Idx = outRec1->Idx; + + outRec1->IsHole = holeStateRec->IsHole; + if (holeStateRec == outRec2) + outRec1->FirstLeft = outRec2->FirstLeft; + outRec2->FirstLeft = outRec1; + + //fixup FirstLeft pointers that may need reassigning to OutRec1 + if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); + } + } +} + +//------------------------------------------------------------------------------ +// ClipperOffset support functions ... +//------------------------------------------------------------------------------ + +DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2) +{ + if(pt2.X == pt1.X && pt2.Y == pt1.Y) + return DoublePoint(0, 0); + + double Dx = (double)(pt2.X - pt1.X); + double dy = (double)(pt2.Y - pt1.Y); + double f = 1 *1.0/ std::sqrt( Dx*Dx + dy*dy ); + Dx *= f; + dy *= f; + return DoublePoint(dy, -Dx); +} + +//------------------------------------------------------------------------------ +// ClipperOffset class +//------------------------------------------------------------------------------ + +ClipperOffset::ClipperOffset(double miterLimit, double arcTolerance) +{ + this->MiterLimit = miterLimit; + this->ArcTolerance = arcTolerance; + m_lowest.X = -1; +} +//------------------------------------------------------------------------------ + +ClipperOffset::~ClipperOffset() +{ + Clear(); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::Clear() +{ + for (int i = 0; i < m_polyNodes.ChildCount(); ++i) + delete m_polyNodes.Childs[i]; + m_polyNodes.Childs.clear(); + m_lowest.X = -1; +} +//------------------------------------------------------------------------------ + +void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType) +{ + int highI = (int)path.size() - 1; + if (highI < 0) return; + PolyNode* newNode = new PolyNode(); + newNode->m_jointype = joinType; + newNode->m_endtype = endType; + + //strip duplicate points from path and also get index to the lowest point ... + if (endType == etClosedLine || endType == etClosedPolygon) + while (highI > 0 && path[0] == path[highI]) highI--; + newNode->Contour.reserve(highI + 1); + newNode->Contour.push_back(path[0]); + int j = 0, k = 0; + for (int i = 1; i <= highI; i++) + if (newNode->Contour[j] != path[i]) + { + j++; + newNode->Contour.push_back(path[i]); + if (path[i].Y > newNode->Contour[k].Y || + (path[i].Y == newNode->Contour[k].Y && + path[i].X < newNode->Contour[k].X)) k = j; + } + if ((endType == etClosedPolygon && j < 2) || + (endType != etClosedPolygon && j < 0)) + { + delete newNode; + return; + } + m_polyNodes.AddChild(*newNode); + + //if this path's lowest pt is lower than all the others then update m_lowest + if (endType != etClosedPolygon) return; + if (m_lowest.X < 0) + m_lowest = IntPoint(0, k); + else + { + IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y]; + if (newNode->Contour[k].Y > ip.Y || + (newNode->Contour[k].Y == ip.Y && + newNode->Contour[k].X < ip.X)) + m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k); + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::AddPaths(const Paths& paths, JoinType joinType, EndType endType) +{ + for (Paths::size_type i = 0; i < paths.size(); ++i) + AddPath(paths[i], joinType, endType); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::FixOrientations() +{ + //fixup orientations of all closed paths if the orientation of the + //closed path with the lowermost vertex is wrong ... + if (m_lowest.X >= 0 && + !Orientation(m_polyNodes.Childs[(int)m_lowest.X]->Contour)) + { + for (int i = 0; i < m_polyNodes.ChildCount(); ++i) + { + PolyNode& node = *m_polyNodes.Childs[i]; + if (node.m_endtype == etClosedPolygon || + (node.m_endtype == etClosedLine && Orientation(node.Contour))) + ReversePath(node.Contour); + } + } else + { + for (int i = 0; i < m_polyNodes.ChildCount(); ++i) + { + PolyNode& node = *m_polyNodes.Childs[i]; + if (node.m_endtype == etClosedLine && !Orientation(node.Contour)) + ReversePath(node.Contour); + } + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::Execute(Paths& solution, double delta) +{ + solution.clear(); + FixOrientations(); + DoOffset(delta); + + //now clean up 'corners' ... + Clipper clpr; + clpr.AddPaths(m_destPolys, ptSubject, true); + if (delta > 0) + { + clpr.Execute(ctUnion, solution, pftPositive, pftPositive); + } + else + { + IntRect r = clpr.GetBounds(); + Path outer(4); + outer[0] = IntPoint(r.left - 10, r.bottom + 10); + outer[1] = IntPoint(r.right + 10, r.bottom + 10); + outer[2] = IntPoint(r.right + 10, r.top - 10); + outer[3] = IntPoint(r.left - 10, r.top - 10); + + clpr.AddPath(outer, ptSubject, true); + clpr.ReverseSolution(true); + clpr.Execute(ctUnion, solution, pftNegative, pftNegative); + if (solution.size() > 0) solution.erase(solution.begin()); + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::Execute(PolyTree& solution, double delta) +{ + solution.Clear(); + FixOrientations(); + DoOffset(delta); + + //now clean up 'corners' ... + Clipper clpr; + clpr.AddPaths(m_destPolys, ptSubject, true); + if (delta > 0) + { + clpr.Execute(ctUnion, solution, pftPositive, pftPositive); + } + else + { + IntRect r = clpr.GetBounds(); + Path outer(4); + outer[0] = IntPoint(r.left - 10, r.bottom + 10); + outer[1] = IntPoint(r.right + 10, r.bottom + 10); + outer[2] = IntPoint(r.right + 10, r.top - 10); + outer[3] = IntPoint(r.left - 10, r.top - 10); + + clpr.AddPath(outer, ptSubject, true); + clpr.ReverseSolution(true); + clpr.Execute(ctUnion, solution, pftNegative, pftNegative); + //remove the outer PolyNode rectangle ... + if (solution.ChildCount() == 1 && solution.Childs[0]->ChildCount() > 0) + { + PolyNode* outerNode = solution.Childs[0]; + solution.Childs.reserve(outerNode->ChildCount()); + solution.Childs[0] = outerNode->Childs[0]; + for (int i = 1; i < outerNode->ChildCount(); ++i) + solution.AddChild(*outerNode->Childs[i]); + } + else + solution.Clear(); + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoOffset(double delta) +{ + m_destPolys.clear(); + m_delta = delta; + + //if Zero offset, just copy any CLOSED polygons to m_p and return ... + if (NEAR_ZERO(delta)) + { + m_destPolys.reserve(m_polyNodes.ChildCount()); + for (int i = 0; i < m_polyNodes.ChildCount(); i++) + { + PolyNode& node = *m_polyNodes.Childs[i]; + if (node.m_endtype == etClosedPolygon) + m_destPolys.push_back(node.Contour); + } + return; + } + + //see offset_triginometry3.svg in the documentation folder ... + if (MiterLimit > 2) m_miterLim = 2/(MiterLimit * MiterLimit); + else m_miterLim = 0.5; + + double y; + if (ArcTolerance <= 0.0) y = def_arc_tolerance; + else if (ArcTolerance > std::fabs(delta) * def_arc_tolerance) + y = std::fabs(delta) * def_arc_tolerance; + else y = ArcTolerance; + //see offset_triginometry2.svg in the documentation folder ... + double steps = pi / std::acos(1 - y / std::fabs(delta)); + if (steps > std::fabs(delta) * pi) + steps = std::fabs(delta) * pi; //ie excessive precision check + m_sin = std::sin(two_pi / steps); + m_cos = std::cos(two_pi / steps); + m_StepsPerRad = steps / two_pi; + if (delta < 0.0) m_sin = -m_sin; + + m_destPolys.reserve(m_polyNodes.ChildCount() * 2); + for (int i = 0; i < m_polyNodes.ChildCount(); i++) + { + PolyNode& node = *m_polyNodes.Childs[i]; + m_srcPoly = node.Contour; + + int len = (int)m_srcPoly.size(); + if (len == 0 || (delta <= 0 && (len < 3 || node.m_endtype != etClosedPolygon))) + continue; + + m_destPoly.clear(); + if (len == 1) + { + if (node.m_jointype == jtRound) + { + double X = 1.0, Y = 0.0; + for (cInt j = 1; j <= steps; j++) + { + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[0].X + X * delta), + Round(m_srcPoly[0].Y + Y * delta))); + double X2 = X; + X = X * m_cos - m_sin * Y; + Y = X2 * m_sin + Y * m_cos; + } + } + else + { + double X = -1.0, Y = -1.0; + for (int j = 0; j < 4; ++j) + { + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[0].X + X * delta), + Round(m_srcPoly[0].Y + Y * delta))); + if (X < 0) X = 1; + else if (Y < 0) Y = 1; + else X = -1; + } + } + m_destPolys.push_back(m_destPoly); + continue; + } + //build m_normals ... + m_normals.clear(); + m_normals.reserve(len); + for (int j = 0; j < len - 1; ++j) + m_normals.push_back(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1])); + if (node.m_endtype == etClosedLine || node.m_endtype == etClosedPolygon) + m_normals.push_back(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0])); + else + m_normals.push_back(DoublePoint(m_normals[len - 2])); + + if (node.m_endtype == etClosedPolygon) + { + int k = len - 1; + for (int j = 0; j < len; ++j) + OffsetPoint(j, k, node.m_jointype); + m_destPolys.push_back(m_destPoly); + } + else if (node.m_endtype == etClosedLine) + { + int k = len - 1; + for (int j = 0; j < len; ++j) + OffsetPoint(j, k, node.m_jointype); + m_destPolys.push_back(m_destPoly); + m_destPoly.clear(); + //re-build m_normals ... + DoublePoint n = m_normals[len -1]; + for (int j = len - 1; j > 0; j--) + m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); + m_normals[0] = DoublePoint(-n.X, -n.Y); + k = 0; + for (int j = len - 1; j >= 0; j--) + OffsetPoint(j, k, node.m_jointype); + m_destPolys.push_back(m_destPoly); + } + else + { + int k = 0; + for (int j = 1; j < len - 1; ++j) + OffsetPoint(j, k, node.m_jointype); + + IntPoint pt1; + if (node.m_endtype == etOpenButt) + { + int j = len - 1; + pt1 = IntPoint((cInt)Round(m_srcPoly[j].X + m_normals[j].X * + delta), (cInt)Round(m_srcPoly[j].Y + m_normals[j].Y * delta)); + m_destPoly.push_back(pt1); + pt1 = IntPoint((cInt)Round(m_srcPoly[j].X - m_normals[j].X * + delta), (cInt)Round(m_srcPoly[j].Y - m_normals[j].Y * delta)); + m_destPoly.push_back(pt1); + } + else + { + int j = len - 1; + k = len - 2; + m_sinA = 0; + m_normals[j] = DoublePoint(-m_normals[j].X, -m_normals[j].Y); + if (node.m_endtype == etOpenSquare) + DoSquare(j, k); + else + DoRound(j, k); + } + + //re-build m_normals ... + for (int j = len - 1; j > 0; j--) + m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); + m_normals[0] = DoublePoint(-m_normals[1].X, -m_normals[1].Y); + + k = len - 1; + for (int j = k - 1; j > 0; --j) OffsetPoint(j, k, node.m_jointype); + + if (node.m_endtype == etOpenButt) + { + pt1 = IntPoint((cInt)Round(m_srcPoly[0].X - m_normals[0].X * delta), + (cInt)Round(m_srcPoly[0].Y - m_normals[0].Y * delta)); + m_destPoly.push_back(pt1); + pt1 = IntPoint((cInt)Round(m_srcPoly[0].X + m_normals[0].X * delta), + (cInt)Round(m_srcPoly[0].Y + m_normals[0].Y * delta)); + m_destPoly.push_back(pt1); + } + else + { + k = 1; + m_sinA = 0; + if (node.m_endtype == etOpenSquare) + DoSquare(0, 1); + else + DoRound(0, 1); + } + m_destPolys.push_back(m_destPoly); + } + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype) +{ + m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y); + if (m_sinA < 0.00005 && m_sinA > -0.00005) return; + else if (m_sinA > 1.0) m_sinA = 1.0; + else if (m_sinA < -1.0) m_sinA = -1.0; + + if (m_sinA * m_delta < 0) + { + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta))); + m_destPoly.push_back(m_srcPoly[j]); + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); + } + else + switch (jointype) + { + case jtMiter: + { + double r = 1 + (m_normals[j].X * m_normals[k].X + + m_normals[j].Y * m_normals[k].Y); + if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k); + break; + } + case jtSquare: DoSquare(j, k); break; + case jtRound: DoRound(j, k); break; + } + k = j; +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoSquare(int j, int k) +{ + double dx = std::tan(std::atan2(m_sinA, + m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y) / 4); + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx)), + Round(m_srcPoly[j].Y + m_delta * (m_normals[k].Y + m_normals[k].X * dx)))); + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx)), + Round(m_srcPoly[j].Y + m_delta * (m_normals[j].Y - m_normals[j].X * dx)))); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoMiter(int j, int k, double r) +{ + double q = m_delta / r; + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + (m_normals[k].X + m_normals[j].X) * q), + Round(m_srcPoly[j].Y + (m_normals[k].Y + m_normals[j].Y) * q))); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoRound(int j, int k) +{ + double a = std::atan2(m_sinA, + m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y); + int steps = (int)Round(m_StepsPerRad * std::fabs(a)); + + double X = m_normals[k].X, Y = m_normals[k].Y, X2; + for (int i = 0; i < steps; ++i) + { + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + X * m_delta), + Round(m_srcPoly[j].Y + Y * m_delta))); + X2 = X; + X = X * m_cos - m_sin * Y; + Y = X2 * m_sin + Y * m_cos; + } + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + m_normals[j].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); +} + +//------------------------------------------------------------------------------ +// Miscellaneous public functions +//------------------------------------------------------------------------------ + +void Clipper::DoSimplePolygons() +{ + PolyOutList::size_type i = 0; + while (i < m_PolyOuts.size()) + { + OutRec* outrec = m_PolyOuts[i++]; + OutPt* op = outrec->Pts; + if (!op) continue; + do //for each Pt in Polygon until duplicate found do ... + { + OutPt* op2 = op->Next; + while (op2 != outrec->Pts) + { + if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op) + { + //split the polygon into two ... + OutPt* op3 = op->Prev; + OutPt* op4 = op2->Prev; + op->Prev = op4; + op4->Next = op; + op2->Prev = op3; + op3->Next = op2; + + outrec->Pts = op; + OutRec* outrec2 = CreateOutRec(); + outrec2->Pts = op2; + UpdateOutPtIdxs(*outrec2); + if (Poly2ContainsPoly1(outrec2->Pts, outrec->Pts)) + { + //OutRec2 is contained by OutRec1 ... + outrec2->IsHole = !outrec->IsHole; + outrec2->FirstLeft = outrec; + } + else + if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts)) + { + //OutRec1 is contained by OutRec2 ... + outrec2->IsHole = outrec->IsHole; + outrec->IsHole = !outrec2->IsHole; + outrec2->FirstLeft = outrec->FirstLeft; + outrec->FirstLeft = outrec2; + } else + { + //the 2 polygons are separate ... + outrec2->IsHole = outrec->IsHole; + outrec2->FirstLeft = outrec->FirstLeft; + } + op2 = op; //ie get ready for the Next iteration + } + op2 = op2->Next; + } + op = op->Next; + } + while (op != outrec->Pts); + } +} +//------------------------------------------------------------------------------ + +void ReversePath(Path& p) +{ + std::reverse(p.begin(), p.end()); +} +//------------------------------------------------------------------------------ + +void ReversePaths(Paths& p) +{ + for (Paths::size_type i = 0; i < p.size(); ++i) + ReversePath(p[i]); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType) +{ + Clipper c; + c.StrictlySimple(true); + c.AddPath(in_poly, ptSubject, true); + c.Execute(ctUnion, out_polys, fillType, fillType); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType) +{ + Clipper c; + c.StrictlySimple(true); + c.AddPaths(in_polys, ptSubject, true); + c.Execute(ctUnion, out_polys, fillType, fillType); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygons(Paths &polys, PolyFillType fillType) +{ + SimplifyPolygons(polys, polys, fillType); +} +//------------------------------------------------------------------------------ + +inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2) +{ + double Dx = ((double)pt1.X - pt2.X); + double dy = ((double)pt1.Y - pt2.Y); + return (Dx*Dx + dy*dy); +} +//------------------------------------------------------------------------------ + +double DistanceFromLineSqrd( + const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2) +{ + //The equation of a line in general form (Ax + By + C = 0) + //given 2 points (x¹,y¹) & (x²,y²) is ... + //(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0 + //A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹ + //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²) + //see http://en.wikipedia.org/wiki/Perpendicular_distance + double A = double(ln1.Y - ln2.Y); + double B = double(ln2.X - ln1.X); + double C = A * ln1.X + B * ln1.Y; + C = A * pt.X + B * pt.Y - C; + return (C * C) / (A * A + B * B); +} +//--------------------------------------------------------------------------- + +bool SlopesNearCollinear(const IntPoint& pt1, + const IntPoint& pt2, const IntPoint& pt3, double distSqrd) +{ + return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; +} +//------------------------------------------------------------------------------ + +bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd) +{ + double Dx = (double)pt1.X - pt2.X; + double dy = (double)pt1.Y - pt2.Y; + return ((Dx * Dx) + (dy * dy) <= distSqrd); +} +//------------------------------------------------------------------------------ + +OutPt* ExcludeOp(OutPt* op) +{ + OutPt* result = op->Prev; + result->Next = op->Next; + op->Next->Prev = result; + result->Idx = 0; + return result; +} +//------------------------------------------------------------------------------ + +void CleanPolygon(const Path& in_poly, Path& out_poly, double distance) +{ + //distance = proximity in units/pixels below which vertices + //will be stripped. Default ~= sqrt(2). + + size_t size = in_poly.size(); + + if (size == 0) + { + out_poly.clear(); + return; + } + + OutPt* outPts = new OutPt[size]; + for (size_t i = 0; i < size; ++i) + { + outPts[i].Pt = in_poly[i]; + outPts[i].Next = &outPts[(i + 1) % size]; + outPts[i].Next->Prev = &outPts[i]; + outPts[i].Idx = 0; + } + + double distSqrd = distance * distance; + OutPt* op = &outPts[0]; + while (op->Idx == 0 && op->Next != op->Prev) + { + if (PointsAreClose(op->Pt, op->Prev->Pt, distSqrd)) + { + op = ExcludeOp(op); + size--; + } + else if (PointsAreClose(op->Prev->Pt, op->Next->Pt, distSqrd)) + { + ExcludeOp(op->Next); + op = ExcludeOp(op); + size -= 2; + } + else if (SlopesNearCollinear(op->Prev->Pt, op->Pt, op->Next->Pt, distSqrd)) + { + op = ExcludeOp(op); + size--; + } + else + { + op->Idx = 1; + op = op->Next; + } + } + + if (size < 3) size = 0; + out_poly.resize(size); + for (size_t i = 0; i < size; ++i) + { + out_poly[i] = op->Pt; + op = op->Next; + } + delete [] outPts; +} +//------------------------------------------------------------------------------ + +void CleanPolygon(Path& poly, double distance) +{ + CleanPolygon(poly, poly, distance); +} +//------------------------------------------------------------------------------ + +void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance) +{ + for (Paths::size_type i = 0; i < in_polys.size(); ++i) + CleanPolygon(in_polys[i], out_polys[i], distance); +} +//------------------------------------------------------------------------------ + +void CleanPolygons(Paths& polys, double distance) +{ + CleanPolygons(polys, polys, distance); +} +//------------------------------------------------------------------------------ + +void Minkowski(const Path& poly, const Path& path, + Paths& solution, bool isSum, bool isClosed) +{ + int delta = (isClosed ? 1 : 0); + size_t polyCnt = poly.size(); + size_t pathCnt = path.size(); + Paths pp; + pp.reserve(pathCnt); + if (isSum) + for (size_t i = 0; i < pathCnt; ++i) + { + Path p; + p.reserve(polyCnt); + for (size_t j = 0; j < poly.size(); ++j) + p.push_back(IntPoint(path[i].X + poly[j].X, path[i].Y + poly[j].Y)); + pp.push_back(p); + } + else + for (size_t i = 0; i < pathCnt; ++i) + { + Path p; + p.reserve(polyCnt); + for (size_t j = 0; j < poly.size(); ++j) + p.push_back(IntPoint(path[i].X - poly[j].X, path[i].Y - poly[j].Y)); + pp.push_back(p); + } + + Paths quads; + quads.reserve((pathCnt + delta) * (polyCnt + 1)); + for (size_t i = 0; i < pathCnt - 1 + delta; ++i) + for (size_t j = 0; j < polyCnt; ++j) + { + Path quad; + quad.reserve(4); + quad.push_back(pp[i % pathCnt][j % polyCnt]); + quad.push_back(pp[(i + 1) % pathCnt][j % polyCnt]); + quad.push_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]); + quad.push_back(pp[i % pathCnt][(j + 1) % polyCnt]); + if (!Orientation(quad)) ReversePath(quad); + quads.push_back(quad); + } + + Clipper c; + c.AddPaths(quads, ptSubject, true); + c.Execute(ctUnion, solution, pftNonZero, pftNonZero); +} +//------------------------------------------------------------------------------ + +void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed) +{ + Minkowski(pattern, path, solution, true, pathIsClosed); +} +//------------------------------------------------------------------------------ + +void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, + PolyFillType pathFillType, bool pathIsClosed) +{ + Clipper c; + for (size_t i = 0; i < paths.size(); ++i) + { + Paths tmp; + Minkowski(pattern, paths[i], tmp, true, pathIsClosed); + c.AddPaths(tmp, ptSubject, true); + } + if (pathIsClosed) c.AddPaths(paths, ptClip, true); + c.Execute(ctUnion, solution, pathFillType, pathFillType); +} +//------------------------------------------------------------------------------ + +void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution) +{ + Minkowski(poly1, poly2, solution, false, true); +} +//------------------------------------------------------------------------------ + +enum NodeType {ntAny, ntOpen, ntClosed}; + +void AddPolyNodeToPolygons(const PolyNode& polynode, NodeType nodetype, Paths& paths) +{ + bool match = true; + if (nodetype == ntClosed) match = !polynode.IsOpen(); + else if (nodetype == ntOpen) return; + + if (!polynode.Contour.empty() && match) + paths.push_back(polynode.Contour); + for (int i = 0; i < polynode.ChildCount(); ++i) + AddPolyNodeToPolygons(*polynode.Childs[i], nodetype, paths); +} +//------------------------------------------------------------------------------ + +void PolyTreeToPaths(const PolyTree& polytree, Paths& paths) +{ + paths.resize(0); + paths.reserve(polytree.Total()); + AddPolyNodeToPolygons(polytree, ntAny, paths); +} +//------------------------------------------------------------------------------ + +void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths) +{ + paths.resize(0); + paths.reserve(polytree.Total()); + AddPolyNodeToPolygons(polytree, ntClosed, paths); +} +//------------------------------------------------------------------------------ + +void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths) +{ + paths.resize(0); + paths.reserve(polytree.Total()); + //Open paths are top level only, so ... + for (int i = 0; i < polytree.ChildCount(); ++i) + if (polytree.Childs[i]->IsOpen()) + paths.push_back(polytree.Childs[i]->Contour); +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, const IntPoint &p) +{ + s << "(" << p.X << "," << p.Y << ")"; + return s; +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, const Path &p) +{ + if (p.empty()) return s; + Path::size_type last = p.size() -1; + for (Path::size_type i = 0; i < last; i++) + s << "(" << p[i].X << "," << p[i].Y << "), "; + s << "(" << p[last].X << "," << p[last].Y << ")\n"; + return s; +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, const Paths &p) +{ + for (Paths::size_type i = 0; i < p.size(); i++) + s << p[i]; + s << "\n"; + return s; +} +//------------------------------------------------------------------------------ + +#ifdef use_deprecated + +void OffsetPaths(const Paths &in_polys, Paths &out_polys, + double delta, JoinType jointype, EndType_ endtype, double limit) +{ + ClipperOffset co(limit, limit); + co.AddPaths(in_polys, jointype, (EndType)endtype); + co.Execute(out_polys, delta); +} +//------------------------------------------------------------------------------ + +#endif + + +} //ClipperLib namespace diff --git a/src/clipper/clipper.hpp b/src/clipper/clipper.hpp new file mode 100755 index 000000000..84870141e --- /dev/null +++ b/src/clipper/clipper.hpp @@ -0,0 +1,398 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 6.1.3a * +* Date : 22 January 2014 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2014 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Attributions: * +* The code in this library is an extension of Bala Vatti's clipping algorithm: * +* "A generic solution to polygon clipping" * +* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * +* http://portal.acm.org/citation.cfm?id=129906 * +* * +* Computer graphics and geometric modeling: implementation and algorithms * +* By Max K. Agoston * +* Springer; 1 edition (January 4, 2005) * +* http://books.google.com/books?q=vatti+clipping+agoston * +* * +* See also: * +* "Polygon Offsetting by Computing Winding Numbers" * +* Paper no. DETC2005-85513 pp. 565-575 * +* ASME 2005 International Design Engineering Technical Conferences * +* and Computers and Information in Engineering Conference (IDETC/CIE2005) * +* September 24-28, 2005 , Long Beach, California, USA * +* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * +* * +*******************************************************************************/ + +#ifndef clipper_hpp +#define clipper_hpp + +#define CLIPPER_VERSION "6.1.3" + +//use_int32: When enabled 32bit ints are used instead of 64bit ints. This +//improve performance but coordinate values are limited to the range +/- 46340 +//#define use_int32 + +//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance. +//#define use_xyz + +//use_lines: Enables line clipping. Adds a very minor cost to performance. +//#define use_lines + +//use_deprecated: Enables support for the obsolete OffsetPaths() function +//which has been replace with the ClipperOffset class. +#define use_deprecated + +#include +#include +#include +#include +#include +#include +#include + +namespace ClipperLib { + +enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; +enum PolyType { ptSubject, ptClip }; +//By far the most widely used winding rules for polygon filling are +//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) +//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) +//see http://glprogramming.com/red/chapter11.html +enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; + +#ifdef use_int32 +typedef int cInt; +typedef unsigned int cUInt; +#else +typedef signed long long cInt; +typedef unsigned long long cUInt; +#endif + +struct IntPoint { + cInt X; + cInt Y; +#ifdef use_xyz + cInt Z; + IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {}; +#else + IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {}; +#endif + + friend inline bool operator== (const IntPoint& a, const IntPoint& b) + { + return a.X == b.X && a.Y == b.Y; + } + friend inline bool operator!= (const IntPoint& a, const IntPoint& b) + { + return a.X != b.X || a.Y != b.Y; + } +}; +//------------------------------------------------------------------------------ + +typedef std::vector< IntPoint > Path; +typedef std::vector< Path > Paths; + +inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;} +inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;} + +std::ostream& operator <<(std::ostream &s, const IntPoint &p); +std::ostream& operator <<(std::ostream &s, const Path &p); +std::ostream& operator <<(std::ostream &s, const Paths &p); + +struct DoublePoint +{ + double X; + double Y; + DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} + DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {} +}; +//------------------------------------------------------------------------------ + +#ifdef use_xyz +typedef void (*TZFillCallback)(IntPoint& z1, IntPoint& z2, IntPoint& pt); +#endif + +enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4}; +enum JoinType {jtSquare, jtRound, jtMiter}; +enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound}; +#ifdef use_deprecated + enum EndType_ {etClosed, etButt = 2, etSquare, etRound}; +#endif + +class PolyNode; +typedef std::vector< PolyNode* > PolyNodes; + +class PolyNode +{ +public: + PolyNode(); + Path Contour; + PolyNodes Childs; + PolyNode* Parent; + PolyNode* GetNext() const; + bool IsHole() const; + bool IsOpen() const; + int ChildCount() const; +private: + unsigned Index; //node index in Parent.Childs + bool m_IsOpen; + JoinType m_jointype; + EndType m_endtype; + PolyNode* GetNextSiblingUp() const; + void AddChild(PolyNode& child); + friend class Clipper; //to access Index + friend class ClipperOffset; +}; + +class PolyTree: public PolyNode +{ +public: + ~PolyTree(){Clear();}; + PolyNode* GetFirst() const; + void Clear(); + int Total() const; +private: + PolyNodes AllNodes; + friend class Clipper; //to access AllNodes +}; + +bool Orientation(const Path &poly); +double Area(const Path &poly); +int PointInPolygon(const IntPoint &pt, const Path &path); + +#ifdef use_deprecated + void OffsetPaths(const Paths &in_polys, Paths &out_polys, + double delta, JoinType jointype, EndType_ endtype, double limit = 0); +#endif + +void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd); +void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd); +void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd); + +void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); +void CleanPolygon(Path& poly, double distance = 1.415); +void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415); +void CleanPolygons(Paths& polys, double distance = 1.415); + +void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed); +void MinkowskiSum(const Path& pattern, const Paths& paths, + Paths& solution, PolyFillType pathFillType, bool pathIsClosed); +void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution); + +void PolyTreeToPaths(const PolyTree& polytree, Paths& paths); +void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths); +void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths); + +void ReversePath(Path& p); +void ReversePaths(Paths& p); + +struct IntRect { cInt left; cInt top; cInt right; cInt bottom; }; + +//enums that are used internally ... +enum EdgeSide { esLeft = 1, esRight = 2}; + +//forward declarations (for stuff used internally) ... +struct TEdge; +struct IntersectNode; +struct LocalMinima; +struct Scanbeam; +struct OutPt; +struct OutRec; +struct Join; + +typedef std::vector < OutRec* > PolyOutList; +typedef std::vector < TEdge* > EdgeList; +typedef std::vector < Join* > JoinList; +typedef std::vector < IntersectNode* > IntersectList; + + +//------------------------------------------------------------------------------ + +//ClipperBase is the ancestor to the Clipper class. It should not be +//instantiated directly. This class simply abstracts the conversion of sets of +//polygon coordinates into edge objects that are stored in a LocalMinima list. +class ClipperBase +{ +public: + ClipperBase(); + virtual ~ClipperBase(); + bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed); + bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed); + virtual void Clear(); + IntRect GetBounds(); + bool PreserveCollinear() {return m_PreserveCollinear;}; + void PreserveCollinear(bool value) {m_PreserveCollinear = value;}; +protected: + void DisposeLocalMinimaList(); + TEdge* AddBoundsToLML(TEdge *e, bool IsClosed); + void PopLocalMinima(); + virtual void Reset(); + TEdge* ProcessBound(TEdge* E, bool IsClockwise); + void InsertLocalMinima(LocalMinima *newLm); + void DoMinimaLML(TEdge* E1, TEdge* E2, bool IsClosed); + TEdge* DescendToMin(TEdge *&E); + void AscendToMax(TEdge *&E, bool Appending, bool IsClosed); + LocalMinima *m_CurrentLM; + LocalMinima *m_MinimaList; + bool m_UseFullRange; + EdgeList m_edges; + bool m_PreserveCollinear; + bool m_HasOpenPaths; +}; +//------------------------------------------------------------------------------ + +class Clipper : public virtual ClipperBase +{ +public: + Clipper(int initOptions = 0); + ~Clipper(); + bool Execute(ClipType clipType, + Paths &solution, + PolyFillType subjFillType = pftEvenOdd, + PolyFillType clipFillType = pftEvenOdd); + bool Execute(ClipType clipType, + PolyTree &polytree, + PolyFillType subjFillType = pftEvenOdd, + PolyFillType clipFillType = pftEvenOdd); + bool ReverseSolution() {return m_ReverseOutput;}; + void ReverseSolution(bool value) {m_ReverseOutput = value;}; + bool StrictlySimple() {return m_StrictSimple;}; + void StrictlySimple(bool value) {m_StrictSimple = value;}; + //set the callback function for z value filling on intersections (otherwise Z is 0) +#ifdef use_xyz + void ZFillFunction(TZFillCallback zFillFunc); +#endif +protected: + void Reset(); + virtual bool ExecuteInternal(); +private: + PolyOutList m_PolyOuts; + JoinList m_Joins; + JoinList m_GhostJoins; + IntersectList m_IntersectList; + ClipType m_ClipType; + std::set< cInt, std::greater > m_Scanbeam; + TEdge *m_ActiveEdges; + TEdge *m_SortedEdges; + bool m_ExecuteLocked; + PolyFillType m_ClipFillType; + PolyFillType m_SubjFillType; + bool m_ReverseOutput; + bool m_UsingPolyTree; + bool m_StrictSimple; +#ifdef use_xyz + TZFillCallback m_ZFill; //custom callback +#endif + void SetWindingCount(TEdge& edge); + bool IsEvenOddFillType(const TEdge& edge) const; + bool IsEvenOddAltFillType(const TEdge& edge) const; + void InsertScanbeam(const cInt Y); + cInt PopScanbeam(); + void InsertLocalMinimaIntoAEL(const cInt botY); + void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge); + void AddEdgeToSEL(TEdge *edge); + void CopyAELToSEL(); + void DeleteFromSEL(TEdge *e); + void DeleteFromAEL(TEdge *e); + void UpdateEdgeIntoAEL(TEdge *&e); + void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); + bool IsContributing(const TEdge& edge) const; + bool IsTopHorz(const cInt XPos); + void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); + void DoMaxima(TEdge *e); + void PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam); + void ProcessHorizontals(bool IsTopOfScanbeam); + void ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam); + void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); + OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); + OutRec* GetOutRec(int idx); + void AppendPolygon(TEdge *e1, TEdge *e2); + void IntersectEdges(TEdge *e1, TEdge *e2, + const IntPoint &pt, bool protect = false); + OutRec* CreateOutRec(); + OutPt* AddOutPt(TEdge *e, const IntPoint &pt); + void DisposeAllOutRecs(); + void DisposeOutRec(PolyOutList::size_type index); + bool ProcessIntersections(const cInt botY, const cInt topY); + void BuildIntersectList(const cInt botY, const cInt topY); + void ProcessIntersectList(); + void ProcessEdgesAtTopOfScanbeam(const cInt topY); + void BuildResult(Paths& polys); + void BuildResult2(PolyTree& polytree); + void SetHoleState(TEdge *e, OutRec *outrec); + void DisposeIntersectNodes(); + bool FixupIntersectionOrder(); + void FixupOutPolygon(OutRec &outrec); + bool IsHole(TEdge *e); + bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl); + void FixHoleLinkage(OutRec &outrec); + void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt); + void ClearJoins(); + void ClearGhostJoins(); + void AddGhostJoin(OutPt *op, const IntPoint offPt); + bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2); + void JoinCommonEdges(); + void DoSimplePolygons(); + void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); + void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec); +#ifdef use_xyz + void SetZ(IntPoint& pt, TEdge& e); +#endif +}; +//------------------------------------------------------------------------------ + +class ClipperOffset +{ +public: + ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25); + ~ClipperOffset(); + void AddPath(const Path& path, JoinType joinType, EndType endType); + void AddPaths(const Paths& paths, JoinType joinType, EndType endType); + void Execute(Paths& solution, double delta); + void Execute(PolyTree& solution, double delta); + void Clear(); + double MiterLimit; + double ArcTolerance; +private: + Paths m_destPolys; + Path m_srcPoly; + Path m_destPoly; + std::vector m_normals; + double m_delta, m_sinA, m_sin, m_cos; + double m_miterLim, m_StepsPerRad; + IntPoint m_lowest; + PolyNode m_polyNodes; + + void FixOrientations(); + void DoOffset(double delta); + void OffsetPoint(int j, int& k, JoinType jointype); + void DoSquare(int j, int k); + void DoMiter(int j, int k, double r); + void DoRound(int j, int k); +}; +//------------------------------------------------------------------------------ + +class clipperException : public std::exception +{ + public: + clipperException(const char* description): m_descr(description) {} + virtual ~clipperException() throw() {} + virtual const char* what() const throw() {return m_descr.c_str();} + private: + std::string m_descr; +}; +//------------------------------------------------------------------------------ + +} //ClipperLib namespace + +#endif //clipper_hpp + + diff --git a/src/csscolorparser/csscolorparser.cpp b/src/csscolorparser/csscolorparser.cpp new file mode 100644 index 000000000..8281eb420 --- /dev/null +++ b/src/csscolorparser/csscolorparser.cpp @@ -0,0 +1,290 @@ +// (c) Dean McNamee , 2012. +// C++ port by Konstantin Käfer , 2014. +// +// https://github.com/deanm/css-color-parser-js +// https://github.com/kkaefer/css-color-parser-cpp +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "csscolorparser.hpp" + +#include +#include +#include +#include +#include + +using namespace CSSColorParser; + +// http://www.w3.org/TR/css3-color/ +struct NamedColor { const char *const name; const Color color; }; +const NamedColor namedColors[] = { + { "transparent", { 0, 0, 0, 0 } }, { "aliceblue", { 240, 248, 255, 1 } }, + { "antiquewhite", { 250, 235, 215, 1 } }, { "aqua", { 0, 255, 255, 1 } }, + { "aquamarine", { 127, 255, 212, 1 } }, { "azure", { 240, 255, 255, 1 } }, + { "beige", { 245, 245, 220, 1 } }, { "bisque", { 255, 228, 196, 1 } }, + { "black", { 0, 0, 0, 1 } }, { "blanchedalmond", { 255, 235, 205, 1 } }, + { "blue", { 0, 0, 255, 1 } }, { "blueviolet", { 138, 43, 226, 1 } }, + { "brown", { 165, 42, 42, 1 } }, { "burlywood", { 222, 184, 135, 1 } }, + { "cadetblue", { 95, 158, 160, 1 } }, { "chartreuse", { 127, 255, 0, 1 } }, + { "chocolate", { 210, 105, 30, 1 } }, { "coral", { 255, 127, 80, 1 } }, + { "cornflowerblue", { 100, 149, 237, 1 } }, { "cornsilk", { 255, 248, 220, 1 } }, + { "crimson", { 220, 20, 60, 1 } }, { "cyan", { 0, 255, 255, 1 } }, + { "darkblue", { 0, 0, 139, 1 } }, { "darkcyan", { 0, 139, 139, 1 } }, + { "darkgoldenrod", { 184, 134, 11, 1 } }, { "darkgray", { 169, 169, 169, 1 } }, + { "darkgreen", { 0, 100, 0, 1 } }, { "darkgrey", { 169, 169, 169, 1 } }, + { "darkkhaki", { 189, 183, 107, 1 } }, { "darkmagenta", { 139, 0, 139, 1 } }, + { "darkolivegreen", { 85, 107, 47, 1 } }, { "darkorange", { 255, 140, 0, 1 } }, + { "darkorchid", { 153, 50, 204, 1 } }, { "darkred", { 139, 0, 0, 1 } }, + { "darksalmon", { 233, 150, 122, 1 } }, { "darkseagreen", { 143, 188, 143, 1 } }, + { "darkslateblue", { 72, 61, 139, 1 } }, { "darkslategray", { 47, 79, 79, 1 } }, + { "darkslategrey", { 47, 79, 79, 1 } }, { "darkturquoise", { 0, 206, 209, 1 } }, + { "darkviolet", { 148, 0, 211, 1 } }, { "deeppink", { 255, 20, 147, 1 } }, + { "deepskyblue", { 0, 191, 255, 1 } }, { "dimgray", { 105, 105, 105, 1 } }, + { "dimgrey", { 105, 105, 105, 1 } }, { "dodgerblue", { 30, 144, 255, 1 } }, + { "firebrick", { 178, 34, 34, 1 } }, { "floralwhite", { 255, 250, 240, 1 } }, + { "forestgreen", { 34, 139, 34, 1 } }, { "fuchsia", { 255, 0, 255, 1 } }, + { "gainsboro", { 220, 220, 220, 1 } }, { "ghostwhite", { 248, 248, 255, 1 } }, + { "gold", { 255, 215, 0, 1 } }, { "goldenrod", { 218, 165, 32, 1 } }, + { "gray", { 128, 128, 128, 1 } }, { "green", { 0, 128, 0, 1 } }, + { "greenyellow", { 173, 255, 47, 1 } }, { "grey", { 128, 128, 128, 1 } }, + { "honeydew", { 240, 255, 240, 1 } }, { "hotpink", { 255, 105, 180, 1 } }, + { "indianred", { 205, 92, 92, 1 } }, { "indigo", { 75, 0, 130, 1 } }, + { "ivory", { 255, 255, 240, 1 } }, { "khaki", { 240, 230, 140, 1 } }, + { "lavender", { 230, 230, 250, 1 } }, { "lavenderblush", { 255, 240, 245, 1 } }, + { "lawngreen", { 124, 252, 0, 1 } }, { "lemonchiffon", { 255, 250, 205, 1 } }, + { "lightblue", { 173, 216, 230, 1 } }, { "lightcoral", { 240, 128, 128, 1 } }, + { "lightcyan", { 224, 255, 255, 1 } }, { "lightgoldenrodyellow", { 250, 250, 210, 1 } }, + { "lightgray", { 211, 211, 211, 1 } }, { "lightgreen", { 144, 238, 144, 1 } }, + { "lightgrey", { 211, 211, 211, 1 } }, { "lightpink", { 255, 182, 193, 1 } }, + { "lightsalmon", { 255, 160, 122, 1 } }, { "lightseagreen", { 32, 178, 170, 1 } }, + { "lightskyblue", { 135, 206, 250, 1 } }, { "lightslategray", { 119, 136, 153, 1 } }, + { "lightslategrey", { 119, 136, 153, 1 } }, { "lightsteelblue", { 176, 196, 222, 1 } }, + { "lightyellow", { 255, 255, 224, 1 } }, { "lime", { 0, 255, 0, 1 } }, + { "limegreen", { 50, 205, 50, 1 } }, { "linen", { 250, 240, 230, 1 } }, + { "magenta", { 255, 0, 255, 1 } }, { "maroon", { 128, 0, 0, 1 } }, + { "mediumaquamarine", { 102, 205, 170, 1 } }, { "mediumblue", { 0, 0, 205, 1 } }, + { "mediumorchid", { 186, 85, 211, 1 } }, { "mediumpurple", { 147, 112, 219, 1 } }, + { "mediumseagreen", { 60, 179, 113, 1 } }, { "mediumslateblue", { 123, 104, 238, 1 } }, + { "mediumspringgreen", { 0, 250, 154, 1 } }, { "mediumturquoise", { 72, 209, 204, 1 } }, + { "mediumvioletred", { 199, 21, 133, 1 } }, { "midnightblue", { 25, 25, 112, 1 } }, + { "mintcream", { 245, 255, 250, 1 } }, { "mistyrose", { 255, 228, 225, 1 } }, + { "moccasin", { 255, 228, 181, 1 } }, { "navajowhite", { 255, 222, 173, 1 } }, + { "navy", { 0, 0, 128, 1 } }, { "oldlace", { 253, 245, 230, 1 } }, + { "olive", { 128, 128, 0, 1 } }, { "olivedrab", { 107, 142, 35, 1 } }, + { "orange", { 255, 165, 0, 1 } }, { "orangered", { 255, 69, 0, 1 } }, + { "orchid", { 218, 112, 214, 1 } }, { "palegoldenrod", { 238, 232, 170, 1 } }, + { "palegreen", { 152, 251, 152, 1 } }, { "paleturquoise", { 175, 238, 238, 1 } }, + { "palevioletred", { 219, 112, 147, 1 } }, { "papayawhip", { 255, 239, 213, 1 } }, + { "peachpuff", { 255, 218, 185, 1 } }, { "peru", { 205, 133, 63, 1 } }, + { "pink", { 255, 192, 203, 1 } }, { "plum", { 221, 160, 221, 1 } }, + { "powderblue", { 176, 224, 230, 1 } }, { "purple", { 128, 0, 128, 1 } }, + { "red", { 255, 0, 0, 1 } }, { "rosybrown", { 188, 143, 143, 1 } }, + { "royalblue", { 65, 105, 225, 1 } }, { "saddlebrown", { 139, 69, 19, 1 } }, + { "salmon", { 250, 128, 114, 1 } }, { "sandybrown", { 244, 164, 96, 1 } }, + { "seagreen", { 46, 139, 87, 1 } }, { "seashell", { 255, 245, 238, 1 } }, + { "sienna", { 160, 82, 45, 1 } }, { "silver", { 192, 192, 192, 1 } }, + { "skyblue", { 135, 206, 235, 1 } }, { "slateblue", { 106, 90, 205, 1 } }, + { "slategray", { 112, 128, 144, 1 } }, { "slategrey", { 112, 128, 144, 1 } }, + { "snow", { 255, 250, 250, 1 } }, { "springgreen", { 0, 255, 127, 1 } }, + { "steelblue", { 70, 130, 180, 1 } }, { "tan", { 210, 180, 140, 1 } }, + { "teal", { 0, 128, 128, 1 } }, { "thistle", { 216, 191, 216, 1 } }, + { "tomato", { 255, 99, 71, 1 } }, { "turquoise", { 64, 224, 208, 1 } }, + { "violet", { 238, 130, 238, 1 } }, { "wheat", { 245, 222, 179, 1 } }, + { "white", { 255, 255, 255, 1 } }, { "whitesmoke", { 245, 245, 245, 1 } }, + { "yellow", { 255, 255, 0, 1 } }, { "yellowgreen", { 154, 205, 50, 1 } } +}; + +const size_t namedColorCount = sizeof (namedColors) / sizeof (NamedColor); + + +template +uint8_t clamp_css_byte(T i) { // Clamp to integer 0 .. 255. + i = ::round(i); // Seems to be what Chrome does (vs truncation). + return i < 0 ? 0 : i > 255 ? 255 : i; +} + +template +float clamp_css_float(T f) { // Clamp to float 0.0 .. 1.0. + return f < 0 ? 0 : f > 1 ? 1 : f; +} + +float parseFloat(const std::string& str) { + return strtof(str.c_str(), nullptr); +} + +int64_t parseInt(const std::string& str, uint8_t base = 10) { + return strtoll(str.c_str(), nullptr, base); +} + +uint8_t parse_css_int(const std::string& str) { // int or percentage. + if (str.length() && str.back() == '%') { + return clamp_css_byte(parseFloat(str) / 100.0f * 255.0f); + } else { + return clamp_css_byte(parseInt(str)); + } +} + +float parse_css_float(const std::string& str) { // float or percentage. + if (str.length() && str.back() == '%') { + return clamp_css_float(parseFloat(str) / 100.0f); + } else { + return clamp_css_float(parseFloat(str)); + } +} + +float css_hue_to_rgb(float m1, float m2, float h) { + if (h < 0.0f) { + h += 1.0f; + } else if (h > 1.0f) { + h -= 1.0f; + } + + if (h * 6.0f < 1.0f) { + return m1 + (m2 - m1) * h * 6.0f; + } + if (h * 2.0f < 1.0f) { + return m2; + } + if (h * 3.0f < 2.0f) { + return m1 + (m2 - m1) * (2.0 / 3.0 - h) * 6.0f; + } + return m1; +} + + + +std::vector split(const std::string& s, char delim) { + std::vector elems; + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + elems.push_back(item); + } + return elems; +} + +Color CSSColorParser::parse(const std::string& css_str) { + std::string str = css_str; + + // Remove all whitespace, not compliant, but should just be more accepting. + str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); + + // Convert to lowercase. + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + + + for (size_t i = 0; i < namedColorCount; i++) { + if (str == namedColors[i].name) { + return namedColors[i].color; + } + } + + // #abc and #abc123 syntax. + if (str.length() && str.front() == '#') { + if (str.length() == 4) { + int64_t iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + if (!(iv >= 0 && iv <= 0xfff)) { + return {}; + } else { + return { + static_cast(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)), + static_cast((iv & 0xf0) | ((iv & 0xf0) >> 4)), + static_cast((iv & 0xf) | ((iv & 0xf) << 4)), + 1 + }; + } + } else if (str.length() == 7) { + int64_t iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + if (!(iv >= 0 && iv <= 0xffffff)) { + return {}; // Covers NaN. + } else { + return { + static_cast((iv & 0xff0000) >> 16), + static_cast((iv & 0xff00) >> 8), + static_cast(iv & 0xff), + 1 + }; + } + } + + return {}; + } + + size_t op = str.find_first_of('('), ep = str.find_first_of(')'); + if (op != std::string::npos && ep + 1 == str.length()) { + const std::string fname = str.substr(0, op); + const std::vector params = split(str.substr(op + 1, ep - (op + 1)), ','); + + float alpha = 1.0f; + + if (fname == "rgba" || fname == "rgb") { + if (fname == "rgba") { + if (params.size() != 4) { + return {}; + } + alpha = parse_css_float(params.back()); + } else { + if (params.size() != 3) { + return {}; + } + } + + return { + parse_css_int(params[0]), + parse_css_int(params[1]), + parse_css_int(params[2]), + alpha + }; + + } else if (fname == "hsla" || fname == "hsl") { + if (fname == "hsla") { + if (params.size() != 4) { + return {}; + } + alpha = parse_css_float(params.back()); + } else { + if (params.size() != 3) { + return {}; + } + } + + float h = parseFloat(params[0]) / 360.0f; + while (h < 0.0f) h++; + while (h > 1.0f) h--; + + // NOTE(deanm): According to the CSS spec s/l should only be + // percentages, but we don't bother and let float or percentage. + float s = parse_css_float(params[1]); + float l = parse_css_float(params[2]); + + float m2 = l <= 0.5f ? l * (s + 1.0f) : l + s - l * s; + float m1 = l * 2.0f - m2; + + return { + clamp_css_byte(css_hue_to_rgb(m1, m2, h + 1.0f / 3.0f) * 255.0f), + clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255.0f), + clamp_css_byte(css_hue_to_rgb(m1, m2, h - 1.0f / 3.0f) * 255.0f), + alpha + }; + } + } + + return {}; +} diff --git a/src/csscolorparser/csscolorparser.hpp b/src/csscolorparser/csscolorparser.hpp new file mode 100644 index 000000000..6caf79694 --- /dev/null +++ b/src/csscolorparser/csscolorparser.hpp @@ -0,0 +1,44 @@ +// (c) Dean McNamee , 2012. +// C++ port by Konstantin Käfer , 2014. +// +// https://github.com/deanm/css-color-parser-js +// https://github.com/kkaefer/css-color-parser-cpp +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef CSS_COLOR_PARSER_CPP +#define CSS_COLOR_PARSER_CPP + +#include + +namespace CSSColorParser { + +struct Color { + inline Color() {} + inline Color(unsigned char r_, unsigned char g_, unsigned char b_, float a_) + : r(r_), g(g_), b(b_), a(a_) {} + unsigned char r = 0, g = 0, b = 0; + float a = 1.0f; +}; + +Color parse(const std::string& css_str); + +} + +#endif diff --git a/src/libtess2/LICENSE.txt b/src/libtess2/LICENSE.txt new file mode 100644 index 000000000..30133655c --- /dev/null +++ b/src/libtess2/LICENSE.txt @@ -0,0 +1,25 @@ +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. diff --git a/src/libtess2/bucketalloc.c b/src/libtess2/bucketalloc.c new file mode 100755 index 000000000..efb2b9813 --- /dev/null +++ b/src/libtess2/bucketalloc.c @@ -0,0 +1,199 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Mikko Mononen, July 2009. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "tesselator.h" + +//#define CHECK_BOUNDS + +typedef struct BucketAlloc BucketAlloc; +typedef struct Bucket Bucket; + +struct Bucket +{ + Bucket *next; +}; + +struct BucketAlloc +{ + void *freelist; + Bucket *buckets; + unsigned int itemSize; + unsigned int bucketSize; + const char *name; + TESSalloc* alloc; +}; + +static int CreateBucket( struct BucketAlloc* ba ) +{ + unsigned int size; + Bucket* bucket; + void* freelist; + unsigned char* head; + unsigned char* it; + + // Allocate memory for the bucket + size = sizeof(Bucket) + ba->itemSize * ba->bucketSize; + bucket = (Bucket*)ba->alloc->memalloc( ba->alloc->userData, size ); + if ( !bucket ) + return 0; + bucket->next = 0; + + // Add the bucket into the list of buckets. + bucket->next = ba->buckets; + ba->buckets = bucket; + + // Add new items to the free list. + freelist = ba->freelist; + head = (unsigned char*)bucket + sizeof(Bucket); + it = head + ba->itemSize * ba->bucketSize; + do + { + it -= ba->itemSize; + // Store pointer to next free item. + *((void**)it) = freelist; + // Pointer to next location containing a free item. + freelist = (void*)it; + } + while ( it != head ); + // Update pointer to next location containing a free item. + ba->freelist = (void*)it; + + return 1; +} + +static void *NextFreeItem( struct BucketAlloc *ba ) +{ + return *(void**)ba->freelist; +} + +struct BucketAlloc* createBucketAlloc( TESSalloc* alloc, const char* name, + unsigned int itemSize, unsigned int bucketSize ) +{ + BucketAlloc* ba = (BucketAlloc*)alloc->memalloc( alloc->userData, sizeof(BucketAlloc) ); + + ba->alloc = alloc; + ba->name = name; + ba->itemSize = itemSize; + if ( ba->itemSize < sizeof(void*) ) + ba->itemSize = sizeof(void*); + ba->bucketSize = bucketSize; + ba->freelist = 0; + ba->buckets = 0; + + if ( !CreateBucket( ba ) ) + { + alloc->memfree( alloc->userData, ba ); + return 0; + } + + return ba; +} + +void* bucketAlloc( struct BucketAlloc *ba ) +{ + void *it; + + // If running out of memory, allocate new bucket and update the freelist. + if ( !ba->freelist || !NextFreeItem( ba ) ) + { + if ( !CreateBucket( ba ) ) + return 0; + } + + // Pop item from in front of the free list. + it = ba->freelist; + ba->freelist = NextFreeItem( ba ); + + return it; +} + +void bucketFree( struct BucketAlloc *ba, void *ptr ) +{ +#ifdef CHECK_BOUNDS + int inBounds = 0; + Bucket *bucket; + + // Check that the pointer is allocated with this allocator. + bucket = ba->buckets; + while ( bucket ) + { + void *bucketMin = (void*)((unsigned char*)bucket + sizeof(Bucket)); + void *bucketMax = (void*)((unsigned char*)bucket + sizeof(Bucket) + ba->itemSize * ba->bucketSize); + if ( ptr >= bucketMin && ptr < bucketMax ) + { + inBounds = 1; + break; + } + bucket = bucket->next; + } + + if ( inBounds ) + { + // Add the node in front of the free list. + *(void**)ptr = ba->freelist; + ba->freelist = ptr; + } + else + { + printf("ERROR! pointer 0x%p does not belong to allocator '%s'\n", ba->name); + } +#else + // Add the node in front of the free list. + *(void**)ptr = ba->freelist; + ba->freelist = ptr; +#endif +} + +void deleteBucketAlloc( struct BucketAlloc *ba ) +{ + TESSalloc* alloc = ba->alloc; + Bucket *bucket = ba->buckets; + Bucket *next; + while ( bucket ) + { + next = bucket->next; + alloc->memfree( alloc->userData, bucket ); + bucket = next; + } + ba->freelist = 0; + ba->buckets = 0; + alloc->memfree( alloc->userData, ba ); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/libtess2/bucketalloc.h b/src/libtess2/bucketalloc.h new file mode 100755 index 000000000..077d76813 --- /dev/null +++ b/src/libtess2/bucketalloc.h @@ -0,0 +1,51 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Mikko Mononen, July 2009. +*/ + +#ifndef MEMALLOC_H +#define MEMALLOC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "tesselator.h" + +struct BucketAlloc *createBucketAlloc( TESSalloc* alloc, const char *name, + unsigned int itemSize, unsigned int bucketSize ); +void *bucketAlloc( struct BucketAlloc *ba); +void bucketFree( struct BucketAlloc *ba, void *ptr ); +void deleteBucketAlloc( struct BucketAlloc *ba ); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/src/libtess2/dict.c b/src/libtess2/dict.c new file mode 100755 index 000000000..dd7bade2c --- /dev/null +++ b/src/libtess2/dict.c @@ -0,0 +1,109 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +#include +#include "tesselator.h" +#include "bucketalloc.h" +#include "dict.h" + +/* really tessDictListNewDict */ +Dict *dictNewDict( TESSalloc* alloc, void *frame, int (*leq)(void *frame, DictKey key1, DictKey key2) ) +{ + Dict *dict = (Dict *)alloc->memalloc( alloc->userData, sizeof( Dict )); + DictNode *head; + + if (dict == NULL) return NULL; + + head = &dict->head; + + head->key = NULL; + head->next = head; + head->prev = head; + + dict->frame = frame; + dict->leq = leq; + + if (alloc->dictNodeBucketSize < 16) + alloc->dictNodeBucketSize = 16; + if (alloc->dictNodeBucketSize > 4096) + alloc->dictNodeBucketSize = 4096; + dict->nodePool = createBucketAlloc( alloc, "Dict", sizeof(DictNode), alloc->dictNodeBucketSize ); + + return dict; +} + +/* really tessDictListDeleteDict */ +void dictDeleteDict( TESSalloc* alloc, Dict *dict ) +{ + deleteBucketAlloc( dict->nodePool ); + alloc->memfree( alloc->userData, dict ); +} + +/* really tessDictListInsertBefore */ +DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ) +{ + DictNode *newNode; + + do { + node = node->prev; + } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key)); + + newNode = (DictNode *)bucketAlloc( dict->nodePool ); + if (newNode == NULL) return NULL; + + newNode->key = key; + newNode->next = node->next; + node->next->prev = newNode; + newNode->prev = node; + node->next = newNode; + + return newNode; +} + +/* really tessDictListDelete */ +void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/ +{ + node->next->prev = node->prev; + node->prev->next = node->next; + bucketFree( dict->nodePool, node ); +} + +/* really tessDictListSearch */ +DictNode *dictSearch( Dict *dict, DictKey key ) +{ + DictNode *node = &dict->head; + + do { + node = node->next; + } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key)); + + return node; +} diff --git a/src/libtess2/dict.h b/src/libtess2/dict.h new file mode 100755 index 000000000..2f4df9945 --- /dev/null +++ b/src/libtess2/dict.h @@ -0,0 +1,74 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +#ifndef DICT_LIST_H +#define DICT_LIST_H + +typedef void *DictKey; +typedef struct Dict Dict; +typedef struct DictNode DictNode; + +Dict *dictNewDict( TESSalloc* alloc, void *frame, int (*leq)(void *frame, DictKey key1, DictKey key2) ); + +void dictDeleteDict( TESSalloc* alloc, Dict *dict ); + +/* Search returns the node with the smallest key greater than or equal +* to the given key. If there is no such key, returns a node whose +* key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc. +*/ +DictNode *dictSearch( Dict *dict, DictKey key ); +DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); +void dictDelete( Dict *dict, DictNode *node ); + +#define dictKey(n) ((n)->key) +#define dictSucc(n) ((n)->next) +#define dictPred(n) ((n)->prev) +#define dictMin(d) ((d)->head.next) +#define dictMax(d) ((d)->head.prev) +#define dictInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) + + +/*** Private data structures ***/ + +struct DictNode { + DictKey key; + DictNode *next; + DictNode *prev; +}; + +struct Dict { + DictNode head; + void *frame; + struct BucketAlloc *nodePool; + int (*leq)(void *frame, DictKey key1, DictKey key2); +}; + +#endif diff --git a/src/libtess2/geom.c b/src/libtess2/geom.c new file mode 100755 index 000000000..44cf38c1d --- /dev/null +++ b/src/libtess2/geom.c @@ -0,0 +1,261 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +//#include "tesos.h" +#include +#include "mesh.h" +#include "geom.h" + +int tesvertLeq( TESSvertex *u, TESSvertex *v ) +{ + /* Returns TRUE if u is lexicographically <= v. */ + + return VertLeq( u, v ); +} + +TESSreal tesedgeEval( TESSvertex *u, TESSvertex *v, TESSvertex *w ) +{ + /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w), + * evaluates the t-coord of the edge uw at the s-coord of the vertex v. + * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v. + * If uw is vertical (and thus passes thru v), the result is zero. + * + * The calculation is extremely accurate and stable, even when v + * is very close to u or w. In particular if we set v->t = 0 and + * let r be the negated result (this evaluates (uw)(v->s)), then + * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t). + */ + TESSreal gapL, gapR; + + assert( VertLeq( u, v ) && VertLeq( v, w )); + + gapL = v->s - u->s; + gapR = w->s - v->s; + + if( gapL + gapR > 0 ) { + if( gapL < gapR ) { + return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR)); + } else { + return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR)); + } + } + /* vertical line */ + return 0; +} + +TESSreal tesedgeSign( TESSvertex *u, TESSvertex *v, TESSvertex *w ) +{ + /* Returns a number whose sign matches EdgeEval(u,v,w) but which + * is cheaper to evaluate. Returns > 0, == 0 , or < 0 + * as v is above, on, or below the edge uw. + */ + TESSreal gapL, gapR; + + assert( VertLeq( u, v ) && VertLeq( v, w )); + + gapL = v->s - u->s; + gapR = w->s - v->s; + + if( gapL + gapR > 0 ) { + return (v->t - w->t) * gapL + (v->t - u->t) * gapR; + } + /* vertical line */ + return 0; +} + + +/*********************************************************************** +* Define versions of EdgeSign, EdgeEval with s and t transposed. +*/ + +TESSreal testransEval( TESSvertex *u, TESSvertex *v, TESSvertex *w ) +{ + /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w), + * evaluates the t-coord of the edge uw at the s-coord of the vertex v. + * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v. + * If uw is vertical (and thus passes thru v), the result is zero. + * + * The calculation is extremely accurate and stable, even when v + * is very close to u or w. In particular if we set v->s = 0 and + * let r be the negated result (this evaluates (uw)(v->t)), then + * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s). + */ + TESSreal gapL, gapR; + + assert( TransLeq( u, v ) && TransLeq( v, w )); + + gapL = v->t - u->t; + gapR = w->t - v->t; + + if( gapL + gapR > 0 ) { + if( gapL < gapR ) { + return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR)); + } else { + return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR)); + } + } + /* vertical line */ + return 0; +} + +TESSreal testransSign( TESSvertex *u, TESSvertex *v, TESSvertex *w ) +{ + /* Returns a number whose sign matches TransEval(u,v,w) but which + * is cheaper to evaluate. Returns > 0, == 0 , or < 0 + * as v is above, on, or below the edge uw. + */ + TESSreal gapL, gapR; + + assert( TransLeq( u, v ) && TransLeq( v, w )); + + gapL = v->t - u->t; + gapR = w->t - v->t; + + if( gapL + gapR > 0 ) { + return (v->s - w->s) * gapL + (v->s - u->s) * gapR; + } + /* vertical line */ + return 0; +} + + +int tesvertCCW( TESSvertex *u, TESSvertex *v, TESSvertex *w ) +{ + /* For almost-degenerate situations, the results are not reliable. + * Unless the floating-point arithmetic can be performed without + * rounding errors, *any* implementation will give incorrect results + * on some degenerate inputs, so the client must have some way to + * handle this situation. + */ + return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0; +} + +/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b), +* or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces +* this in the rare case that one argument is slightly negative. +* The implementation is extremely stable numerically. +* In particular it guarantees that the result r satisfies +* MIN(x,y) <= r <= MAX(x,y), and the results are very accurate +* even when a and b differ greatly in magnitude. +*/ +#define RealInterpolate(a,x,b,y) \ + (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \ + ((a <= b) ? ((b == 0) ? ((x+y) / 2) \ + : (x + (y-x) * (a/(a+b)))) \ + : (y + (x-y) * (b/(a+b))))) + +#ifndef FOR_TRITE_TEST_PROGRAM +#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y) +#else + +/* Claim: the ONLY property the sweep algorithm relies on is that +* MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that. +*/ +#include +extern int RandomInterpolate; + +double Interpolate( double a, double x, double b, double y) +{ + printf("*********************%d\n",RandomInterpolate); + if( RandomInterpolate ) { + a = 1.2 * drand48() - 0.1; + a = (a < 0) ? 0 : ((a > 1) ? 1 : a); + b = 1.0 - a; + } + return RealInterpolate(a,x,b,y); +} + +#endif + +#define Swap(a,b) if (1) { TESSvertex *t = a; a = b; b = t; } else + +void tesedgeIntersect( TESSvertex *o1, TESSvertex *d1, + TESSvertex *o2, TESSvertex *d2, + TESSvertex *v ) + /* Given edges (o1,d1) and (o2,d2), compute their point of intersection. + * The computed point is guaranteed to lie in the intersection of the + * bounding rectangles defined by each edge. + */ +{ + TESSreal z1, z2; + + /* This is certainly not the most efficient way to find the intersection + * of two line segments, but it is very numerically stable. + * + * Strategy: find the two middle vertices in the VertLeq ordering, + * and interpolate the intersection s-value from these. Then repeat + * using the TransLeq ordering to find the intersection t-value. + */ + + if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); } + if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); } + if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } + + if( ! VertLeq( o2, d1 )) { + /* Technically, no intersection -- do our best */ + v->s = (o2->s + d1->s) / 2; + } else if( VertLeq( d1, d2 )) { + /* Interpolate between o2 and d1 */ + z1 = EdgeEval( o1, o2, d1 ); + z2 = EdgeEval( o2, d1, d2 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->s = Interpolate( z1, o2->s, z2, d1->s ); + } else { + /* Interpolate between o2 and d2 */ + z1 = EdgeSign( o1, o2, d1 ); + z2 = -EdgeSign( o1, d2, d1 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->s = Interpolate( z1, o2->s, z2, d2->s ); + } + + /* Now repeat the process for t */ + + if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); } + if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); } + if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } + + if( ! TransLeq( o2, d1 )) { + /* Technically, no intersection -- do our best */ + v->t = (o2->t + d1->t) / 2; + } else if( TransLeq( d1, d2 )) { + /* Interpolate between o2 and d1 */ + z1 = TransEval( o1, o2, d1 ); + z2 = TransEval( o2, d1, d2 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->t = Interpolate( z1, o2->t, z2, d1->t ); + } else { + /* Interpolate between o2 and d2 */ + z1 = TransSign( o1, o2, d1 ); + z2 = -TransSign( o1, d2, d1 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->t = Interpolate( z1, o2->t, z2, d2->t ); + } +} diff --git a/src/libtess2/geom.h b/src/libtess2/geom.h new file mode 100755 index 000000000..6aca5734d --- /dev/null +++ b/src/libtess2/geom.h @@ -0,0 +1,76 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +#ifndef GEOM_H +#define GEOM_H + +#include "mesh.h" + +#ifdef NO_BRANCH_CONDITIONS +/* MIPS architecture has special instructions to evaluate boolean +* conditions -- more efficient than branching, IF you can get the +* compiler to generate the right instructions (SGI compiler doesn't) +*/ +#define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t)) +#define VertLeq(u,v) (((u)->s < (v)->s) | \ + ((u)->s == (v)->s & (u)->t <= (v)->t)) +#else +#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t) +#define VertLeq(u,v) (((u)->s < (v)->s) || ((u)->s == (v)->s && (u)->t <= (v)->t)) +#endif + +#define EdgeEval(u,v,w) tesedgeEval(u,v,w) +#define EdgeSign(u,v,w) tesedgeSign(u,v,w) + +/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */ + +#define TransLeq(u,v) (((u)->t < (v)->t) || ((u)->t == (v)->t && (u)->s <= (v)->s)) +#define TransEval(u,v,w) testransEval(u,v,w) +#define TransSign(u,v,w) testransSign(u,v,w) + + +#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org ) +#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst ) + +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t)) + +#define VertCCW(u,v,w) tesvertCCW(u,v,w) + +int tesvertLeq( TESSvertex *u, TESSvertex *v ); +TESSreal tesedgeEval( TESSvertex *u, TESSvertex *v, TESSvertex *w ); +TESSreal tesedgeSign( TESSvertex *u, TESSvertex *v, TESSvertex *w ); +TESSreal testransEval( TESSvertex *u, TESSvertex *v, TESSvertex *w ); +TESSreal testransSign( TESSvertex *u, TESSvertex *v, TESSvertex *w ); +int tesvertCCW( TESSvertex *u, TESSvertex *v, TESSvertex *w ); +void tesedgeIntersect( TESSvertex *o1, TESSvertex *d1, TESSvertex *o2, TESSvertex *d2, TESSvertex *v ); + +#endif diff --git a/src/libtess2/mesh.c b/src/libtess2/mesh.c new file mode 100755 index 000000000..3eb4ad20a --- /dev/null +++ b/src/libtess2/mesh.c @@ -0,0 +1,844 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +//#include "tesos.h" +#include +#include +#include "mesh.h" +#include "geom.h" +#include "bucketalloc.h" + +#define TRUE 1 +#define FALSE 0 + +/************************ Utility Routines ************************/ + +/* Allocate and free half-edges in pairs for efficiency. +* The *only* place that should use this fact is allocation/free. +*/ +typedef struct { TESShalfEdge e, eSym; } EdgePair; + +/* MakeEdge creates a new pair of half-edges which form their own loop. +* No vertex or face structures are allocated, but these must be assigned +* before the current edge operation is completed. +*/ +static TESShalfEdge *MakeEdge( TESSmesh* mesh, TESShalfEdge *eNext ) +{ + TESShalfEdge *e; + TESShalfEdge *eSym; + TESShalfEdge *ePrev; + EdgePair *pair = (EdgePair *)bucketAlloc( mesh->edgeBucket ); + if (pair == NULL) return NULL; + + e = &pair->e; + eSym = &pair->eSym; + + /* Make sure eNext points to the first edge of the edge pair */ + if( eNext->Sym < eNext ) { eNext = eNext->Sym; } + + /* Insert in circular doubly-linked list before eNext. + * Note that the prev pointer is stored in Sym->next. + */ + ePrev = eNext->Sym->next; + eSym->next = ePrev; + ePrev->Sym->next = e; + e->next = eNext; + eNext->Sym->next = eSym; + + e->Sym = eSym; + e->Onext = e; + e->Lnext = eSym; + e->Org = NULL; + e->Lface = NULL; + e->winding = 0; + e->activeRegion = NULL; + + eSym->Sym = e; + eSym->Onext = eSym; + eSym->Lnext = e; + eSym->Org = NULL; + eSym->Lface = NULL; + eSym->winding = 0; + eSym->activeRegion = NULL; + + return e; +} + +/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the +* CS348a notes (see mesh.h). Basically it modifies the mesh so that +* a->Onext and b->Onext are exchanged. This can have various effects +* depending on whether a and b belong to different face or vertex rings. +* For more explanation see tessMeshSplice() below. +*/ +static void Splice( TESShalfEdge *a, TESShalfEdge *b ) +{ + TESShalfEdge *aOnext = a->Onext; + TESShalfEdge *bOnext = b->Onext; + + aOnext->Sym->Lnext = b; + bOnext->Sym->Lnext = a; + a->Onext = bOnext; + b->Onext = aOnext; +} + +/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the +* origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives +* a place to insert the new vertex in the global vertex list. We insert +* the new vertex *before* vNext so that algorithms which walk the vertex +* list will not see the newly created vertices. +*/ +static void MakeVertex( TESSvertex *newVertex, + TESShalfEdge *eOrig, TESSvertex *vNext ) +{ + TESShalfEdge *e; + TESSvertex *vPrev; + TESSvertex *vNew = newVertex; + + assert(vNew != NULL); + + /* insert in circular doubly-linked list before vNext */ + vPrev = vNext->prev; + vNew->prev = vPrev; + vPrev->next = vNew; + vNew->next = vNext; + vNext->prev = vNew; + + vNew->anEdge = eOrig; + /* leave coords, s, t undefined */ + + /* fix other edges on this vertex loop */ + e = eOrig; + do { + e->Org = vNew; + e = e->Onext; + } while( e != eOrig ); +} + +/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left +* face of all edges in the face loop to which eOrig belongs. "fNext" gives +* a place to insert the new face in the global face list. We insert +* the new face *before* fNext so that algorithms which walk the face +* list will not see the newly created faces. +*/ +static void MakeFace( TESSface *newFace, TESShalfEdge *eOrig, TESSface *fNext ) +{ + TESShalfEdge *e; + TESSface *fPrev; + TESSface *fNew = newFace; + + assert(fNew != NULL); + + /* insert in circular doubly-linked list before fNext */ + fPrev = fNext->prev; + fNew->prev = fPrev; + fPrev->next = fNew; + fNew->next = fNext; + fNext->prev = fNew; + + fNew->anEdge = eOrig; + fNew->trail = NULL; + fNew->marked = FALSE; + + /* The new face is marked "inside" if the old one was. This is a + * convenience for the common case where a face has been split in two. + */ + fNew->inside = fNext->inside; + + /* fix other edges on this face loop */ + e = eOrig; + do { + e->Lface = fNew; + e = e->Lnext; + } while( e != eOrig ); +} + +/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym), +* and removes from the global edge list. +*/ +static void KillEdge( TESSmesh *mesh, TESShalfEdge *eDel ) +{ + TESShalfEdge *ePrev, *eNext; + + /* Half-edges are allocated in pairs, see EdgePair above */ + if( eDel->Sym < eDel ) { eDel = eDel->Sym; } + + /* delete from circular doubly-linked list */ + eNext = eDel->next; + ePrev = eDel->Sym->next; + eNext->Sym->next = ePrev; + ePrev->Sym->next = eNext; + + bucketFree( mesh->edgeBucket, eDel ); +} + + +/* KillVertex( vDel ) destroys a vertex and removes it from the global +* vertex list. It updates the vertex loop to point to a given new vertex. +*/ +static void KillVertex( TESSmesh *mesh, TESSvertex *vDel, TESSvertex *newOrg ) +{ + TESShalfEdge *e, *eStart = vDel->anEdge; + TESSvertex *vPrev, *vNext; + + /* change the origin of all affected edges */ + e = eStart; + do { + e->Org = newOrg; + e = e->Onext; + } while( e != eStart ); + + /* delete from circular doubly-linked list */ + vPrev = vDel->prev; + vNext = vDel->next; + vNext->prev = vPrev; + vPrev->next = vNext; + + bucketFree( mesh->vertexBucket, vDel ); +} + +/* KillFace( fDel ) destroys a face and removes it from the global face +* list. It updates the face loop to point to a given new face. +*/ +static void KillFace( TESSmesh *mesh, TESSface *fDel, TESSface *newLface ) +{ + TESShalfEdge *e, *eStart = fDel->anEdge; + TESSface *fPrev, *fNext; + + /* change the left face of all affected edges */ + e = eStart; + do { + e->Lface = newLface; + e = e->Lnext; + } while( e != eStart ); + + /* delete from circular doubly-linked list */ + fPrev = fDel->prev; + fNext = fDel->next; + fNext->prev = fPrev; + fPrev->next = fNext; + + bucketFree( mesh->faceBucket, fDel ); +} + + +/****************** Basic Edge Operations **********************/ + +/* tessMeshMakeEdge creates one edge, two vertices, and a loop (face). +* The loop consists of the two new half-edges. +*/ +TESShalfEdge *tessMeshMakeEdge( TESSmesh *mesh ) +{ + TESSvertex *newVertex1 = (TESSvertex*)bucketAlloc(mesh->vertexBucket); + TESSvertex *newVertex2 = (TESSvertex*)bucketAlloc(mesh->vertexBucket); + TESSface *newFace = (TESSface*)bucketAlloc(mesh->faceBucket); + TESShalfEdge *e; + + /* if any one is null then all get freed */ + if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) { + if (newVertex1 != NULL) bucketFree( mesh->vertexBucket, newVertex1 ); + if (newVertex2 != NULL) bucketFree( mesh->vertexBucket, newVertex2 ); + if (newFace != NULL) bucketFree( mesh->faceBucket, newFace ); + return NULL; + } + + e = MakeEdge( mesh, &mesh->eHead ); + if (e == NULL) return NULL; + + MakeVertex( newVertex1, e, &mesh->vHead ); + MakeVertex( newVertex2, e->Sym, &mesh->vHead ); + MakeFace( newFace, e, &mesh->fHead ); + return e; +} + + +/* tessMeshSplice( eOrg, eDst ) is the basic operation for changing the +* mesh connectivity and topology. It changes the mesh so that +* eOrg->Onext <- OLD( eDst->Onext ) +* eDst->Onext <- OLD( eOrg->Onext ) +* where OLD(...) means the value before the meshSplice operation. +* +* This can have two effects on the vertex structure: +* - if eOrg->Org != eDst->Org, the two vertices are merged together +* - if eOrg->Org == eDst->Org, the origin is split into two vertices +* In both cases, eDst->Org is changed and eOrg->Org is untouched. +* +* Similarly (and independently) for the face structure, +* - if eOrg->Lface == eDst->Lface, one loop is split into two +* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one +* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. +* +* Some special cases: +* If eDst == eOrg, the operation has no effect. +* If eDst == eOrg->Lnext, the new face will have a single edge. +* If eDst == eOrg->Lprev, the old face will have a single edge. +* If eDst == eOrg->Onext, the new vertex will have a single edge. +* If eDst == eOrg->Oprev, the old vertex will have a single edge. +*/ +int tessMeshSplice( TESSmesh* mesh, TESShalfEdge *eOrg, TESShalfEdge *eDst ) +{ + int joiningLoops = FALSE; + int joiningVertices = FALSE; + + if( eOrg == eDst ) return 1; + + if( eDst->Org != eOrg->Org ) { + /* We are merging two disjoint vertices -- destroy eDst->Org */ + joiningVertices = TRUE; + KillVertex( mesh, eDst->Org, eOrg->Org ); + } + if( eDst->Lface != eOrg->Lface ) { + /* We are connecting two disjoint loops -- destroy eDst->Lface */ + joiningLoops = TRUE; + KillFace( mesh, eDst->Lface, eOrg->Lface ); + } + + /* Change the edge structure */ + Splice( eDst, eOrg ); + + if( ! joiningVertices ) { + TESSvertex *newVertex = (TESSvertex*)bucketAlloc( mesh->vertexBucket ); + if (newVertex == NULL) return 0; + + /* We split one vertex into two -- the new vertex is eDst->Org. + * Make sure the old vertex points to a valid half-edge. + */ + MakeVertex( newVertex, eDst, eOrg->Org ); + eOrg->Org->anEdge = eOrg; + } + if( ! joiningLoops ) { + TESSface *newFace = (TESSface*)bucketAlloc( mesh->faceBucket ); + if (newFace == NULL) return 0; + + /* We split one loop into two -- the new loop is eDst->Lface. + * Make sure the old face points to a valid half-edge. + */ + MakeFace( newFace, eDst, eOrg->Lface ); + eOrg->Lface->anEdge = eOrg; + } + + return 1; +} + + +/* tessMeshDelete( eDel ) removes the edge eDel. There are several cases: +* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop +* eDel->Lface is deleted. Otherwise, we are splitting one loop into two; +* the newly created loop will contain eDel->Dst. If the deletion of eDel +* would create isolated vertices, those are deleted as well. +* +* This function could be implemented as two calls to tessMeshSplice +* plus a few calls to memFree, but this would allocate and delete +* unnecessary vertices and faces. +*/ +int tessMeshDelete( TESSmesh *mesh, TESShalfEdge *eDel ) +{ + TESShalfEdge *eDelSym = eDel->Sym; + int joiningLoops = FALSE; + + /* First step: disconnect the origin vertex eDel->Org. We make all + * changes to get a consistent mesh in this "intermediate" state. + */ + if( eDel->Lface != eDel->Rface ) { + /* We are joining two loops into one -- remove the left face */ + joiningLoops = TRUE; + KillFace( mesh, eDel->Lface, eDel->Rface ); + } + + if( eDel->Onext == eDel ) { + KillVertex( mesh, eDel->Org, NULL ); + } else { + /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */ + eDel->Rface->anEdge = eDel->Oprev; + eDel->Org->anEdge = eDel->Onext; + + Splice( eDel, eDel->Oprev ); + if( ! joiningLoops ) { + TESSface *newFace= (TESSface*)bucketAlloc( mesh->faceBucket ); + if (newFace == NULL) return 0; + + /* We are splitting one loop into two -- create a new loop for eDel. */ + MakeFace( newFace, eDel, eDel->Lface ); + } + } + + /* Claim: the mesh is now in a consistent state, except that eDel->Org + * may have been deleted. Now we disconnect eDel->Dst. + */ + if( eDelSym->Onext == eDelSym ) { + KillVertex( mesh, eDelSym->Org, NULL ); + KillFace( mesh, eDelSym->Lface, NULL ); + } else { + /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */ + eDel->Lface->anEdge = eDelSym->Oprev; + eDelSym->Org->anEdge = eDelSym->Onext; + Splice( eDelSym, eDelSym->Oprev ); + } + + /* Any isolated vertices or faces have already been freed. */ + KillEdge( mesh, eDel ); + + return 1; +} + + +/******************** Other Edge Operations **********************/ + +/* All these routines can be implemented with the basic edge +* operations above. They are provided for convenience and efficiency. +*/ + + +/* tessMeshAddEdgeVertex( eOrg ) creates a new edge eNew such that +* eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. +* eOrg and eNew will have the same left face. +*/ +TESShalfEdge *tessMeshAddEdgeVertex( TESSmesh *mesh, TESShalfEdge *eOrg ) +{ + TESShalfEdge *eNewSym; + TESShalfEdge *eNew = MakeEdge( mesh, eOrg ); + if (eNew == NULL) return NULL; + + eNewSym = eNew->Sym; + + /* Connect the new edge appropriately */ + Splice( eNew, eOrg->Lnext ); + + /* Set the vertex and face information */ + eNew->Org = eOrg->Dst; + { + TESSvertex *newVertex= (TESSvertex*)bucketAlloc( mesh->vertexBucket ); + if (newVertex == NULL) return NULL; + + MakeVertex( newVertex, eNewSym, eNew->Org ); + } + eNew->Lface = eNewSym->Lface = eOrg->Lface; + + return eNew; +} + + +/* tessMeshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, +* such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org. +* eOrg and eNew will have the same left face. +*/ +TESShalfEdge *tessMeshSplitEdge( TESSmesh *mesh, TESShalfEdge *eOrg ) +{ + TESShalfEdge *eNew; + TESShalfEdge *tempHalfEdge= tessMeshAddEdgeVertex( mesh, eOrg ); + if (tempHalfEdge == NULL) return NULL; + + eNew = tempHalfEdge->Sym; + + /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */ + Splice( eOrg->Sym, eOrg->Sym->Oprev ); + Splice( eOrg->Sym, eNew ); + + /* Set the vertex and face information */ + eOrg->Dst = eNew->Org; + eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */ + eNew->Rface = eOrg->Rface; + eNew->winding = eOrg->winding; /* copy old winding information */ + eNew->Sym->winding = eOrg->Sym->winding; + + return eNew; +} + + +/* tessMeshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst +* to eDst->Org, and returns the corresponding half-edge eNew. +* If eOrg->Lface == eDst->Lface, this splits one loop into two, +* and the newly created loop is eNew->Lface. Otherwise, two disjoint +* loops are merged into one, and the loop eDst->Lface is destroyed. +* +* If (eOrg == eDst), the new face will have only two edges. +* If (eOrg->Lnext == eDst), the old face is reduced to a single edge. +* If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges. +*/ +TESShalfEdge *tessMeshConnect( TESSmesh *mesh, TESShalfEdge *eOrg, TESShalfEdge *eDst ) +{ + TESShalfEdge *eNewSym; + int joiningLoops = FALSE; + TESShalfEdge *eNew = MakeEdge( mesh, eOrg ); + if (eNew == NULL) return NULL; + + eNewSym = eNew->Sym; + + if( eDst->Lface != eOrg->Lface ) { + /* We are connecting two disjoint loops -- destroy eDst->Lface */ + joiningLoops = TRUE; + KillFace( mesh, eDst->Lface, eOrg->Lface ); + } + + /* Connect the new edge appropriately */ + Splice( eNew, eOrg->Lnext ); + Splice( eNewSym, eDst ); + + /* Set the vertex and face information */ + eNew->Org = eOrg->Dst; + eNewSym->Org = eDst->Org; + eNew->Lface = eNewSym->Lface = eOrg->Lface; + + /* Make sure the old face points to a valid half-edge */ + eOrg->Lface->anEdge = eNewSym; + + if( ! joiningLoops ) { + TESSface *newFace= (TESSface*)bucketAlloc( mesh->faceBucket ); + if (newFace == NULL) return NULL; + + /* We split one loop into two -- the new loop is eNew->Lface */ + MakeFace( newFace, eNew, eOrg->Lface ); + } + return eNew; +} + + +/******************** Other Operations **********************/ + +/* tessMeshZapFace( fZap ) destroys a face and removes it from the +* global face list. All edges of fZap will have a NULL pointer as their +* left face. Any edges which also have a NULL pointer as their right face +* are deleted entirely (along with any isolated vertices this produces). +* An entire mesh can be deleted by zapping its faces, one at a time, +* in any order. Zapped faces cannot be used in further mesh operations! +*/ +void tessMeshZapFace( TESSmesh *mesh, TESSface *fZap ) +{ + TESShalfEdge *eStart = fZap->anEdge; + TESShalfEdge *e, *eNext, *eSym; + TESSface *fPrev, *fNext; + + /* walk around face, deleting edges whose right face is also NULL */ + eNext = eStart->Lnext; + do { + e = eNext; + eNext = e->Lnext; + + e->Lface = NULL; + if( e->Rface == NULL ) { + /* delete the edge -- see TESSmeshDelete above */ + + if( e->Onext == e ) { + KillVertex( mesh, e->Org, NULL ); + } else { + /* Make sure that e->Org points to a valid half-edge */ + e->Org->anEdge = e->Onext; + Splice( e, e->Oprev ); + } + eSym = e->Sym; + if( eSym->Onext == eSym ) { + KillVertex( mesh, eSym->Org, NULL ); + } else { + /* Make sure that eSym->Org points to a valid half-edge */ + eSym->Org->anEdge = eSym->Onext; + Splice( eSym, eSym->Oprev ); + } + KillEdge( mesh, e ); + } + } while( e != eStart ); + + /* delete from circular doubly-linked list */ + fPrev = fZap->prev; + fNext = fZap->next; + fNext->prev = fPrev; + fPrev->next = fNext; + + bucketFree( mesh->faceBucket, fZap ); +} + +#include + +/* tessMeshNewMesh() creates a new mesh with no edges, no vertices, +* and no loops (what we usually call a "face"). +*/ +TESSmesh *tessMeshNewMesh( TESSalloc* alloc ) +{ + TESSvertex *v; + TESSface *f; + TESShalfEdge *e; + TESShalfEdge *eSym; + TESSmesh *mesh = (TESSmesh *)alloc->memalloc( alloc->userData, sizeof( TESSmesh )); + if (mesh == NULL) { + return NULL; + } + + if (alloc->meshEdgeBucketSize < 16) + alloc->meshEdgeBucketSize = 16; + if (alloc->meshEdgeBucketSize > 4096) + alloc->meshEdgeBucketSize = 4096; + + if (alloc->meshVertexBucketSize < 16) + alloc->meshVertexBucketSize = 16; + if (alloc->meshVertexBucketSize > 4096) + alloc->meshVertexBucketSize = 4096; + + if (alloc->meshFaceBucketSize < 16) + alloc->meshFaceBucketSize = 16; + if (alloc->meshFaceBucketSize > 4096) + alloc->meshFaceBucketSize = 4096; + + mesh->edgeBucket = createBucketAlloc( alloc, "Mesh Edges", sizeof(EdgePair), alloc->meshEdgeBucketSize ); + mesh->vertexBucket = createBucketAlloc( alloc, "Mesh Vertices", sizeof(TESSvertex), alloc->meshVertexBucketSize ); + mesh->faceBucket = createBucketAlloc( alloc, "Mesh Faces", sizeof(TESSface), alloc->meshFaceBucketSize ); + + v = &mesh->vHead; + f = &mesh->fHead; + e = &mesh->eHead; + eSym = &mesh->eHeadSym; + + v->next = v->prev = v; + v->anEdge = NULL; + + f->next = f->prev = f; + f->anEdge = NULL; + f->trail = NULL; + f->marked = FALSE; + f->inside = FALSE; + + e->next = e; + e->Sym = eSym; + e->Onext = NULL; + e->Lnext = NULL; + e->Org = NULL; + e->Lface = NULL; + e->winding = 0; + e->activeRegion = NULL; + + eSym->next = eSym; + eSym->Sym = e; + eSym->Onext = NULL; + eSym->Lnext = NULL; + eSym->Org = NULL; + eSym->Lface = NULL; + eSym->winding = 0; + eSym->activeRegion = NULL; + + return mesh; +} + + +/* tessMeshUnion( mesh1, mesh2 ) forms the union of all structures in +* both meshes, and returns the new mesh (the old meshes are destroyed). +*/ +TESSmesh *tessMeshUnion( TESSalloc* alloc, TESSmesh *mesh1, TESSmesh *mesh2 ) +{ + TESSface *f1 = &mesh1->fHead; + TESSvertex *v1 = &mesh1->vHead; + TESShalfEdge *e1 = &mesh1->eHead; + TESSface *f2 = &mesh2->fHead; + TESSvertex *v2 = &mesh2->vHead; + TESShalfEdge *e2 = &mesh2->eHead; + + /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */ + if( f2->next != f2 ) { + f1->prev->next = f2->next; + f2->next->prev = f1->prev; + f2->prev->next = f1; + f1->prev = f2->prev; + } + + if( v2->next != v2 ) { + v1->prev->next = v2->next; + v2->next->prev = v1->prev; + v2->prev->next = v1; + v1->prev = v2->prev; + } + + if( e2->next != e2 ) { + e1->Sym->next->Sym->next = e2->next; + e2->next->Sym->next = e1->Sym->next; + e2->Sym->next->Sym->next = e1; + e1->Sym->next = e2->Sym->next; + } + + alloc->memfree( alloc->userData, mesh2 ); + return mesh1; +} + + +static int CountFaceVerts( TESSface *f ) +{ + TESShalfEdge *eCur = f->anEdge; + int n = 0; + do + { + n++; + eCur = eCur->Lnext; + } + while (eCur != f->anEdge); + return n; +} + +int tessMeshMergeConvexFaces( TESSmesh *mesh, int maxVertsPerFace ) +{ + TESSface *f; + TESShalfEdge *eCur, *eNext, *eSym; + TESSvertex *vStart; + int curNv, symNv; + + for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) + { + // Skip faces which are outside the result. + if( !f->inside ) + continue; + + eCur = f->anEdge; + vStart = eCur->Org; + + while (1) + { + eNext = eCur->Lnext; + eSym = eCur->Sym; + + // Try to merge if the neighbour face is valid. + if( eSym && eSym->Lface && eSym->Lface->inside ) + { + // Try to merge the neighbour faces if the resulting polygons + // does not exceed maximum number of vertices. + curNv = CountFaceVerts( f ); + symNv = CountFaceVerts( eSym->Lface ); + if( (curNv+symNv-2) <= maxVertsPerFace ) + { + // Merge if the resulting poly is convex. + if( VertCCW( eCur->Lprev->Org, eCur->Org, eSym->Lnext->Lnext->Org ) && + VertCCW( eSym->Lprev->Org, eSym->Org, eCur->Lnext->Lnext->Org ) ) + { + eNext = eSym->Lnext; + if( !tessMeshDelete( mesh, eSym ) ) + return 0; + eCur = 0; + } + } + } + + if( eCur && eCur->Lnext->Org == vStart ) + break; + + // Continue to next edge. + eCur = eNext; + } + } + + return 1; +} + + +#ifdef DELETE_BY_ZAPPING + +/* tessMeshDeleteMesh( mesh ) will free all storage for any valid mesh. +*/ +void tessMeshDeleteMesh( TESSalloc* alloc, TESSmesh *mesh ) +{ + TESSface *fHead = &mesh->fHead; + + while( fHead->next != fHead ) { + tessMeshZapFace( fHead->next ); + } + assert( mesh->vHead.next == &mesh->vHead ); + + alloc->memfree( alloc->userData, mesh ); +} + +#else + +/* tessMeshDeleteMesh( mesh ) will free all storage for any valid mesh. +*/ +void tessMeshDeleteMesh( TESSalloc* alloc, TESSmesh *mesh ) +{ + deleteBucketAlloc(mesh->edgeBucket); + deleteBucketAlloc(mesh->vertexBucket); + deleteBucketAlloc(mesh->faceBucket); + + alloc->memfree( alloc->userData, mesh ); +} + +#endif + +#ifndef NDEBUG + +/* tessMeshCheckMesh( mesh ) checks a mesh for self-consistency. +*/ +void tessMeshCheckMesh( TESSmesh *mesh ) +{ + TESSface *fHead = &mesh->fHead; + TESSvertex *vHead = &mesh->vHead; + TESShalfEdge *eHead = &mesh->eHead; + TESSface *f, *fPrev; + TESSvertex *v, *vPrev; + TESShalfEdge *e, *ePrev; + + fPrev = fHead; + for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) { + assert( f->prev == fPrev ); + e = f->anEdge; + do { + assert( e->Sym != e ); + assert( e->Sym->Sym == e ); + assert( e->Lnext->Onext->Sym == e ); + assert( e->Onext->Sym->Lnext == e ); + assert( e->Lface == f ); + e = e->Lnext; + } while( e != f->anEdge ); + } + assert( f->prev == fPrev && f->anEdge == NULL ); + + vPrev = vHead; + for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) { + assert( v->prev == vPrev ); + e = v->anEdge; + do { + assert( e->Sym != e ); + assert( e->Sym->Sym == e ); + assert( e->Lnext->Onext->Sym == e ); + assert( e->Onext->Sym->Lnext == e ); + assert( e->Org == v ); + e = e->Onext; + } while( e != v->anEdge ); + } + assert( v->prev == vPrev && v->anEdge == NULL ); + + ePrev = eHead; + for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) { + assert( e->Sym->next == ePrev->Sym ); + assert( e->Sym != e ); + assert( e->Sym->Sym == e ); + assert( e->Org != NULL ); + assert( e->Dst != NULL ); + assert( e->Lnext->Onext->Sym == e ); + assert( e->Onext->Sym->Lnext == e ); + } + assert( e->Sym->next == ePrev->Sym + && e->Sym == &mesh->eHeadSym + && e->Sym->Sym == e + && e->Org == NULL && e->Dst == NULL + && e->Lface == NULL && e->Rface == NULL ); +} + +#endif diff --git a/src/libtess2/mesh.h b/src/libtess2/mesh.h new file mode 100755 index 000000000..1e16a194c --- /dev/null +++ b/src/libtess2/mesh.h @@ -0,0 +1,267 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +#ifndef MESH_H +#define MESH_H + +#include "tesselator.h" + +typedef struct TESSmesh TESSmesh; +typedef struct TESSvertex TESSvertex; +typedef struct TESSface TESSface; +typedef struct TESShalfEdge TESShalfEdge; +typedef struct ActiveRegion ActiveRegion; + +/* The mesh structure is similar in spirit, notation, and operations +* to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives +* for the manipulation of general subdivisions and the computation of +* Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985). +* For a simplified description, see the course notes for CS348a, +* "Mathematical Foundations of Computer Graphics", available at the +* Stanford bookstore (and taught during the fall quarter). +* The implementation also borrows a tiny subset of the graph-based approach +* use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction +* to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988). +* +* The fundamental data structure is the "half-edge". Two half-edges +* go together to make an edge, but they point in opposite directions. +* Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym), +* its origin vertex (Org), the face on its left side (Lface), and the +* adjacent half-edges in the CCW direction around the origin vertex +* (Onext) and around the left face (Lnext). There is also a "next" +* pointer for the global edge list (see below). +* +* The notation used for mesh navigation: +* Sym = the mate of a half-edge (same edge, but opposite direction) +* Onext = edge CCW around origin vertex (keep same origin) +* Dnext = edge CCW around destination vertex (keep same dest) +* Lnext = edge CCW around left face (dest becomes new origin) +* Rnext = edge CCW around right face (origin becomes new dest) +* +* "prev" means to substitute CW for CCW in the definitions above. +* +* The mesh keeps global lists of all vertices, faces, and edges, +* stored as doubly-linked circular lists with a dummy header node. +* The mesh stores pointers to these dummy headers (vHead, fHead, eHead). +* +* The circular edge list is special; since half-edges always occur +* in pairs (e and e->Sym), each half-edge stores a pointer in only +* one direction. Starting at eHead and following the e->next pointers +* will visit each *edge* once (ie. e or e->Sym, but not both). +* e->Sym stores a pointer in the opposite direction, thus it is +* always true that e->Sym->next->Sym->next == e. +* +* Each vertex has a pointer to next and previous vertices in the +* circular list, and a pointer to a half-edge with this vertex as +* the origin (NULL if this is the dummy header). There is also a +* field "data" for client data. +* +* Each face has a pointer to the next and previous faces in the +* circular list, and a pointer to a half-edge with this face as +* the left face (NULL if this is the dummy header). There is also +* a field "data" for client data. +* +* Note that what we call a "face" is really a loop; faces may consist +* of more than one loop (ie. not simply connected), but there is no +* record of this in the data structure. The mesh may consist of +* several disconnected regions, so it may not be possible to visit +* the entire mesh by starting at a half-edge and traversing the edge +* structure. +* +* The mesh does NOT support isolated vertices; a vertex is deleted along +* with its last edge. Similarly when two faces are merged, one of the +* faces is deleted (see tessMeshDelete below). For mesh operations, +* all face (loop) and vertex pointers must not be NULL. However, once +* mesh manipulation is finished, TESSmeshZapFace can be used to delete +* faces of the mesh, one at a time. All external faces can be "zapped" +* before the mesh is returned to the client; then a NULL face indicates +* a region which is not part of the output polygon. +*/ + +struct TESSvertex { + TESSvertex *next; /* next vertex (never NULL) */ + TESSvertex *prev; /* previous vertex (never NULL) */ + TESShalfEdge *anEdge; /* a half-edge with this origin */ + + /* Internal data (keep hidden) */ + TESSreal coords[3]; /* vertex location in 3D */ + TESSreal s, t; /* projection onto the sweep plane */ + int pqHandle; /* to allow deletion from priority queue */ + TESSindex n; /* to allow identify unique vertices */ + TESSindex idx; /* to allow map result to original verts */ +}; + +struct TESSface { + TESSface *next; /* next face (never NULL) */ + TESSface *prev; /* previous face (never NULL) */ + TESShalfEdge *anEdge; /* a half edge with this left face */ + + /* Internal data (keep hidden) */ + TESSface *trail; /* "stack" for conversion to strips */ + TESSindex n; /* to allow identiy unique faces */ + char marked; /* flag for conversion to strips */ + char inside; /* this face is in the polygon interior */ +}; + +struct TESShalfEdge { + TESShalfEdge *next; /* doubly-linked list (prev==Sym->next) */ + TESShalfEdge *Sym; /* same edge, opposite direction */ + TESShalfEdge *Onext; /* next edge CCW around origin */ + TESShalfEdge *Lnext; /* next edge CCW around left face */ + TESSvertex *Org; /* origin vertex (Overtex too long) */ + TESSface *Lface; /* left face */ + + /* Internal data (keep hidden) */ + ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */ + int winding; /* change in winding number when crossing + from the right face to the left face */ +}; + +#define Rface Sym->Lface +#define Dst Sym->Org + +#define Oprev Sym->Lnext +#define Lprev Onext->Sym +#define Dprev Lnext->Sym +#define Rprev Sym->Onext +#define Dnext Rprev->Sym /* 3 pointers */ +#define Rnext Oprev->Sym /* 3 pointers */ + + +struct TESSmesh { + TESSvertex vHead; /* dummy header for vertex list */ + TESSface fHead; /* dummy header for face list */ + TESShalfEdge eHead; /* dummy header for edge list */ + TESShalfEdge eHeadSym; /* and its symmetric counterpart */ + + struct BucketAlloc* edgeBucket; + struct BucketAlloc* vertexBucket; + struct BucketAlloc* faceBucket; +}; + +/* The mesh operations below have three motivations: completeness, +* convenience, and efficiency. The basic mesh operations are MakeEdge, +* Splice, and Delete. All the other edge operations can be implemented +* in terms of these. The other operations are provided for convenience +* and/or efficiency. +* +* When a face is split or a vertex is added, they are inserted into the +* global list *before* the existing vertex or face (ie. e->Org or e->Lface). +* This makes it easier to process all vertices or faces in the global lists +* without worrying about processing the same data twice. As a convenience, +* when a face is split, the "inside" flag is copied from the old face. +* Other internal data (v->data, v->activeRegion, f->data, f->marked, +* f->trail, e->winding) is set to zero. +* +* ********************** Basic Edge Operations ************************** +* +* tessMeshMakeEdge( mesh ) creates one edge, two vertices, and a loop. +* The loop (face) consists of the two new half-edges. +* +* tessMeshSplice( eOrg, eDst ) is the basic operation for changing the +* mesh connectivity and topology. It changes the mesh so that +* eOrg->Onext <- OLD( eDst->Onext ) +* eDst->Onext <- OLD( eOrg->Onext ) +* where OLD(...) means the value before the meshSplice operation. +* +* This can have two effects on the vertex structure: +* - if eOrg->Org != eDst->Org, the two vertices are merged together +* - if eOrg->Org == eDst->Org, the origin is split into two vertices +* In both cases, eDst->Org is changed and eOrg->Org is untouched. +* +* Similarly (and independently) for the face structure, +* - if eOrg->Lface == eDst->Lface, one loop is split into two +* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one +* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. +* +* tessMeshDelete( eDel ) removes the edge eDel. There are several cases: +* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop +* eDel->Lface is deleted. Otherwise, we are splitting one loop into two; +* the newly created loop will contain eDel->Dst. If the deletion of eDel +* would create isolated vertices, those are deleted as well. +* +* ********************** Other Edge Operations ************************** +* +* tessMeshAddEdgeVertex( eOrg ) creates a new edge eNew such that +* eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. +* eOrg and eNew will have the same left face. +* +* tessMeshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, +* such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org. +* eOrg and eNew will have the same left face. +* +* tessMeshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst +* to eDst->Org, and returns the corresponding half-edge eNew. +* If eOrg->Lface == eDst->Lface, this splits one loop into two, +* and the newly created loop is eNew->Lface. Otherwise, two disjoint +* loops are merged into one, and the loop eDst->Lface is destroyed. +* +* ************************ Other Operations ***************************** +* +* tessMeshNewMesh() creates a new mesh with no edges, no vertices, +* and no loops (what we usually call a "face"). +* +* tessMeshUnion( mesh1, mesh2 ) forms the union of all structures in +* both meshes, and returns the new mesh (the old meshes are destroyed). +* +* tessMeshDeleteMesh( mesh ) will free all storage for any valid mesh. +* +* tessMeshZapFace( fZap ) destroys a face and removes it from the +* global face list. All edges of fZap will have a NULL pointer as their +* left face. Any edges which also have a NULL pointer as their right face +* are deleted entirely (along with any isolated vertices this produces). +* An entire mesh can be deleted by zapping its faces, one at a time, +* in any order. Zapped faces cannot be used in further mesh operations! +* +* tessMeshCheckMesh( mesh ) checks a mesh for self-consistency. +*/ + +TESShalfEdge *tessMeshMakeEdge( TESSmesh *mesh ); +int tessMeshSplice( TESSmesh *mesh, TESShalfEdge *eOrg, TESShalfEdge *eDst ); +int tessMeshDelete( TESSmesh *mesh, TESShalfEdge *eDel ); + +TESShalfEdge *tessMeshAddEdgeVertex( TESSmesh *mesh, TESShalfEdge *eOrg ); +TESShalfEdge *tessMeshSplitEdge( TESSmesh *mesh, TESShalfEdge *eOrg ); +TESShalfEdge *tessMeshConnect( TESSmesh *mesh, TESShalfEdge *eOrg, TESShalfEdge *eDst ); + +TESSmesh *tessMeshNewMesh( TESSalloc* alloc ); +TESSmesh *tessMeshUnion( TESSalloc* alloc, TESSmesh *mesh1, TESSmesh *mesh2 ); +int tessMeshMergeConvexFaces( TESSmesh *mesh, int maxVertsPerFace ); +void tessMeshDeleteMesh( TESSalloc* alloc, TESSmesh *mesh ); +void tessMeshZapFace( TESSmesh *mesh, TESSface *fZap ); + +#ifdef NDEBUG +#define tessMeshCheckMesh( mesh ) +#else +void tessMeshCheckMesh( TESSmesh *mesh ); +#endif + +#endif diff --git a/src/libtess2/priorityq.c b/src/libtess2/priorityq.c new file mode 100755 index 000000000..6229b6bfc --- /dev/null +++ b/src/libtess2/priorityq.c @@ -0,0 +1,514 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +//#include "tesos.h" +#include +#include +#include "tesselator.h" +#include "priorityq.h" + + +#define INIT_SIZE 32 + +#define TRUE 1 +#define FALSE 0 + +#ifdef FOR_TRITE_TEST_PROGRAM +#define LEQ(x,y) (*pq->leq)(x,y) +#else +/* Violates modularity, but a little faster */ +#include "geom.h" +#define LEQ(x,y) VertLeq((TESSvertex *)x, (TESSvertex *)y) +#endif + + +/* Include all the code for the regular heap-based queue here. */ + +/* The basic operations are insertion of a new key (pqInsert), +* and examination/extraction of a key whose value is minimum +* (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); +* for this purpose pqInsert returns a "handle" which is supplied +* as the argument. +* +* An initial heap may be created efficiently by calling pqInsert +* repeatedly, then calling pqInit. In any case pqInit must be called +* before any operations other than pqInsert are used. +* +* If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. +* This may also be tested with pqIsEmpty. +*/ + + +/* Since we support deletion the data structure is a little more +* complicated than an ordinary heap. "nodes" is the heap itself; +* active nodes are stored in the range 1..pq->size. When the +* heap exceeds its allocated size (pq->max), its size doubles. +* The children of node i are nodes 2i and 2i+1. +* +* Each node stores an index into an array "handles". Each handle +* stores a key, plus a pointer back to the node which currently +* represents that key (ie. nodes[handles[i].node].handle == i). +*/ + + +#define pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key) +#define pqHeapIsEmpty(pq) ((pq)->size == 0) + + + +/* really pqHeapNewPriorityQHeap */ +PriorityQHeap *pqHeapNewPriorityQ( TESSalloc* alloc, int size, int (*leq)(PQkey key1, PQkey key2) ) +{ + PriorityQHeap *pq = (PriorityQHeap *)alloc->memalloc( alloc->userData, sizeof( PriorityQHeap )); + if (pq == NULL) return NULL; + + pq->size = 0; + pq->max = size; + pq->nodes = (PQnode *)alloc->memalloc( alloc->userData, (size + 1) * sizeof(pq->nodes[0]) ); + if (pq->nodes == NULL) { + alloc->memfree( alloc->userData, pq ); + return NULL; + } + + pq->handles = (PQhandleElem *)alloc->memalloc( alloc->userData, (size + 1) * sizeof(pq->handles[0]) ); + if (pq->handles == NULL) { + alloc->memfree( alloc->userData, pq->nodes ); + alloc->memfree( alloc->userData, pq ); + return NULL; + } + + pq->initialized = FALSE; + pq->freeList = 0; + pq->leq = leq; + + pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */ + pq->handles[1].key = NULL; + return pq; +} + +/* really pqHeapDeletePriorityQHeap */ +void pqHeapDeletePriorityQ( TESSalloc* alloc, PriorityQHeap *pq ) +{ + alloc->memfree( alloc->userData, pq->handles ); + alloc->memfree( alloc->userData, pq->nodes ); + alloc->memfree( alloc->userData, pq ); +} + + +static void FloatDown( PriorityQHeap *pq, int curr ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + PQhandle hCurr, hChild; + int child; + + hCurr = n[curr].handle; + for( ;; ) { + child = curr << 1; + if( child < pq->size && LEQ( h[n[child+1].handle].key, + h[n[child].handle].key )) { + ++child; + } + + assert(child <= pq->max); + + hChild = n[child].handle; + if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) { + n[curr].handle = hCurr; + h[hCurr].node = curr; + break; + } + n[curr].handle = hChild; + h[hChild].node = curr; + curr = child; + } +} + + +static void FloatUp( PriorityQHeap *pq, int curr ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + PQhandle hCurr, hParent; + int parent; + + hCurr = n[curr].handle; + for( ;; ) { + parent = curr >> 1; + hParent = n[parent].handle; + if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) { + n[curr].handle = hCurr; + h[hCurr].node = curr; + break; + } + n[curr].handle = hParent; + h[hParent].node = curr; + curr = parent; + } +} + +/* really pqHeapInit */ +void pqHeapInit( PriorityQHeap *pq ) +{ + int i; + + /* This method of building a heap is O(n), rather than O(n lg n). */ + + for( i = pq->size; i >= 1; --i ) { + FloatDown( pq, i ); + } + pq->initialized = TRUE; +} + +/* really pqHeapInsert */ +/* returns INV_HANDLE iff out of memory */ +PQhandle pqHeapInsert( TESSalloc* alloc, PriorityQHeap *pq, PQkey keyNew ) +{ + int curr; + PQhandle free; + + curr = ++ pq->size; + if( (curr*2) > pq->max ) { + if (!alloc->memrealloc) + { + return INV_HANDLE; + } + else + { + PQnode *saveNodes= pq->nodes; + PQhandleElem *saveHandles= pq->handles; + + // If the heap overflows, double its size. + pq->max <<= 1; + pq->nodes = (PQnode *)alloc->memrealloc( alloc->userData, pq->nodes, + (unsigned int)((pq->max + 1) * sizeof( pq->nodes[0] ))); + if (pq->nodes == NULL) { + pq->nodes = saveNodes; // restore ptr to free upon return + return INV_HANDLE; + } + pq->handles = (PQhandleElem *)alloc->memrealloc( alloc->userData, pq->handles, + (unsigned int) ((pq->max + 1) * sizeof( pq->handles[0] ))); + if (pq->handles == NULL) { + pq->handles = saveHandles; // restore ptr to free upon return + return INV_HANDLE; + } + } + } + + if( pq->freeList == 0 ) { + free = curr; + } else { + free = pq->freeList; + pq->freeList = pq->handles[free].node; + } + + pq->nodes[curr].handle = free; + pq->handles[free].node = curr; + pq->handles[free].key = keyNew; + + if( pq->initialized ) { + FloatUp( pq, curr ); + } + assert(free != INV_HANDLE); + return free; +} + +/* really pqHeapExtractMin */ +PQkey pqHeapExtractMin( PriorityQHeap *pq ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + PQhandle hMin = n[1].handle; + PQkey min = h[hMin].key; + + if( pq->size > 0 ) { + n[1].handle = n[pq->size].handle; + h[n[1].handle].node = 1; + + h[hMin].key = NULL; + h[hMin].node = pq->freeList; + pq->freeList = hMin; + + if( -- pq->size > 0 ) { + FloatDown( pq, 1 ); + } + } + return min; +} + +/* really pqHeapDelete */ +void pqHeapDelete( PriorityQHeap *pq, PQhandle hCurr ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + int curr; + + assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL ); + + curr = h[hCurr].node; + n[curr].handle = n[pq->size].handle; + h[n[curr].handle].node = curr; + + if( curr <= -- pq->size ) { + if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) { + FloatDown( pq, curr ); + } else { + FloatUp( pq, curr ); + } + } + h[hCurr].key = NULL; + h[hCurr].node = pq->freeList; + pq->freeList = hCurr; +} + + + +/* Now redefine all the function names to map to their "Sort" versions. */ + +/* really tessPqSortNewPriorityQ */ +PriorityQ *pqNewPriorityQ( TESSalloc* alloc, int size, int (*leq)(PQkey key1, PQkey key2) ) +{ + PriorityQ *pq = (PriorityQ *)alloc->memalloc( alloc->userData, sizeof( PriorityQ )); + if (pq == NULL) return NULL; + + pq->heap = pqHeapNewPriorityQ( alloc, size, leq ); + if (pq->heap == NULL) { + alloc->memfree( alloc->userData, pq ); + return NULL; + } + +// pq->keys = (PQkey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) ); + pq->keys = (PQkey *)alloc->memalloc( alloc->userData, size * sizeof(pq->keys[0]) ); + if (pq->keys == NULL) { + pqHeapDeletePriorityQ( alloc, pq->heap ); + alloc->memfree( alloc->userData, pq ); + return NULL; + } + + pq->size = 0; + pq->max = size; //INIT_SIZE; + pq->initialized = FALSE; + pq->leq = leq; + + return pq; +} + +/* really tessPqSortDeletePriorityQ */ +void pqDeletePriorityQ( TESSalloc* alloc, PriorityQ *pq ) +{ + assert(pq != NULL); + if (pq->heap != NULL) pqHeapDeletePriorityQ( alloc, pq->heap ); + if (pq->order != NULL) alloc->memfree( alloc->userData, pq->order ); + if (pq->keys != NULL) alloc->memfree( alloc->userData, pq->keys ); + alloc->memfree( alloc->userData, pq ); +} + + +#define LT(x,y) (! LEQ(y,x)) +#define GT(x,y) (! LEQ(x,y)) +#define Swap(a,b) if(1){PQkey *tmp = *a; *a = *b; *b = tmp;}else + +/* really tessPqSortInit */ +int pqInit( TESSalloc* alloc, PriorityQ *pq ) +{ + PQkey **p, **r, **i, **j, *piv; + struct { PQkey **p, **r; } Stack[50], *top = Stack; + unsigned int seed = 2016473283; + + /* Create an array of indirect pointers to the keys, so that we + * the handles we have returned are still valid. + */ + /* + pq->order = (PQkey **)memAlloc( (size_t) + (pq->size * sizeof(pq->order[0])) ); + */ + pq->order = (PQkey **)alloc->memalloc( alloc->userData, + (unsigned int)((pq->size+1) * sizeof(pq->order[0])) ); + /* the previous line is a patch to compensate for the fact that IBM */ + /* machines return a null on a malloc of zero bytes (unlike SGI), */ + /* so we have to put in this defense to guard against a memory */ + /* fault four lines down. from fossum@austin.ibm.com. */ + if (pq->order == NULL) return 0; + + p = pq->order; + r = p + pq->size - 1; + for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) { + *i = piv; + } + + /* Sort the indirect pointers in descending order, + * using randomized Quicksort + */ + top->p = p; top->r = r; ++top; + while( --top >= Stack ) { + p = top->p; + r = top->r; + while( r > p + 10 ) { + seed = seed * 1539415821 + 1; + i = p + seed % (r - p + 1); + piv = *i; + *i = *p; + *p = piv; + i = p - 1; + j = r + 1; + do { + do { ++i; } while( GT( **i, *piv )); + do { --j; } while( LT( **j, *piv )); + Swap( i, j ); + } while( i < j ); + Swap( i, j ); /* Undo last swap */ + if( i - p < r - j ) { + top->p = j+1; top->r = r; ++top; + r = i-1; + } else { + top->p = p; top->r = i-1; ++top; + p = j+1; + } + } + /* Insertion sort small lists */ + for( i = p+1; i <= r; ++i ) { + piv = *i; + for( j = i; j > p && LT( **(j-1), *piv ); --j ) { + *j = *(j-1); + } + *j = piv; + } + } + pq->max = pq->size; + pq->initialized = TRUE; + pqHeapInit( pq->heap ); /* always succeeds */ + +#ifndef NDEBUG + p = pq->order; + r = p + pq->size - 1; + for( i = p; i < r; ++i ) { + assert( LEQ( **(i+1), **i )); + } +#endif + + return 1; +} + +/* really tessPqSortInsert */ +/* returns INV_HANDLE iff out of memory */ +PQhandle pqInsert( TESSalloc* alloc, PriorityQ *pq, PQkey keyNew ) +{ + int curr; + + if( pq->initialized ) { + return pqHeapInsert( alloc, pq->heap, keyNew ); + } + curr = pq->size; + if( ++ pq->size >= pq->max ) { + if (!alloc->memrealloc) + { + return INV_HANDLE; + } + else + { + PQkey *saveKey= pq->keys; + // If the heap overflows, double its size. + pq->max <<= 1; + pq->keys = (PQkey *)alloc->memrealloc( alloc->userData, pq->keys, + (unsigned int)(pq->max * sizeof( pq->keys[0] ))); + if (pq->keys == NULL) { + pq->keys = saveKey; // restore ptr to free upon return + return INV_HANDLE; + } + } + } + assert(curr != INV_HANDLE); + pq->keys[curr] = keyNew; + + /* Negative handles index the sorted array. */ + return -(curr+1); +} + +/* really tessPqSortExtractMin */ +PQkey pqExtractMin( PriorityQ *pq ) +{ + PQkey sortMin, heapMin; + + if( pq->size == 0 ) { + return pqHeapExtractMin( pq->heap ); + } + sortMin = *(pq->order[pq->size-1]); + if( ! pqHeapIsEmpty( pq->heap )) { + heapMin = pqHeapMinimum( pq->heap ); + if( LEQ( heapMin, sortMin )) { + return pqHeapExtractMin( pq->heap ); + } + } + do { + -- pq->size; + } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ); + return sortMin; +} + +/* really tessPqSortMinimum */ +PQkey pqMinimum( PriorityQ *pq ) +{ + PQkey sortMin, heapMin; + + if( pq->size == 0 ) { + return pqHeapMinimum( pq->heap ); + } + sortMin = *(pq->order[pq->size-1]); + if( ! pqHeapIsEmpty( pq->heap )) { + heapMin = pqHeapMinimum( pq->heap ); + if( LEQ( heapMin, sortMin )) { + return heapMin; + } + } + return sortMin; +} + +/* really tessPqSortIsEmpty */ +int pqIsEmpty( PriorityQ *pq ) +{ + return (pq->size == 0) && pqHeapIsEmpty( pq->heap ); +} + +/* really tessPqSortDelete */ +void pqDelete( PriorityQ *pq, PQhandle curr ) +{ + if( curr >= 0 ) { + pqHeapDelete( pq->heap, curr ); + return; + } + curr = -(curr+1); + assert( curr < pq->max && pq->keys[curr] != NULL ); + + pq->keys[curr] = NULL; + while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) { + -- pq->size; + } +} diff --git a/src/libtess2/priorityq.h b/src/libtess2/priorityq.h new file mode 100755 index 000000000..42d933449 --- /dev/null +++ b/src/libtess2/priorityq.h @@ -0,0 +1,104 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +#ifndef PRIORITYQ_H +#define PRIORITYQ_H + +/* The basic operations are insertion of a new key (pqInsert), +* and examination/extraction of a key whose value is minimum +* (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); +* for this purpose pqInsert returns a "handle" which is supplied +* as the argument. +* +* An initial heap may be created efficiently by calling pqInsert +* repeatedly, then calling pqInit. In any case pqInit must be called +* before any operations other than pqInsert are used. +* +* If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. +* This may also be tested with pqIsEmpty. +*/ + +/* Since we support deletion the data structure is a little more +* complicated than an ordinary heap. "nodes" is the heap itself; +* active nodes are stored in the range 1..pq->size. When the +* heap exceeds its allocated size (pq->max), its size doubles. +* The children of node i are nodes 2i and 2i+1. +* +* Each node stores an index into an array "handles". Each handle +* stores a key, plus a pointer back to the node which currently +* represents that key (ie. nodes[handles[i].node].handle == i). +*/ + +typedef void *PQkey; +typedef int PQhandle; +typedef struct PriorityQHeap PriorityQHeap; + +#define INV_HANDLE 0x0fffffff + +typedef struct { PQhandle handle; } PQnode; +typedef struct { PQkey key; PQhandle node; } PQhandleElem; + +struct PriorityQHeap { + + PQnode *nodes; + PQhandleElem *handles; + int size, max; + PQhandle freeList; + int initialized; + + int (*leq)(PQkey key1, PQkey key2); +}; + +typedef struct PriorityQ PriorityQ; + +struct PriorityQ { + PriorityQHeap *heap; + + PQkey *keys; + PQkey **order; + PQhandle size, max; + int initialized; + + int (*leq)(PQkey key1, PQkey key2); +}; + +PriorityQ *pqNewPriorityQ( TESSalloc* alloc, int size, int (*leq)(PQkey key1, PQkey key2) ); +void pqDeletePriorityQ( TESSalloc* alloc, PriorityQ *pq ); + +int pqInit( TESSalloc* alloc, PriorityQ *pq ); +PQhandle pqInsert( TESSalloc* alloc, PriorityQ *pq, PQkey key ); +PQkey pqExtractMin( PriorityQ *pq ); +void pqDelete( PriorityQ *pq, PQhandle handle ); + +PQkey pqMinimum( PriorityQ *pq ); +int pqIsEmpty( PriorityQ *pq ); + +#endif diff --git a/src/libtess2/sweep.c b/src/libtess2/sweep.c new file mode 100755 index 000000000..be3ee561c --- /dev/null +++ b/src/libtess2/sweep.c @@ -0,0 +1,1325 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +#include +#include +#include /* longjmp */ + +#include "mesh.h" +#include "geom.h" +#include "tess.h" +#include "dict.h" +#include "priorityq.h" +#include "bucketalloc.h" +#include "sweep.h" + +#define TRUE 1 +#define FALSE 0 + +#ifdef FOR_TRITE_TEST_PROGRAM +extern void DebugEvent( TESStesselator *tess ); +#else +#define DebugEvent( tess ) +#endif + +/* +* Invariants for the Edge Dictionary. +* - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2) +* at any valid location of the sweep event +* - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2 +* share a common endpoint +* - for each e, e->Dst has been processed, but not e->Org +* - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org) +* where "event" is the current sweep line event. +* - no edge e has zero length +* +* Invariants for the Mesh (the processed portion). +* - the portion of the mesh left of the sweep line is a planar graph, +* ie. there is *some* way to embed it in the plane +* - no processed edge has zero length +* - no two processed vertices have identical coordinates +* - each "inside" region is monotone, ie. can be broken into two chains +* of monotonically increasing vertices according to VertLeq(v1,v2) +* - a non-invariant: these chains may intersect (very slightly) +* +* Invariants for the Sweep. +* - if none of the edges incident to the event vertex have an activeRegion +* (ie. none of these edges are in the edge dictionary), then the vertex +* has only right-going edges. +* - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced +* by ConnectRightVertex), then it is the only right-going edge from +* its associated vertex. (This says that these edges exist only +* when it is necessary.) +*/ + +#define MAX(x,y) ((x) >= (y) ? (x) : (y)) +#define MIN(x,y) ((x) <= (y) ? (x) : (y)) + +/* When we merge two edges into one, we need to compute the combined +* winding of the new edge. +*/ +#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ + eDst->Sym->winding += eSrc->Sym->winding) + +static void SweepEvent( TESStesselator *tess, TESSvertex *vEvent ); +static void WalkDirtyRegions( TESStesselator *tess, ActiveRegion *regUp ); +static int CheckForRightSplice( TESStesselator *tess, ActiveRegion *regUp ); + +static int EdgeLeq( TESStesselator *tess, ActiveRegion *reg1, ActiveRegion *reg2 ) +/* +* Both edges must be directed from right to left (this is the canonical +* direction for the upper edge of each region). +* +* The strategy is to evaluate a "t" value for each edge at the +* current sweep line position, given by tess->event. The calculations +* are designed to be very stable, but of course they are not perfect. +* +* Special case: if both edge destinations are at the sweep event, +* we sort the edges by slope (they would otherwise compare equally). +*/ +{ + TESSvertex *event = tess->event; + TESShalfEdge *e1, *e2; + TESSreal t1, t2; + + e1 = reg1->eUp; + e2 = reg2->eUp; + + if( e1->Dst == event ) { + if( e2->Dst == event ) { + /* Two edges right of the sweep line which meet at the sweep event. + * Sort them by slope. + */ + if( VertLeq( e1->Org, e2->Org )) { + return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0; + } + return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0; + } + return EdgeSign( e2->Dst, event, e2->Org ) <= 0; + } + if( e2->Dst == event ) { + return EdgeSign( e1->Dst, event, e1->Org ) >= 0; + } + + /* General case - compute signed distance *from* e1, e2 to event */ + t1 = EdgeEval( e1->Dst, event, e1->Org ); + t2 = EdgeEval( e2->Dst, event, e2->Org ); + return (t1 >= t2); +} + + +static void DeleteRegion( TESStesselator *tess, ActiveRegion *reg ) +{ + if( reg->fixUpperEdge ) { + /* It was created with zero winding number, so it better be + * deleted with zero winding number (ie. it better not get merged + * with a real edge). + */ + assert( reg->eUp->winding == 0 ); + } + reg->eUp->activeRegion = NULL; + dictDelete( tess->dict, reg->nodeUp ); + bucketFree( tess->regionPool, reg ); +} + + +static int FixUpperEdge( TESStesselator *tess, ActiveRegion *reg, TESShalfEdge *newEdge ) +/* +* Replace an upper edge which needs fixing (see ConnectRightVertex). +*/ +{ + assert( reg->fixUpperEdge ); + if ( !tessMeshDelete( tess->mesh, reg->eUp ) ) return 0; + reg->fixUpperEdge = FALSE; + reg->eUp = newEdge; + newEdge->activeRegion = reg; + + return 1; +} + +static ActiveRegion *TopLeftRegion( TESStesselator *tess, ActiveRegion *reg ) +{ + TESSvertex *org = reg->eUp->Org; + TESShalfEdge *e; + + /* Find the region above the uppermost edge with the same origin */ + do { + reg = RegionAbove( reg ); + } while( reg->eUp->Org == org ); + + /* If the edge above was a temporary edge introduced by ConnectRightVertex, + * now is the time to fix it. + */ + if( reg->fixUpperEdge ) { + e = tessMeshConnect( tess->mesh, RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext ); + if (e == NULL) return NULL; + if ( !FixUpperEdge( tess, reg, e ) ) return NULL; + reg = RegionAbove( reg ); + } + return reg; +} + +static ActiveRegion *TopRightRegion( ActiveRegion *reg ) +{ + TESSvertex *dst = reg->eUp->Dst; + + /* Find the region above the uppermost edge with the same destination */ + do { + reg = RegionAbove( reg ); + } while( reg->eUp->Dst == dst ); + return reg; +} + +static ActiveRegion *AddRegionBelow( TESStesselator *tess, + ActiveRegion *regAbove, + TESShalfEdge *eNewUp ) +/* +* Add a new active region to the sweep line, *somewhere* below "regAbove" +* (according to where the new edge belongs in the sweep-line dictionary). +* The upper edge of the new region will be "eNewUp". +* Winding number and "inside" flag are not updated. +*/ +{ + ActiveRegion *regNew = (ActiveRegion *)bucketAlloc( tess->regionPool ); + if (regNew == NULL) longjmp(tess->env,1); + + regNew->eUp = eNewUp; + regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew ); + if (regNew->nodeUp == NULL) longjmp(tess->env,1); + regNew->fixUpperEdge = FALSE; + regNew->sentinel = FALSE; + regNew->dirty = FALSE; + + eNewUp->activeRegion = regNew; + return regNew; +} + +static int IsWindingInside( TESStesselator *tess, int n ) +{ + switch( tess->windingRule ) { + case TESS_WINDING_ODD: + return (n & 1); + case TESS_WINDING_NONZERO: + return (n != 0); + case TESS_WINDING_POSITIVE: + return (n > 0); + case TESS_WINDING_NEGATIVE: + return (n < 0); + case TESS_WINDING_ABS_GEQ_TWO: + return (n >= 2) || (n <= -2); + } + /*LINTED*/ + assert( FALSE ); + /*NOTREACHED*/ + + return( FALSE ); +} + + +static void ComputeWinding( TESStesselator *tess, ActiveRegion *reg ) +{ + reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding; + reg->inside = IsWindingInside( tess, reg->windingNumber ); +} + + +static void FinishRegion( TESStesselator *tess, ActiveRegion *reg ) +/* +* Delete a region from the sweep line. This happens when the upper +* and lower chains of a region meet (at a vertex on the sweep line). +* The "inside" flag is copied to the appropriate mesh face (we could +* not do this before -- since the structure of the mesh is always +* changing, this face may not have even existed until now). +*/ +{ + TESShalfEdge *e = reg->eUp; + TESSface *f = e->Lface; + + f->inside = reg->inside; + f->anEdge = e; /* optimization for tessMeshTessellateMonoRegion() */ + DeleteRegion( tess, reg ); +} + + +static TESShalfEdge *FinishLeftRegions( TESStesselator *tess, + ActiveRegion *regFirst, ActiveRegion *regLast ) +/* +* We are given a vertex with one or more left-going edges. All affected +* edges should be in the edge dictionary. Starting at regFirst->eUp, +* we walk down deleting all regions where both edges have the same +* origin vOrg. At the same time we copy the "inside" flag from the +* active region to the face, since at this point each face will belong +* to at most one region (this was not necessarily true until this point +* in the sweep). The walk stops at the region above regLast; if regLast +* is NULL we walk as far as possible. At the same time we relink the +* mesh if necessary, so that the ordering of edges around vOrg is the +* same as in the dictionary. +*/ +{ + ActiveRegion *reg, *regPrev; + TESShalfEdge *e, *ePrev; + + regPrev = regFirst; + ePrev = regFirst->eUp; + while( regPrev != regLast ) { + regPrev->fixUpperEdge = FALSE; /* placement was OK */ + reg = RegionBelow( regPrev ); + e = reg->eUp; + if( e->Org != ePrev->Org ) { + if( ! reg->fixUpperEdge ) { + /* Remove the last left-going edge. Even though there are no further + * edges in the dictionary with this origin, there may be further + * such edges in the mesh (if we are adding left edges to a vertex + * that has already been processed). Thus it is important to call + * FinishRegion rather than just DeleteRegion. + */ + FinishRegion( tess, regPrev ); + break; + } + /* If the edge below was a temporary edge introduced by + * ConnectRightVertex, now is the time to fix it. + */ + e = tessMeshConnect( tess->mesh, ePrev->Lprev, e->Sym ); + if (e == NULL) longjmp(tess->env,1); + if ( !FixUpperEdge( tess, reg, e ) ) longjmp(tess->env,1); + } + + /* Relink edges so that ePrev->Onext == e */ + if( ePrev->Onext != e ) { + if ( !tessMeshSplice( tess->mesh, e->Oprev, e ) ) longjmp(tess->env,1); + if ( !tessMeshSplice( tess->mesh, ePrev, e ) ) longjmp(tess->env,1); + } + FinishRegion( tess, regPrev ); /* may change reg->eUp */ + ePrev = reg->eUp; + regPrev = reg; + } + return ePrev; +} + + +static void AddRightEdges( TESStesselator *tess, ActiveRegion *regUp, + TESShalfEdge *eFirst, TESShalfEdge *eLast, TESShalfEdge *eTopLeft, + int cleanUp ) +/* +* Purpose: insert right-going edges into the edge dictionary, and update +* winding numbers and mesh connectivity appropriately. All right-going +* edges share a common origin vOrg. Edges are inserted CCW starting at +* eFirst; the last edge inserted is eLast->Oprev. If vOrg has any +* left-going edges already processed, then eTopLeft must be the edge +* such that an imaginary upward vertical segment from vOrg would be +* contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft +* should be NULL. +*/ +{ + ActiveRegion *reg, *regPrev; + TESShalfEdge *e, *ePrev; + int firstTime = TRUE; + + /* Insert the new right-going edges in the dictionary */ + e = eFirst; + do { + assert( VertLeq( e->Org, e->Dst )); + AddRegionBelow( tess, regUp, e->Sym ); + e = e->Onext; + } while ( e != eLast ); + + /* Walk *all* right-going edges from e->Org, in the dictionary order, + * updating the winding numbers of each region, and re-linking the mesh + * edges to match the dictionary ordering (if necessary). + */ + if( eTopLeft == NULL ) { + eTopLeft = RegionBelow( regUp )->eUp->Rprev; + } + regPrev = regUp; + ePrev = eTopLeft; + for( ;; ) { + reg = RegionBelow( regPrev ); + e = reg->eUp->Sym; + if( e->Org != ePrev->Org ) break; + + if( e->Onext != ePrev ) { + /* Unlink e from its current position, and relink below ePrev */ + if ( !tessMeshSplice( tess->mesh, e->Oprev, e ) ) longjmp(tess->env,1); + if ( !tessMeshSplice( tess->mesh, ePrev->Oprev, e ) ) longjmp(tess->env,1); + } + /* Compute the winding number and "inside" flag for the new regions */ + reg->windingNumber = regPrev->windingNumber - e->winding; + reg->inside = IsWindingInside( tess, reg->windingNumber ); + + /* Check for two outgoing edges with same slope -- process these + * before any intersection tests (see example in tessComputeInterior). + */ + regPrev->dirty = TRUE; + if( ! firstTime && CheckForRightSplice( tess, regPrev )) { + AddWinding( e, ePrev ); + DeleteRegion( tess, regPrev ); + if ( !tessMeshDelete( tess->mesh, ePrev ) ) longjmp(tess->env,1); + } + firstTime = FALSE; + regPrev = reg; + ePrev = e; + } + regPrev->dirty = TRUE; + assert( regPrev->windingNumber - e->winding == reg->windingNumber ); + + if( cleanUp ) { + /* Check for intersections between newly adjacent edges. */ + WalkDirtyRegions( tess, regPrev ); + } +} + + +static void SpliceMergeVertices( TESStesselator *tess, TESShalfEdge *e1, + TESShalfEdge *e2 ) +/* +* Two vertices with idential coordinates are combined into one. +* e1->Org is kept, while e2->Org is discarded. +*/ +{ + if ( !tessMeshSplice( tess->mesh, e1, e2 ) ) longjmp(tess->env,1); +} + +static void VertexWeights( TESSvertex *isect, TESSvertex *org, TESSvertex *dst, + TESSreal *weights ) +/* +* Find some weights which describe how the intersection vertex is +* a linear combination of "org" and "dest". Each of the two edges +* which generated "isect" is allocated 50% of the weight; each edge +* splits the weight between its org and dst according to the +* relative distance to "isect". +*/ +{ + TESSreal t1 = VertL1dist( org, isect ); + TESSreal t2 = VertL1dist( dst, isect ); + + weights[0] = (TESSreal)0.5 * t2 / (t1 + t2); + weights[1] = (TESSreal)0.5 * t1 / (t1 + t2); + isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0]; + isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1]; + isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2]; +} + + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +static void GetIntersectData( TESStesselator *tess, TESSvertex *isect, + TESSvertex *orgUp, TESSvertex *dstUp, + TESSvertex *orgLo, TESSvertex *dstLo ) + /* + * We've computed a new intersection point, now we need a "data" pointer + * from the user so that we can refer to this new vertex in the + * rendering callbacks. + */ +{ + TESSreal weights[4]; + + isect->coords[0] = isect->coords[1] = isect->coords[2] = 0; + isect->idx = TESS_UNDEF; + VertexWeights( isect, orgUp, dstUp, &weights[0] ); + VertexWeights( isect, orgLo, dstLo, &weights[2] ); +} +#pragma GCC diagnostic pop + +static int CheckForRightSplice( TESStesselator *tess, ActiveRegion *regUp ) +/* +* Check the upper and lower edge of "regUp", to make sure that the +* eUp->Org is above eLo, or eLo->Org is below eUp (depending on which +* origin is leftmost). +* +* The main purpose is to splice right-going edges with the same +* dest vertex and nearly identical slopes (ie. we can't distinguish +* the slopes numerically). However the splicing can also help us +* to recover from numerical errors. For example, suppose at one +* point we checked eUp and eLo, and decided that eUp->Org is barely +* above eLo. Then later, we split eLo into two edges (eg. from +* a splice operation like this one). This can change the result of +* our test so that now eUp->Org is incident to eLo, or barely below it. +* We must correct this condition to maintain the dictionary invariants. +* +* One possibility is to check these edges for intersection again +* (ie. CheckForIntersect). This is what we do if possible. However +* CheckForIntersect requires that tess->event lies between eUp and eLo, +* so that it has something to fall back on when the intersection +* calculation gives us an unusable answer. So, for those cases where +* we can't check for intersection, this routine fixes the problem +* by just splicing the offending vertex into the other edge. +* This is a guaranteed solution, no matter how degenerate things get. +* Basically this is a combinatorial solution to a numerical problem. +*/ +{ + ActiveRegion *regLo = RegionBelow(regUp); + TESShalfEdge *eUp = regUp->eUp; + TESShalfEdge *eLo = regLo->eUp; + + if( VertLeq( eUp->Org, eLo->Org )) { + if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE; + + /* eUp->Org appears to be below eLo */ + if( ! VertEq( eUp->Org, eLo->Org )) { + /* Splice eUp->Org into eLo */ + if ( tessMeshSplitEdge( tess->mesh, eLo->Sym ) == NULL) longjmp(tess->env,1); + if ( !tessMeshSplice( tess->mesh, eUp, eLo->Oprev ) ) longjmp(tess->env,1); + regUp->dirty = regLo->dirty = TRUE; + + } else if( eUp->Org != eLo->Org ) { + /* merge the two vertices, discarding eUp->Org */ + pqDelete( tess->pq, eUp->Org->pqHandle ); + SpliceMergeVertices( tess, eLo->Oprev, eUp ); + } + } else { + if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE; + + /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */ + RegionAbove(regUp)->dirty = regUp->dirty = TRUE; + if (tessMeshSplitEdge( tess->mesh, eUp->Sym ) == NULL) longjmp(tess->env,1); + if ( !tessMeshSplice( tess->mesh, eLo->Oprev, eUp ) ) longjmp(tess->env,1); + } + return TRUE; +} + +static int CheckForLeftSplice( TESStesselator *tess, ActiveRegion *regUp ) +/* +* Check the upper and lower edge of "regUp", to make sure that the +* eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which +* destination is rightmost). +* +* Theoretically, this should always be true. However, splitting an edge +* into two pieces can change the results of previous tests. For example, +* suppose at one point we checked eUp and eLo, and decided that eUp->Dst +* is barely above eLo. Then later, we split eLo into two edges (eg. from +* a splice operation like this one). This can change the result of +* the test so that now eUp->Dst is incident to eLo, or barely below it. +* We must correct this condition to maintain the dictionary invariants +* (otherwise new edges might get inserted in the wrong place in the +* dictionary, and bad stuff will happen). +* +* We fix the problem by just splicing the offending vertex into the +* other edge. +*/ +{ + ActiveRegion *regLo = RegionBelow(regUp); + TESShalfEdge *eUp = regUp->eUp; + TESShalfEdge *eLo = regLo->eUp; + TESShalfEdge *e; + + assert( ! VertEq( eUp->Dst, eLo->Dst )); + + if( VertLeq( eUp->Dst, eLo->Dst )) { + if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE; + + /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */ + RegionAbove(regUp)->dirty = regUp->dirty = TRUE; + e = tessMeshSplitEdge( tess->mesh, eUp ); + if (e == NULL) longjmp(tess->env,1); + if ( !tessMeshSplice( tess->mesh, eLo->Sym, e ) ) longjmp(tess->env,1); + e->Lface->inside = regUp->inside; + } else { + if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE; + + /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */ + regUp->dirty = regLo->dirty = TRUE; + e = tessMeshSplitEdge( tess->mesh, eLo ); + if (e == NULL) longjmp(tess->env,1); + if ( !tessMeshSplice( tess->mesh, eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1); + e->Rface->inside = regUp->inside; + } + return TRUE; +} + + +static int CheckForIntersect( TESStesselator *tess, ActiveRegion *regUp ) +/* +* Check the upper and lower edges of the given region to see if +* they intersect. If so, create the intersection and add it +* to the data structures. +* +* Returns TRUE if adding the new intersection resulted in a recursive +* call to AddRightEdges(); in this case all "dirty" regions have been +* checked for intersections, and possibly regUp has been deleted. +*/ +{ + ActiveRegion *regLo = RegionBelow(regUp); + TESShalfEdge *eUp = regUp->eUp; + TESShalfEdge *eLo = regLo->eUp; + TESSvertex *orgUp = eUp->Org; + TESSvertex *orgLo = eLo->Org; + TESSvertex *dstUp = eUp->Dst; + TESSvertex *dstLo = eLo->Dst; + TESSreal tMinUp, tMaxLo; + TESSvertex isect, *orgMin; + TESShalfEdge *e; + + assert( ! VertEq( dstLo, dstUp )); + assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 ); + assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 ); + assert( orgUp != tess->event && orgLo != tess->event ); + assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge ); + + if( orgUp == orgLo ) return FALSE; /* right endpoints are the same */ + + tMinUp = MIN( orgUp->t, dstUp->t ); + tMaxLo = MAX( orgLo->t, dstLo->t ); + if( tMinUp > tMaxLo ) return FALSE; /* t ranges do not overlap */ + + if( VertLeq( orgUp, orgLo )) { + if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE; + } else { + if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE; + } + + /* At this point the edges intersect, at least marginally */ + DebugEvent( tess ); + + tesedgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect ); + /* The following properties are guaranteed: */ + assert( MIN( orgUp->t, dstUp->t ) <= isect.t ); + assert( isect.t <= MAX( orgLo->t, dstLo->t )); + assert( MIN( dstLo->s, dstUp->s ) <= isect.s ); + assert( isect.s <= MAX( orgLo->s, orgUp->s )); + + if( VertLeq( &isect, tess->event )) { + /* The intersection point lies slightly to the left of the sweep line, + * so move it until it''s slightly to the right of the sweep line. + * (If we had perfect numerical precision, this would never happen + * in the first place). The easiest and safest thing to do is + * replace the intersection by tess->event. + */ + isect.s = tess->event->s; + isect.t = tess->event->t; + } + /* Similarly, if the computed intersection lies to the right of the + * rightmost origin (which should rarely happen), it can cause + * unbelievable inefficiency on sufficiently degenerate inputs. + * (If you have the test program, try running test54.d with the + * "X zoom" option turned on). + */ + orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo; + if( VertLeq( orgMin, &isect )) { + isect.s = orgMin->s; + isect.t = orgMin->t; + } + + if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) { + /* Easy case -- intersection at one of the right endpoints */ + (void) CheckForRightSplice( tess, regUp ); + return FALSE; + } + + if( (! VertEq( dstUp, tess->event ) + && EdgeSign( dstUp, tess->event, &isect ) >= 0) + || (! VertEq( dstLo, tess->event ) + && EdgeSign( dstLo, tess->event, &isect ) <= 0 )) + { + /* Very unusual -- the new upper or lower edge would pass on the + * wrong side of the sweep event, or through it. This can happen + * due to very small numerical errors in the intersection calculation. + */ + if( dstLo == tess->event ) { + /* Splice dstLo into eUp, and process the new region(s) */ + if (tessMeshSplitEdge( tess->mesh, eUp->Sym ) == NULL) longjmp(tess->env,1); + if ( !tessMeshSplice( tess->mesh, eLo->Sym, eUp ) ) longjmp(tess->env,1); + regUp = TopLeftRegion( tess, regUp ); + if (regUp == NULL) longjmp(tess->env,1); + eUp = RegionBelow(regUp)->eUp; + FinishLeftRegions( tess, RegionBelow(regUp), regLo ); + AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE ); + return TRUE; + } + if( dstUp == tess->event ) { + /* Splice dstUp into eLo, and process the new region(s) */ + if (tessMeshSplitEdge( tess->mesh, eLo->Sym ) == NULL) longjmp(tess->env,1); + if ( !tessMeshSplice( tess->mesh, eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1); + regLo = regUp; + regUp = TopRightRegion( regUp ); + e = RegionBelow(regUp)->eUp->Rprev; + regLo->eUp = eLo->Oprev; + eLo = FinishLeftRegions( tess, regLo, NULL ); + AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE ); + return TRUE; + } + /* Special case: called from ConnectRightVertex. If either + * edge passes on the wrong side of tess->event, split it + * (and wait for ConnectRightVertex to splice it appropriately). + */ + if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) { + RegionAbove(regUp)->dirty = regUp->dirty = TRUE; + if (tessMeshSplitEdge( tess->mesh, eUp->Sym ) == NULL) longjmp(tess->env,1); + eUp->Org->s = tess->event->s; + eUp->Org->t = tess->event->t; + } + if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) { + regUp->dirty = regLo->dirty = TRUE; + if (tessMeshSplitEdge( tess->mesh, eLo->Sym ) == NULL) longjmp(tess->env,1); + eLo->Org->s = tess->event->s; + eLo->Org->t = tess->event->t; + } + /* leave the rest for ConnectRightVertex */ + return FALSE; + } + + /* General case -- split both edges, splice into new vertex. + * When we do the splice operation, the order of the arguments is + * arbitrary as far as correctness goes. However, when the operation + * creates a new face, the work done is proportional to the size of + * the new face. We expect the faces in the processed part of + * the mesh (ie. eUp->Lface) to be smaller than the faces in the + * unprocessed original contours (which will be eLo->Oprev->Lface). + */ + if (tessMeshSplitEdge( tess->mesh, eUp->Sym ) == NULL) longjmp(tess->env,1); + if (tessMeshSplitEdge( tess->mesh, eLo->Sym ) == NULL) longjmp(tess->env,1); + if ( !tessMeshSplice( tess->mesh, eLo->Oprev, eUp ) ) longjmp(tess->env,1); + eUp->Org->s = isect.s; + eUp->Org->t = isect.t; + eUp->Org->pqHandle = pqInsert( &tess->alloc, tess->pq, eUp->Org ); + if (eUp->Org->pqHandle == INV_HANDLE) { + pqDeletePriorityQ( &tess->alloc, tess->pq ); + tess->pq = NULL; + longjmp(tess->env,1); + } + GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo ); + RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE; + return FALSE; +} + +static void WalkDirtyRegions( TESStesselator *tess, ActiveRegion *regUp ) +/* +* When the upper or lower edge of any region changes, the region is +* marked "dirty". This routine walks through all the dirty regions +* and makes sure that the dictionary invariants are satisfied +* (see the comments at the beginning of this file). Of course +* new dirty regions can be created as we make changes to restore +* the invariants. +*/ +{ + ActiveRegion *regLo = RegionBelow(regUp); + TESShalfEdge *eUp, *eLo; + + for( ;; ) { + /* Find the lowest dirty region (we walk from the bottom up). */ + while( regLo->dirty ) { + regUp = regLo; + regLo = RegionBelow(regLo); + } + if( ! regUp->dirty ) { + regLo = regUp; + regUp = RegionAbove( regUp ); + if( regUp == NULL || ! regUp->dirty ) { + /* We've walked all the dirty regions */ + return; + } + } + regUp->dirty = FALSE; + eUp = regUp->eUp; + eLo = regLo->eUp; + + if( eUp->Dst != eLo->Dst ) { + /* Check that the edge ordering is obeyed at the Dst vertices. */ + if( CheckForLeftSplice( tess, regUp )) { + + /* If the upper or lower edge was marked fixUpperEdge, then + * we no longer need it (since these edges are needed only for + * vertices which otherwise have no right-going edges). + */ + if( regLo->fixUpperEdge ) { + DeleteRegion( tess, regLo ); + if ( !tessMeshDelete( tess->mesh, eLo ) ) longjmp(tess->env,1); + regLo = RegionBelow( regUp ); + eLo = regLo->eUp; + } else if( regUp->fixUpperEdge ) { + DeleteRegion( tess, regUp ); + if ( !tessMeshDelete( tess->mesh, eUp ) ) longjmp(tess->env,1); + regUp = RegionAbove( regLo ); + eUp = regUp->eUp; + } + } + } + if( eUp->Org != eLo->Org ) { + if( eUp->Dst != eLo->Dst + && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge + && (eUp->Dst == tess->event || eLo->Dst == tess->event) ) + { + /* When all else fails in CheckForIntersect(), it uses tess->event + * as the intersection location. To make this possible, it requires + * that tess->event lie between the upper and lower edges, and also + * that neither of these is marked fixUpperEdge (since in the worst + * case it might splice one of these edges into tess->event, and + * violate the invariant that fixable edges are the only right-going + * edge from their associated vertex). + */ + if( CheckForIntersect( tess, regUp )) { + /* WalkDirtyRegions() was called recursively; we're done */ + return; + } + } else { + /* Even though we can't use CheckForIntersect(), the Org vertices + * may violate the dictionary edge ordering. Check and correct this. + */ + (void) CheckForRightSplice( tess, regUp ); + } + } + if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) { + /* A degenerate loop consisting of only two edges -- delete it. */ + AddWinding( eLo, eUp ); + DeleteRegion( tess, regUp ); + if ( !tessMeshDelete( tess->mesh, eUp ) ) longjmp(tess->env,1); + regUp = RegionAbove( regLo ); + } + } +} + + +static void ConnectRightVertex( TESStesselator *tess, ActiveRegion *regUp, + TESShalfEdge *eBottomLeft ) +/* +* Purpose: connect a "right" vertex vEvent (one where all edges go left) +* to the unprocessed portion of the mesh. Since there are no right-going +* edges, two regions (one above vEvent and one below) are being merged +* into one. "regUp" is the upper of these two regions. +* +* There are two reasons for doing this (adding a right-going edge): +* - if the two regions being merged are "inside", we must add an edge +* to keep them separated (the combined region would not be monotone). +* - in any case, we must leave some record of vEvent in the dictionary, +* so that we can merge vEvent with features that we have not seen yet. +* For example, maybe there is a vertical edge which passes just to +* the right of vEvent; we would like to splice vEvent into this edge. +* +* However, we don't want to connect vEvent to just any vertex. We don''t +* want the new edge to cross any other edges; otherwise we will create +* intersection vertices even when the input data had no self-intersections. +* (This is a bad thing; if the user's input data has no intersections, +* we don't want to generate any false intersections ourselves.) +* +* Our eventual goal is to connect vEvent to the leftmost unprocessed +* vertex of the combined region (the union of regUp and regLo). +* But because of unseen vertices with all right-going edges, and also +* new vertices which may be created by edge intersections, we don''t +* know where that leftmost unprocessed vertex is. In the meantime, we +* connect vEvent to the closest vertex of either chain, and mark the region +* as "fixUpperEdge". This flag says to delete and reconnect this edge +* to the next processed vertex on the boundary of the combined region. +* Quite possibly the vertex we connected to will turn out to be the +* closest one, in which case we won''t need to make any changes. +*/ +{ + TESShalfEdge *eNew; + TESShalfEdge *eTopLeft = eBottomLeft->Onext; + ActiveRegion *regLo = RegionBelow(regUp); + TESShalfEdge *eUp = regUp->eUp; + TESShalfEdge *eLo = regLo->eUp; + int degenerate = FALSE; + + if( eUp->Dst != eLo->Dst ) { + (void) CheckForIntersect( tess, regUp ); + } + + /* Possible new degeneracies: upper or lower edge of regUp may pass + * through vEvent, or may coincide with new intersection vertex + */ + if( VertEq( eUp->Org, tess->event )) { + if ( !tessMeshSplice( tess->mesh, eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1); + regUp = TopLeftRegion( tess, regUp ); + if (regUp == NULL) longjmp(tess->env,1); + eTopLeft = RegionBelow( regUp )->eUp; + FinishLeftRegions( tess, RegionBelow(regUp), regLo ); + degenerate = TRUE; + } + if( VertEq( eLo->Org, tess->event )) { + if ( !tessMeshSplice( tess->mesh, eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1); + eBottomLeft = FinishLeftRegions( tess, regLo, NULL ); + degenerate = TRUE; + } + if( degenerate ) { + AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE ); + return; + } + + /* Non-degenerate situation -- need to add a temporary, fixable edge. + * Connect to the closer of eLo->Org, eUp->Org. + */ + if( VertLeq( eLo->Org, eUp->Org )) { + eNew = eLo->Oprev; + } else { + eNew = eUp; + } + eNew = tessMeshConnect( tess->mesh, eBottomLeft->Lprev, eNew ); + if (eNew == NULL) longjmp(tess->env,1); + + /* Prevent cleanup, otherwise eNew might disappear before we've even + * had a chance to mark it as a temporary edge. + */ + AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE ); + eNew->Sym->activeRegion->fixUpperEdge = TRUE; + WalkDirtyRegions( tess, regUp ); +} + +/* Because vertices at exactly the same location are merged together +* before we process the sweep event, some degenerate cases can't occur. +* However if someone eventually makes the modifications required to +* merge features which are close together, the cases below marked +* TOLERANCE_NONZERO will be useful. They were debugged before the +* code to merge identical vertices in the main loop was added. +*/ +#define TOLERANCE_NONZERO FALSE + +static void ConnectLeftDegenerate( TESStesselator *tess, + ActiveRegion *regUp, TESSvertex *vEvent ) +/* +* The event vertex lies exacty on an already-processed edge or vertex. +* Adding the new vertex involves splicing it into the already-processed +* part of the mesh. +*/ +{ + TESShalfEdge *e, *eTopLeft, *eTopRight, *eLast; + ActiveRegion *reg; + + e = regUp->eUp; + if( VertEq( e->Org, vEvent )) { + /* e->Org is an unprocessed vertex - just combine them, and wait + * for e->Org to be pulled from the queue + */ + assert( TOLERANCE_NONZERO ); + SpliceMergeVertices( tess, e, vEvent->anEdge ); + return; + } + + if( ! VertEq( e->Dst, vEvent )) { + /* General case -- splice vEvent into edge e which passes through it */ + if (tessMeshSplitEdge( tess->mesh, e->Sym ) == NULL) longjmp(tess->env,1); + if( regUp->fixUpperEdge ) { + /* This edge was fixable -- delete unused portion of original edge */ + if ( !tessMeshDelete( tess->mesh, e->Onext ) ) longjmp(tess->env,1); + regUp->fixUpperEdge = FALSE; + } + if ( !tessMeshSplice( tess->mesh, vEvent->anEdge, e ) ) longjmp(tess->env,1); + SweepEvent( tess, vEvent ); /* recurse */ + return; + } + + /* vEvent coincides with e->Dst, which has already been processed. + * Splice in the additional right-going edges. + */ + assert( TOLERANCE_NONZERO ); + regUp = TopRightRegion( regUp ); + reg = RegionBelow( regUp ); + eTopRight = reg->eUp->Sym; + eTopLeft = eLast = eTopRight->Onext; + if( reg->fixUpperEdge ) { + /* Here e->Dst has only a single fixable edge going right. + * We can delete it since now we have some real right-going edges. + */ + assert( eTopLeft != eTopRight ); /* there are some left edges too */ + DeleteRegion( tess, reg ); + if ( !tessMeshDelete( tess->mesh, eTopRight ) ) longjmp(tess->env,1); + eTopRight = eTopLeft->Oprev; + } + if ( !tessMeshSplice( tess->mesh, vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1); + if( ! EdgeGoesLeft( eTopLeft )) { + /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */ + eTopLeft = NULL; + } + AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE ); +} + + +static void ConnectLeftVertex( TESStesselator *tess, TESSvertex *vEvent ) +/* +* Purpose: connect a "left" vertex (one where both edges go right) +* to the processed portion of the mesh. Let R be the active region +* containing vEvent, and let U and L be the upper and lower edge +* chains of R. There are two possibilities: +* +* - the normal case: split R into two regions, by connecting vEvent to +* the rightmost vertex of U or L lying to the left of the sweep line +* +* - the degenerate case: if vEvent is close enough to U or L, we +* merge vEvent into that edge chain. The subcases are: +* - merging with the rightmost vertex of U or L +* - merging with the active edge of U or L +* - merging with an already-processed portion of U or L +*/ +{ + ActiveRegion *regUp, *regLo, *reg; + TESShalfEdge *eUp, *eLo, *eNew; + ActiveRegion tmp; + + /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */ + + /* Get a pointer to the active region containing vEvent */ + tmp.eUp = vEvent->anEdge->Sym; + /* __GL_DICTLISTKEY */ /* tessDictListSearch */ + regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp )); + regLo = RegionBelow( regUp ); + if( !regLo ) { + // This may happen if the input polygon is coplanar. + return; + } + eUp = regUp->eUp; + eLo = regLo->eUp; + + /* Try merging with U or L first */ + if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) { + ConnectLeftDegenerate( tess, regUp, vEvent ); + return; + } + + /* Connect vEvent to rightmost processed vertex of either chain. + * e->Dst is the vertex that we will connect to vEvent. + */ + reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo; + + if( regUp->inside || reg->fixUpperEdge) { + if( reg == regUp ) { + eNew = tessMeshConnect( tess->mesh, vEvent->anEdge->Sym, eUp->Lnext ); + if (eNew == NULL) longjmp(tess->env,1); + } else { + TESShalfEdge *tempHalfEdge= tessMeshConnect( tess->mesh, eLo->Dnext, vEvent->anEdge); + if (tempHalfEdge == NULL) longjmp(tess->env,1); + + eNew = tempHalfEdge->Sym; + } + if( reg->fixUpperEdge ) { + if ( !FixUpperEdge( tess, reg, eNew ) ) longjmp(tess->env,1); + } else { + ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew )); + } + SweepEvent( tess, vEvent ); + } else { + /* The new vertex is in a region which does not belong to the polygon. + * We don''t need to connect this vertex to the rest of the mesh. + */ + AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE ); + } +} + + +static void SweepEvent( TESStesselator *tess, TESSvertex *vEvent ) +/* +* Does everything necessary when the sweep line crosses a vertex. +* Updates the mesh and the edge dictionary. +*/ +{ + ActiveRegion *regUp, *reg; + TESShalfEdge *e, *eTopLeft, *eBottomLeft; + + tess->event = vEvent; /* for access in EdgeLeq() */ + DebugEvent( tess ); + + /* Check if this vertex is the right endpoint of an edge that is + * already in the dictionary. In this case we don't need to waste + * time searching for the location to insert new edges. + */ + e = vEvent->anEdge; + while( e->activeRegion == NULL ) { + e = e->Onext; + if( e == vEvent->anEdge ) { + /* All edges go right -- not incident to any processed edges */ + ConnectLeftVertex( tess, vEvent ); + return; + } + } + + /* Processing consists of two phases: first we "finish" all the + * active regions where both the upper and lower edges terminate + * at vEvent (ie. vEvent is closing off these regions). + * We mark these faces "inside" or "outside" the polygon according + * to their winding number, and delete the edges from the dictionary. + * This takes care of all the left-going edges from vEvent. + */ + regUp = TopLeftRegion( tess, e->activeRegion ); + if (regUp == NULL) longjmp(tess->env,1); + reg = RegionBelow( regUp ); + eTopLeft = reg->eUp; + eBottomLeft = FinishLeftRegions( tess, reg, NULL ); + + /* Next we process all the right-going edges from vEvent. This + * involves adding the edges to the dictionary, and creating the + * associated "active regions" which record information about the + * regions between adjacent dictionary edges. + */ + if( eBottomLeft->Onext == eTopLeft ) { + /* No right-going edges -- add a temporary "fixable" edge */ + ConnectRightVertex( tess, regUp, eBottomLeft ); + } else { + AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE ); + } +} + + +/* Make the sentinel coordinates big enough that they will never be +* merged with real input features. +*/ + +static void AddSentinel( TESStesselator *tess, TESSreal smin, TESSreal smax, TESSreal t ) +/* +* We add two sentinel edges above and below all other edges, +* to avoid special cases at the top and bottom. +*/ +{ + TESShalfEdge *e; + ActiveRegion *reg = (ActiveRegion *)bucketAlloc( tess->regionPool ); + if (reg == NULL) longjmp(tess->env,1); + + e = tessMeshMakeEdge( tess->mesh ); + if (e == NULL) longjmp(tess->env,1); + + e->Org->s = smax; + e->Org->t = t; + e->Dst->s = smin; + e->Dst->t = t; + tess->event = e->Dst; /* initialize it */ + + reg->eUp = e; + reg->windingNumber = 0; + reg->inside = FALSE; + reg->fixUpperEdge = FALSE; + reg->sentinel = TRUE; + reg->dirty = FALSE; + reg->nodeUp = dictInsert( tess->dict, reg ); + if (reg->nodeUp == NULL) longjmp(tess->env,1); +} + + +static void InitEdgeDict( TESStesselator *tess ) +/* +* We maintain an ordering of edge intersections with the sweep line. +* This order is maintained in a dynamic dictionary. +*/ +{ + TESSreal w, h; + TESSreal smin, smax, tmin, tmax; + + tess->dict = dictNewDict( &tess->alloc, tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq ); + if (tess->dict == NULL) longjmp(tess->env,1); + + w = (tess->bmax[0] - tess->bmin[0]); + h = (tess->bmax[1] - tess->bmin[1]); + + smin = tess->bmin[0] - w; + smax = tess->bmax[0] + w; + tmin = tess->bmin[1] - h; + tmax = tess->bmax[1] + h; + + AddSentinel( tess, smin, smax, tmin ); + AddSentinel( tess, smin, smax, tmax ); +} + + +static void DoneEdgeDict( TESStesselator *tess ) +{ + ActiveRegion *reg; + int fixedEdges = 0; + + while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) { + /* + * At the end of all processing, the dictionary should contain + * only the two sentinel edges, plus at most one "fixable" edge + * created by ConnectRightVertex(). + */ + if( ! reg->sentinel ) { + assert( reg->fixUpperEdge ); + assert( ++fixedEdges == 1 ); + } + assert( reg->windingNumber == 0 ); + DeleteRegion( tess, reg ); + /* tessMeshDelete( reg->eUp );*/ + } + dictDeleteDict( &tess->alloc, tess->dict ); +} + + +static void RemoveDegenerateEdges( TESStesselator *tess ) +/* +* Remove zero-length edges, and contours with fewer than 3 vertices. +*/ +{ + TESShalfEdge *e, *eNext, *eLnext; + TESShalfEdge *eHead = &tess->mesh->eHead; + + /*LINTED*/ + for( e = eHead->next; e != eHead; e = eNext ) { + eNext = e->next; + eLnext = e->Lnext; + + if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) { + /* Zero-length edge, contour has at least 3 edges */ + + SpliceMergeVertices( tess, eLnext, e ); /* deletes e->Org */ + if ( !tessMeshDelete( tess->mesh, e ) ) longjmp(tess->env,1); /* e is a self-loop */ + e = eLnext; + eLnext = e->Lnext; + } + if( eLnext->Lnext == e ) { + /* Degenerate contour (one or two edges) */ + + if( eLnext != e ) { + if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; } + if ( !tessMeshDelete( tess->mesh, eLnext ) ) longjmp(tess->env,1); + } + if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; } + if ( !tessMeshDelete( tess->mesh, e ) ) longjmp(tess->env,1); + } + } +} + +static int InitPriorityQ( TESStesselator *tess ) +/* +* Insert all vertices into the priority queue which determines the +* order in which vertices cross the sweep line. +*/ +{ + PriorityQ *pq; + TESSvertex *v, *vHead; + int vertexCount = 0; + + vHead = &tess->mesh->vHead; + for( v = vHead->next; v != vHead; v = v->next ) { + vertexCount++; + } + /* Make sure there is enough space for sentinels. */ + vertexCount += MAX( 8, tess->alloc.extraVertices ); + + pq = tess->pq = pqNewPriorityQ( &tess->alloc, vertexCount, (int (*)(PQkey, PQkey)) tesvertLeq ); + if (pq == NULL) return 0; + + vHead = &tess->mesh->vHead; + for( v = vHead->next; v != vHead; v = v->next ) { + v->pqHandle = pqInsert( &tess->alloc, pq, v ); + if (v->pqHandle == INV_HANDLE) + break; + } + if (v != vHead || !pqInit( &tess->alloc, pq ) ) { + pqDeletePriorityQ( &tess->alloc, tess->pq ); + tess->pq = NULL; + return 0; + } + + return 1; +} + + +static void DonePriorityQ( TESStesselator *tess ) +{ + pqDeletePriorityQ( &tess->alloc, tess->pq ); +} + + +static int RemoveDegenerateFaces( TESStesselator *tess, TESSmesh *mesh ) +/* +* Delete any degenerate faces with only two edges. WalkDirtyRegions() +* will catch almost all of these, but it won't catch degenerate faces +* produced by splice operations on already-processed edges. +* The two places this can happen are in FinishLeftRegions(), when +* we splice in a "temporary" edge produced by ConnectRightVertex(), +* and in CheckForLeftSplice(), where we splice already-processed +* edges to ensure that our dictionary invariants are not violated +* by numerical errors. +* +* In both these cases it is *very* dangerous to delete the offending +* edge at the time, since one of the routines further up the stack +* will sometimes be keeping a pointer to that edge. +*/ +{ + TESSface *f, *fNext; + TESShalfEdge *e; + + /*LINTED*/ + for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) { + fNext = f->next; + e = f->anEdge; + assert( e->Lnext != e ); + + if( e->Lnext->Lnext == e ) { + /* A face with only two edges */ + AddWinding( e->Onext, e ); + if ( !tessMeshDelete( tess->mesh, e ) ) return 0; + } + } + return 1; +} + +int tessComputeInterior( TESStesselator *tess ) +/* +* tessComputeInterior( tess ) computes the planar arrangement specified +* by the given contours, and further subdivides this arrangement +* into regions. Each region is marked "inside" if it belongs +* to the polygon, according to the rule given by tess->windingRule. +* Each interior region is guaranteed be monotone. +*/ +{ + TESSvertex *v, *vNext; + + /* Each vertex defines an event for our sweep line. Start by inserting + * all the vertices in a priority queue. Events are processed in + * lexicographic order, ie. + * + * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y) + */ + RemoveDegenerateEdges( tess ); + if ( !InitPriorityQ( tess ) ) return 0; /* if error */ + InitEdgeDict( tess ); + + while( (v = (TESSvertex *)pqExtractMin( tess->pq )) != NULL ) { + for( ;; ) { + vNext = (TESSvertex *)pqMinimum( tess->pq ); + if( vNext == NULL || ! VertEq( vNext, v )) break; + + /* Merge together all vertices at exactly the same location. + * This is more efficient than processing them one at a time, + * simplifies the code (see ConnectLeftDegenerate), and is also + * important for correct handling of certain degenerate cases. + * For example, suppose there are two identical edges A and B + * that belong to different contours (so without this code they would + * be processed by separate sweep events). Suppose another edge C + * crosses A and B from above. When A is processed, we split it + * at its intersection point with C. However this also splits C, + * so when we insert B we may compute a slightly different + * intersection point. This might leave two edges with a small + * gap between them. This kind of error is especially obvious + * when using boundary extraction (TESS_BOUNDARY_ONLY). + */ + vNext = (TESSvertex *)pqExtractMin( tess->pq ); + SpliceMergeVertices( tess, v->anEdge, vNext->anEdge ); + } + SweepEvent( tess, v ); + } + + /* Set tess->event for debugging purposes */ + tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org; + DebugEvent( tess ); + DoneEdgeDict( tess ); + DonePriorityQ( tess ); + + if ( !RemoveDegenerateFaces( tess, tess->mesh ) ) return 0; + tessMeshCheckMesh( tess->mesh ); + + return 1; +} diff --git a/src/libtess2/sweep.h b/src/libtess2/sweep.h new file mode 100755 index 000000000..95bd65a49 --- /dev/null +++ b/src/libtess2/sweep.h @@ -0,0 +1,74 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +#ifndef SWEEP_H +#define SWEEP_H + +#include "mesh.h" + +/* tessComputeInterior( tess ) computes the planar arrangement specified +* by the given contours, and further subdivides this arrangement +* into regions. Each region is marked "inside" if it belongs +* to the polygon, according to the rule given by tess->windingRule. +* Each interior region is guaranteed be monotone. +*/ +int tessComputeInterior( TESStesselator *tess ); + + +/* The following is here *only* for access by debugging routines */ + +#include "dict.h" + +/* For each pair of adjacent edges crossing the sweep line, there is +* an ActiveRegion to represent the region between them. The active +* regions are kept in sorted order in a dynamic dictionary. As the +* sweep line crosses each vertex, we update the affected regions. +*/ + +struct ActiveRegion { + TESShalfEdge *eUp; /* upper edge, directed right to left */ + DictNode *nodeUp; /* dictionary node corresponding to eUp */ + int windingNumber; /* used to determine which regions are + * inside the polygon */ + int inside; /* is this region inside the polygon? */ + int sentinel; /* marks fake edges at t = +/-infinity */ + int dirty; /* marks regions where the upper or lower + * edge has changed, but we haven't checked + * whether they intersect yet */ + int fixUpperEdge; /* marks temporary edges introduced when + * we process a "right vertex" (one without + * any edges leaving to the right) */ +}; + +#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp))) +#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp))) + +#endif diff --git a/src/libtess2/tess.c b/src/libtess2/tess.c new file mode 100755 index 000000000..80c5b70f4 --- /dev/null +++ b/src/libtess2/tess.c @@ -0,0 +1,960 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +#include +#include +#include +#include "bucketalloc.h" +#include "tess.h" +#include "mesh.h" +#include "sweep.h" +#include "geom.h" +#include +#include +#include + +#define TRUE 1 +#define FALSE 0 + +#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2]) + +#define ABS(x) ((x) < 0 ? -(x) : (x)) + +static int LongAxis( TESSreal v[3] ) +{ + int i = 0; + + if( ABS(v[1]) > ABS(v[0]) ) { i = 1; } + if( ABS(v[2]) > ABS(v[i]) ) { i = 2; } + return i; +} + +static void ComputeNormal( TESStesselator *tess, TESSreal norm[3] ) +{ + TESSvertex *v, *v1, *v2; + TESSreal c, tLen2, maxLen2; + TESSreal maxVal[3], minVal[3], d1[3], d2[3], tNorm[3]; + TESSvertex *maxVert[3], *minVert[3]; + TESSvertex *vHead = &tess->mesh->vHead; + int i; + + v = vHead->next; + for( i = 0; i < 3; ++i ) { + c = v->coords[i]; + minVal[i] = c; + minVert[i] = v; + maxVal[i] = c; + maxVert[i] = v; + } + + for( v = vHead->next; v != vHead; v = v->next ) { + for( i = 0; i < 3; ++i ) { + c = v->coords[i]; + if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; } + if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; } + } + } + + /* Find two vertices separated by at least 1/sqrt(3) of the maximum + * distance between any two vertices + */ + i = 0; + if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; } + if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; } + if( minVal[i] >= maxVal[i] ) { + /* All vertices are the same -- normal doesn't matter */ + norm[0] = 0; norm[1] = 0; norm[2] = 1; + return; + } + + /* Look for a third vertex which forms the triangle with maximum area + * (Length of normal == twice the triangle area) + */ + maxLen2 = 0; + v1 = minVert[i]; + v2 = maxVert[i]; + d1[0] = v1->coords[0] - v2->coords[0]; + d1[1] = v1->coords[1] - v2->coords[1]; + d1[2] = v1->coords[2] - v2->coords[2]; + for( v = vHead->next; v != vHead; v = v->next ) { + d2[0] = v->coords[0] - v2->coords[0]; + d2[1] = v->coords[1] - v2->coords[1]; + d2[2] = v->coords[2] - v2->coords[2]; + tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1]; + tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2]; + tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0]; + tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2]; + if( tLen2 > maxLen2 ) { + maxLen2 = tLen2; + norm[0] = tNorm[0]; + norm[1] = tNorm[1]; + norm[2] = tNorm[2]; + } + } + + if( maxLen2 <= 0 ) { + /* All points lie on a single line -- any decent normal will do */ + norm[0] = norm[1] = norm[2] = 0; + norm[LongAxis(d1)] = 1; + } +} + + +static void CheckOrientation( TESStesselator *tess ) +{ + TESSreal area; + TESSface *f, *fHead = &tess->mesh->fHead; + TESSvertex *v, *vHead = &tess->mesh->vHead; + TESShalfEdge *e; + + /* When we compute the normal automatically, we choose the orientation + * so that the the sum of the signed areas of all contours is non-negative. + */ + area = 0; + for( f = fHead->next; f != fHead; f = f->next ) { + e = f->anEdge; + if( e->winding <= 0 ) continue; + do { + area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t); + e = e->Lnext; + } while( e != f->anEdge ); + } + if( area < 0 ) { + /* Reverse the orientation by flipping all the t-coordinates */ + for( v = vHead->next; v != vHead; v = v->next ) { + v->t = - v->t; + } + tess->tUnit[0] = - tess->tUnit[0]; + tess->tUnit[1] = - tess->tUnit[1]; + tess->tUnit[2] = - tess->tUnit[2]; + } +} + +#ifdef FOR_TRITE_TEST_PROGRAM +#include +extern int RandomSweep; +#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0) +#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0) +#else +#if defined(SLANTED_SWEEP) +/* The "feature merging" is not intended to be complete. There are +* special cases where edges are nearly parallel to the sweep line +* which are not implemented. The algorithm should still behave +* robustly (ie. produce a reasonable tesselation) in the presence +* of such edges, however it may miss features which could have been +* merged. We could minimize this effect by choosing the sweep line +* direction to be something unusual (ie. not parallel to one of the +* coordinate axes). +*/ +#define S_UNIT_X (TESSreal)0.50941539564955385 /* Pre-normalized */ +#define S_UNIT_Y (TESSreal)0.86052074622010633 +#else +#define S_UNIT_X (TESSreal)1.0 +#define S_UNIT_Y (TESSreal)0.0 +#endif +#endif + +/* Determine the polygon normal and project vertices onto the plane +* of the polygon. +*/ +void tessProjectPolygon( TESStesselator *tess ) +{ + TESSvertex *v, *vHead = &tess->mesh->vHead; + TESSreal norm[3]; + TESSreal *sUnit, *tUnit; + int i, first, computedNormal = FALSE; + + norm[0] = tess->normal[0]; + norm[1] = tess->normal[1]; + norm[2] = tess->normal[2]; + if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { + ComputeNormal( tess, norm ); + computedNormal = TRUE; + } + sUnit = tess->sUnit; + tUnit = tess->tUnit; + i = LongAxis( norm ); + +#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT) + /* Choose the initial sUnit vector to be approximately perpendicular + * to the normal. + */ + Normalize( norm ); + + sUnit[i] = 0; + sUnit[(i+1)%3] = S_UNIT_X; + sUnit[(i+2)%3] = S_UNIT_Y; + + /* Now make it exactly perpendicular */ + w = Dot( sUnit, norm ); + sUnit[0] -= w * norm[0]; + sUnit[1] -= w * norm[1]; + sUnit[2] -= w * norm[2]; + Normalize( sUnit ); + + /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */ + tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1]; + tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2]; + tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0]; + Normalize( tUnit ); +#else + /* Project perpendicular to a coordinate axis -- better numerically */ + sUnit[i] = 0; + sUnit[(i+1)%3] = S_UNIT_X; + sUnit[(i+2)%3] = S_UNIT_Y; + + tUnit[i] = 0; + tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y; + tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X; +#endif + + /* Project the vertices onto the sweep plane */ + for( v = vHead->next; v != vHead; v = v->next ) + { + v->s = Dot( v->coords, sUnit ); + v->t = Dot( v->coords, tUnit ); + } + if( computedNormal ) { + CheckOrientation( tess ); + } + + /* Compute ST bounds. */ + first = 1; + for( v = vHead->next; v != vHead; v = v->next ) + { + if (first) + { + tess->bmin[0] = tess->bmax[0] = v->s; + tess->bmin[1] = tess->bmax[1] = v->t; + first = 0; + } + else + { + if (v->s < tess->bmin[0]) tess->bmin[0] = v->s; + if (v->s > tess->bmax[0]) tess->bmax[0] = v->s; + if (v->t < tess->bmin[1]) tess->bmin[1] = v->t; + if (v->t > tess->bmax[1]) tess->bmax[1] = v->t; + } + } +} + +#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ + eDst->Sym->winding += eSrc->Sym->winding) + +/* tessMeshTessellateMonoRegion( face ) tessellates a monotone region +* (what else would it do??) The region must consist of a single +* loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this +* case means that any vertical line intersects the interior of the +* region in a single interval. +* +* Tessellation consists of adding interior edges (actually pairs of +* half-edges), to split the region into non-overlapping triangles. +* +* The basic idea is explained in Preparata and Shamos (which I don''t +* have handy right now), although their implementation is more +* complicated than this one. The are two edge chains, an upper chain +* and a lower chain. We process all vertices from both chains in order, +* from right to left. +* +* The algorithm ensures that the following invariant holds after each +* vertex is processed: the untessellated region consists of two +* chains, where one chain (say the upper) is a single edge, and +* the other chain is concave. The left vertex of the single edge +* is always to the left of all vertices in the concave chain. +* +* Each step consists of adding the rightmost unprocessed vertex to one +* of the two chains, and forming a fan of triangles from the rightmost +* of two chain endpoints. Determining whether we can add each triangle +* to the fan is a simple orientation test. By making the fan as large +* as possible, we restore the invariant (check it yourself). +*/ +int tessMeshTessellateMonoRegion( TESSmesh *mesh, TESSface *face ) +{ + TESShalfEdge *up, *lo; + + /* All edges are oriented CCW around the boundary of the region. + * First, find the half-edge whose origin vertex is rightmost. + * Since the sweep goes from left to right, face->anEdge should + * be close to the edge we want. + */ + up = face->anEdge; + assert( up->Lnext != up && up->Lnext->Lnext != up ); + + for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev ) + ; + for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext ) + ; + lo = up->Lprev; + + while( up->Lnext != lo ) { + if( VertLeq( up->Dst, lo->Org )) { + /* up->Dst is on the left. It is safe to form triangles from lo->Org. + * The EdgeGoesLeft test guarantees progress even when some triangles + * are CW, given that the upper and lower chains are truly monotone. + */ + while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext ) + || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) { + TESShalfEdge *tempHalfEdge= tessMeshConnect( mesh, lo->Lnext, lo ); + if (tempHalfEdge == NULL) return 0; + lo = tempHalfEdge->Sym; + } + lo = lo->Lprev; + } else { + /* lo->Org is on the left. We can make CCW triangles from up->Dst. */ + while( lo->Lnext != up && (EdgeGoesRight( up->Lprev ) + || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) { + TESShalfEdge *tempHalfEdge= tessMeshConnect( mesh, up, up->Lprev ); + if (tempHalfEdge == NULL) return 0; + up = tempHalfEdge->Sym; + } + up = up->Lnext; + } + } + + /* Now lo->Org == up->Dst == the leftmost vertex. The remaining region + * can be tessellated in a fan from this leftmost vertex. + */ + assert( lo->Lnext != up ); + while( lo->Lnext->Lnext != up ) { + TESShalfEdge *tempHalfEdge= tessMeshConnect( mesh, lo->Lnext, lo ); + if (tempHalfEdge == NULL) return 0; + lo = tempHalfEdge->Sym; + } + + return 1; +} + + +/* tessMeshTessellateInterior( mesh ) tessellates each region of +* the mesh which is marked "inside" the polygon. Each such region +* must be monotone. +*/ +int tessMeshTessellateInterior( TESSmesh *mesh ) +{ + TESSface *f, *next; + + /*LINTED*/ + for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { + /* Make sure we don''t try to tessellate the new triangles. */ + next = f->next; + if( f->inside ) { + if ( !tessMeshTessellateMonoRegion( mesh, f ) ) return 0; + } + } + + return 1; +} + + +/* tessMeshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces +* which are not marked "inside" the polygon. Since further mesh operations +* on NULL faces are not allowed, the main purpose is to clean up the +* mesh so that exterior loops are not represented in the data structure. +*/ +void tessMeshDiscardExterior( TESSmesh *mesh ) +{ + TESSface *f, *next; + + /*LINTED*/ + for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { + /* Since f will be destroyed, save its next pointer. */ + next = f->next; + if( ! f->inside ) { + tessMeshZapFace( mesh, f ); + } + } +} + +/* tessMeshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the +* winding numbers on all edges so that regions marked "inside" the +* polygon have a winding number of "value", and regions outside +* have a winding number of 0. +* +* If keepOnlyBoundary is TRUE, it also deletes all edges which do not +* separate an interior region from an exterior one. +*/ +int tessMeshSetWindingNumber( TESSmesh *mesh, int value, + int keepOnlyBoundary ) +{ + TESShalfEdge *e, *eNext; + + for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { + eNext = e->next; + if( e->Rface->inside != e->Lface->inside ) { + + /* This is a boundary edge (one side is interior, one is exterior). */ + e->winding = (e->Lface->inside) ? value : -value; + } else { + + /* Both regions are interior, or both are exterior. */ + if( ! keepOnlyBoundary ) { + e->winding = 0; + } else { + if ( !tessMeshDelete( mesh, e ) ) return 0; + } + } + } + return 1; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +void* heapAlloc( void* userData, unsigned int size ) +{ + return malloc( size ); +} + +void* heapRealloc( void *userData, void* ptr, unsigned int size ) +{ + return realloc( ptr, size ); +} + +void heapFree( void* userData, void* ptr ) +{ + free( ptr ); +} +#pragma GCC diagnostic pop + +static TESSalloc defaulAlloc = +{ + heapAlloc, + heapRealloc, + heapFree, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + +TESStesselator* tessNewTess( TESSalloc* alloc ) +{ + TESStesselator* tess; + + if (alloc == NULL) + alloc = &defaulAlloc; + + /* Only initialize fields which can be changed by the api. Other fields + * are initialized where they are used. + */ + + tess = (TESStesselator *)alloc->memalloc( alloc->userData, sizeof( TESStesselator )); + if ( tess == NULL ) { + return 0; /* out of memory */ + } + tess->alloc = *alloc; + /* Check and set defaults. */ + if (tess->alloc.meshEdgeBucketSize == 0) + tess->alloc.meshEdgeBucketSize = 512; + if (tess->alloc.meshVertexBucketSize == 0) + tess->alloc.meshVertexBucketSize = 512; + if (tess->alloc.meshFaceBucketSize == 0) + tess->alloc.meshFaceBucketSize = 256; + if (tess->alloc.dictNodeBucketSize == 0) + tess->alloc.dictNodeBucketSize = 512; + if (tess->alloc.regionBucketSize == 0) + tess->alloc.regionBucketSize = 256; + + tess->normal[0] = 0; + tess->normal[1] = 0; + tess->normal[2] = 0; + + tess->bmin[0] = 0; + tess->bmin[1] = 0; + tess->bmax[0] = 0; + tess->bmax[1] = 0; + + tess->windingRule = TESS_WINDING_ODD; + + if (tess->alloc.regionBucketSize < 16) + tess->alloc.regionBucketSize = 16; + if (tess->alloc.regionBucketSize > 4096) + tess->alloc.regionBucketSize = 4096; + tess->regionPool = createBucketAlloc( &tess->alloc, "Regions", + sizeof(ActiveRegion), tess->alloc.regionBucketSize ); + + // Initialize to begin polygon. + tess->mesh = NULL; + + tess->outOfMemory = 0; + tess->vertexIndexCounter = 0; + + tess->vertices = 0; + tess->vertexIndices = 0; + tess->vertexCount = 0; + tess->elements = 0; + tess->elementCount = 0; + + return tess; +} + +void tessDeleteTess( TESStesselator *tess ) +{ + + struct TESSalloc alloc = tess->alloc; + + deleteBucketAlloc( tess->regionPool ); + + if( tess->mesh != NULL ) { + tessMeshDeleteMesh( &alloc, tess->mesh ); + tess->mesh = NULL; + } + if (tess->vertices != NULL) { + alloc.memfree( alloc.userData, tess->vertices ); + tess->vertices = 0; + } + if (tess->vertexIndices != NULL) { + alloc.memfree( alloc.userData, tess->vertexIndices ); + tess->vertexIndices = 0; + } + if (tess->elements != NULL) { + alloc.memfree( alloc.userData, tess->elements ); + tess->elements = 0; + } + + alloc.memfree( alloc.userData, tess ); +} + + +static TESSindex GetNeighbourFace(TESShalfEdge* edge) +{ + if (!edge->Rface) + return TESS_UNDEF; + if (!edge->Rface->inside) + return TESS_UNDEF; + return edge->Rface->n; +} + +void OutputPolymesh( TESStesselator *tess, TESSmesh *mesh, int elementType, int polySize, int vertexSize ) +{ + TESSvertex* v = 0; + TESSface* f = 0; + TESShalfEdge* edge = 0; + int maxFaceCount = 0; + int maxVertexCount = 0; + int faceVerts, i; + TESSindex *elements = 0; + TESSreal *vert; + + // Assume that the input data is triangles now. + // Try to merge as many polygons as possible + if (polySize > 3) + { + if (!tessMeshMergeConvexFaces( mesh, polySize )) + { + tess->outOfMemory = 1; + return; + } + } + + // Mark unused + for ( v = mesh->vHead.next; v != &mesh->vHead; v = v->next ) + v->n = TESS_UNDEF; + + // Create unique IDs for all vertices and faces. + for ( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) + { + f->n = TESS_UNDEF; + if( !f->inside ) continue; + + edge = f->anEdge; + faceVerts = 0; + do + { + v = edge->Org; + if ( v->n == TESS_UNDEF ) + { + v->n = maxVertexCount; + maxVertexCount++; + } + faceVerts++; + edge = edge->Lnext; + } + while (edge != f->anEdge); + + assert( faceVerts <= polySize ); + + f->n = maxFaceCount; + ++maxFaceCount; + } + + tess->elementCount = maxFaceCount; + if (elementType == TESS_CONNECTED_POLYGONS) + maxFaceCount *= 2; + tess->elements = (TESSindex*)tess->alloc.memalloc( tess->alloc.userData, + sizeof(TESSindex) * maxFaceCount * polySize ); + if (!tess->elements) + { + tess->outOfMemory = 1; + return; + } + + tess->vertexCount = maxVertexCount; + tess->vertices = (TESSreal*)tess->alloc.memalloc( tess->alloc.userData, + sizeof(TESSreal) * tess->vertexCount * vertexSize ); + if (!tess->vertices) + { + tess->outOfMemory = 1; + return; + } + + tess->vertexIndices = (TESSindex*)tess->alloc.memalloc( tess->alloc.userData, + sizeof(TESSindex) * tess->vertexCount ); + if (!tess->vertexIndices) + { + tess->outOfMemory = 1; + return; + } + + // Output vertices. + for ( v = mesh->vHead.next; v != &mesh->vHead; v = v->next ) + { + if ( v->n != TESS_UNDEF ) + { + // Store coordinate + vert = &tess->vertices[v->n*vertexSize]; + vert[0] = v->coords[0]; + vert[1] = v->coords[1]; + if ( vertexSize > 2 ) + vert[2] = v->coords[2]; + // Store vertex index. + tess->vertexIndices[v->n] = v->idx; + } + } + + // Output indices. + elements = tess->elements; + for ( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) + { + if ( !f->inside ) continue; + + // Store polygon + edge = f->anEdge; + faceVerts = 0; + do + { + v = edge->Org; + *elements++ = v->n; + faceVerts++; + edge = edge->Lnext; + } + while (edge != f->anEdge); + // Fill unused. + for (i = faceVerts; i < polySize; ++i) + *elements++ = TESS_UNDEF; + + // Store polygon connectivity + if ( elementType == TESS_CONNECTED_POLYGONS ) + { + edge = f->anEdge; + do + { + *elements++ = GetNeighbourFace( edge ); + edge = edge->Lnext; + } + while (edge != f->anEdge); + // Fill unused. + for (i = faceVerts; i < polySize; ++i) + *elements++ = TESS_UNDEF; + } + } +} + +void OutputContours( TESStesselator *tess, TESSmesh *mesh, int vertexSize ) +{ + TESSface *f = 0; + TESShalfEdge *edge = 0; + TESShalfEdge *start = 0; + TESSreal *verts = 0; + TESSindex *elements = 0; + TESSindex *vertInds = 0; + int startVert = 0; + int vertCount = 0; + + tess->vertexCount = 0; + tess->elementCount = 0; + + for ( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) + { + if ( !f->inside ) continue; + + start = edge = f->anEdge; + do + { + ++tess->vertexCount; + edge = edge->Lnext; + } + while ( edge != start ); + + ++tess->elementCount; + } + + tess->elements = (TESSindex*)tess->alloc.memalloc( tess->alloc.userData, + sizeof(TESSindex) * tess->elementCount * 2 ); + if (!tess->elements) + { + tess->outOfMemory = 1; + return; + } + + tess->vertices = (TESSreal*)tess->alloc.memalloc( tess->alloc.userData, + sizeof(TESSreal) * tess->vertexCount * vertexSize ); + if (!tess->vertices) + { + tess->outOfMemory = 1; + return; + } + + tess->vertexIndices = (TESSindex*)tess->alloc.memalloc( tess->alloc.userData, + sizeof(TESSindex) * tess->vertexCount ); + if (!tess->vertexIndices) + { + tess->outOfMemory = 1; + return; + } + + verts = tess->vertices; + elements = tess->elements; + vertInds = tess->vertexIndices; + + startVert = 0; + + for ( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) + { + if ( !f->inside ) continue; + + vertCount = 0; + start = edge = f->anEdge; + do + { + *verts++ = edge->Org->coords[0]; + *verts++ = edge->Org->coords[1]; + if ( vertexSize > 2 ) + *verts++ = edge->Org->coords[2]; + *vertInds++ = edge->Org->idx; + ++vertCount; + edge = edge->Lnext; + } + while ( edge != start ); + + elements[0] = startVert; + elements[1] = vertCount; + elements += 2; + + startVert += vertCount; + } +} + +void tessAddContour( TESStesselator *tess, int size, const void* vertices, + int stride, int numVertices ) +{ + const unsigned char *src = (const unsigned char*)vertices; + TESShalfEdge *e; + int i; + + if ( tess->mesh == NULL ) + tess->mesh = tessMeshNewMesh( &tess->alloc ); + if ( tess->mesh == NULL ) { + tess->outOfMemory = 1; + return; + } + + if ( size < 2 ) + size = 2; + if ( size > 3 ) + size = 3; + + e = NULL; + + for( i = 0; i < numVertices; ++i ) + { + const TESSreal* coords = (const TESSreal*)src; + src += stride; + + if( e == NULL ) { + /* Make a self-loop (one vertex, one edge). */ + e = tessMeshMakeEdge( tess->mesh ); + if ( e == NULL ) { + tess->outOfMemory = 1; + return; + } + if ( !tessMeshSplice( tess->mesh, e, e->Sym ) ) { + tess->outOfMemory = 1; + return; + } + } else { + /* Create a new vertex and edge which immediately follow e + * in the ordering around the left face. + */ + if ( tessMeshSplitEdge( tess->mesh, e ) == NULL ) { + tess->outOfMemory = 1; + return; + } + e = e->Lnext; + } + + /* The new vertex is now e->Org. */ + e->Org->coords[0] = coords[0]; + e->Org->coords[1] = coords[1]; + if ( size > 2 ) + e->Org->coords[2] = coords[2]; + else + e->Org->coords[2] = 0; + /* Store the insertion number so that the vertex can be later recognized. */ + e->Org->idx = tess->vertexIndexCounter++; + + /* The winding of an edge says how the winding number changes as we + * cross from the edge''s right face to its left face. We add the + * vertices in such an order that a CCW contour will add +1 to + * the winding number of the region inside the contour. + */ + e->winding = 1; + e->Sym->winding = -1; + } +} + +int tessTesselate( TESStesselator *tess, int windingRule, int elementType, + int polySize, int vertexSize, const TESSreal* normal ) +{ + TESSmesh *mesh; + int rc = 1; + + if (tess->vertices != NULL) { + tess->alloc.memfree( tess->alloc.userData, tess->vertices ); + tess->vertices = 0; + } + if (tess->elements != NULL) { + tess->alloc.memfree( tess->alloc.userData, tess->elements ); + tess->elements = 0; + } + if (tess->vertexIndices != NULL) { + tess->alloc.memfree( tess->alloc.userData, tess->vertexIndices ); + tess->vertexIndices = 0; + } + + tess->vertexIndexCounter = 0; + + if (normal) + { + tess->normal[0] = normal[0]; + tess->normal[1] = normal[1]; + tess->normal[2] = normal[2]; + } + + tess->windingRule = windingRule; + + if (vertexSize < 2) + vertexSize = 2; + if (vertexSize > 3) + vertexSize = 3; + + if (setjmp(tess->env) != 0) { + /* come back here if out of memory */ + return 0; + } + + if (!tess->mesh) + { + return 0; + } + + /* Determine the polygon normal and project vertices onto the plane + * of the polygon. + */ + tessProjectPolygon( tess ); + + /* tessComputeInterior( tess ) computes the planar arrangement specified + * by the given contours, and further subdivides this arrangement + * into regions. Each region is marked "inside" if it belongs + * to the polygon, according to the rule given by tess->windingRule. + * Each interior region is guaranteed be monotone. + */ + if ( !tessComputeInterior( tess ) ) { + longjmp(tess->env,1); /* could've used a label */ + } + + mesh = tess->mesh; + + /* If the user wants only the boundary contours, we throw away all edges + * except those which separate the interior from the exterior. + * Otherwise we tessellate all the regions marked "inside". + */ + if (elementType == TESS_BOUNDARY_CONTOURS) { + rc = tessMeshSetWindingNumber( mesh, 1, TRUE ); + } else { + rc = tessMeshTessellateInterior( mesh ); + } + if (rc == 0) longjmp(tess->env,1); /* could've used a label */ + + tessMeshCheckMesh( mesh ); + + if (elementType == TESS_BOUNDARY_CONTOURS) { + OutputContours( tess, mesh, vertexSize ); /* output contours */ + } + else + { + OutputPolymesh( tess, mesh, elementType, polySize, vertexSize ); /* output polygons */ + } + + tessMeshDeleteMesh( &tess->alloc, mesh ); + tess->mesh = NULL; + + if (tess->outOfMemory) + return 0; + return 1; +} + +int tessGetVertexCount( TESStesselator *tess ) +{ + return tess->vertexCount; +} + +const TESSreal* tessGetVertices( TESStesselator *tess ) +{ + return tess->vertices; +} + +const TESSindex* tessGetVertexIndices( TESStesselator *tess ) +{ + return tess->vertexIndices; +} + +int tessGetElementCount( TESStesselator *tess ) +{ + return tess->elementCount; +} + +const int* tessGetElements( TESStesselator *tess ) +{ + return tess->elements; +} diff --git a/src/libtess2/tess.h b/src/libtess2/tess.h new file mode 100755 index 000000000..8ed75600d --- /dev/null +++ b/src/libtess2/tess.h @@ -0,0 +1,90 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Eric Veach, July 1994. +*/ + +#ifndef TESS_H +#define TESS_H + +#include +#include "bucketalloc.h" +#include "mesh.h" +#include "dict.h" +#include "priorityq.h" +#include "tesselator.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//typedef struct TESStesselator TESStesselator; + +struct TESStesselator { + + /*** state needed for collecting the input data ***/ + TESSmesh *mesh; /* stores the input contours, and eventually + the tessellation itself */ + int outOfMemory; + + /*** state needed for projecting onto the sweep plane ***/ + + TESSreal normal[3]; /* user-specified normal (if provided) */ + TESSreal sUnit[3]; /* unit vector in s-direction (debugging) */ + TESSreal tUnit[3]; /* unit vector in t-direction (debugging) */ + + TESSreal bmin[2]; + TESSreal bmax[2]; + + /*** state needed for the line sweep ***/ + int windingRule; /* rule for determining polygon interior */ + + Dict *dict; /* edge dictionary for sweep line */ + PriorityQ *pq; /* priority queue of vertex events */ + TESSvertex *event; /* current sweep event being processed */ + + struct BucketAlloc* regionPool; + + TESSindex vertexIndexCounter; + + TESSreal *vertices; + TESSindex *vertexIndices; + int vertexCount; + TESSindex *elements; + int elementCount; + + TESSalloc alloc; + + jmp_buf env; /* place to jump to when memAllocs fail */ +}; + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/src/libtess2/tesselator.h b/src/libtess2/tesselator.h new file mode 100755 index 000000000..74ca18e27 --- /dev/null +++ b/src/libtess2/tesselator.h @@ -0,0 +1,209 @@ +/* +** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) +** Copyright (C) [dates of first publication] Silicon Graphics, Inc. +** All Rights Reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +** of the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice including the dates of first publication and either this +** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +** OR OTHER DEALINGS IN THE SOFTWARE. +** +** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not +** be used in advertising or otherwise to promote the sale, use or other dealings in +** this Software without prior written authorization from Silicon Graphics, Inc. +*/ +/* +** Author: Mikko Mononen, July 2009. +*/ + +#ifndef TESSELATOR_H +#define TESSELATOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +// See OpenGL Red Book for description of the winding rules +// http://www.glprogramming.com/red/chapter11.html +enum TessWindingRule +{ + TESS_WINDING_ODD, + TESS_WINDING_NONZERO, + TESS_WINDING_POSITIVE, + TESS_WINDING_NEGATIVE, + TESS_WINDING_ABS_GEQ_TWO, +}; + +// The contents of the tessGetElements() depends on element type being passed to tessTesselate(). +// Tesselation result element types: +// TESS_POLYGONS +// Each element in the element array is polygon defined as 'polySize' number of vertex indices. +// If a polygon has than 'polySize' vertices, the remaining indices are stored as TESS_UNDEF. +// Example, drawing a polygon: +// const int nelems = tessGetElementCount(tess); +// const TESSindex* elems = tessGetElements(tess); +// for (int i = 0; i < nelems; i++) { +// const TESSindex* poly = &elems[i * polySize]; +// glBegin(GL_POLYGON); +// for (int j = 0; j < polySize; j++) { +// if (poly[j] == TESS_UNDEF) break; +// glVertex2fv(&verts[poly[j]*vertexSize]); +// } +// glEnd(); +// } +// +// TESS_CONNECTED_POLYGONS +// Each element in the element array is polygon defined as 'polySize' number of vertex indices, +// followed by 'polySize' indices to neighour polygons, that is each element is 'polySize' * 2 indices. +// If a polygon has than 'polySize' vertices, the remaining indices are stored as TESS_UNDEF. +// If a polygon edge is a boundary, that is, not connected to another polygon, the neighbour index is TESS_UNDEF. +// Example, flood fill based on seed polygon: +// const int nelems = tessGetElementCount(tess); +// const TESSindex* elems = tessGetElements(tess); +// unsigned char* visited = (unsigned char*)calloc(nelems); +// TESSindex stack[50]; +// int nstack = 0; +// stack[nstack++] = seedPoly; +// visited[startPoly] = 1; +// while (nstack > 0) { +// TESSindex idx = stack[--nstack]; +// const TESSindex* poly = &elems[idx * polySize * 2]; +// const TESSindex* nei = &poly[polySize]; +// for (int i = 0; i < polySize; i++) { +// if (poly[i] == TESS_UNDEF) break; +// if (nei[i] != TESS_UNDEF && !visited[nei[i]]) +// stack[nstack++] = nei[i]; +// visited[nei[i]] = 1; +// } +// } +// } +// +// TESS_BOUNDARY_CONTOURS +// Each element in the element array is [base index, count] pair defining a range of vertices for a contour. +// The first value is index to first vertex in contour and the second value is number of vertices in the contour. +// Example, drawing contours: +// const int nelems = tessGetElementCount(tess); +// const TESSindex* elems = tessGetElements(tess); +// for (int i = 0; i < nelems; i++) { +// const TESSindex base = elems[i * 2]; +// const TESSindex count = elems[i * 2 + 1]; +// glBegin(GL_LINE_LOOP); +// for (int j = 0; j < count; j++) { +// glVertex2fv(&verts[(base+count) * vertexSize]); +// } +// glEnd(); +// } +// +enum TessElementType +{ + TESS_POLYGONS, + TESS_CONNECTED_POLYGONS, + TESS_BOUNDARY_CONTOURS, +}; + +typedef float TESSreal; +typedef int TESSindex; +typedef struct TESStesselator TESStesselator; +typedef struct TESSalloc TESSalloc; + +#define TESS_UNDEF (~(TESSindex)0) + +// Custom memory allocator interface. +// The internal memory allocator allocates mesh edges, vertices and faces +// as well as dictionary nodes and active regions in buckets and uses simple +// freelist to speed up the allocation. The bucket size should roughly match your +// expected input data. For example if you process only hundreds of vertices, +// a bucket size of 128 might be ok, where as when processing thousands of vertices +// bucket size of 1024 might be approproate. The bucket size is a compromise between +// how often to allocate memory from the system versus how much extra space the system +// should allocate. Reasonable defaults are show in commects below, they will be used if +// the bucket sizes are zero. +// +// The use may left the memrealloc to be null. In that case, the tesselator will not try to +// dynamically grow int's internal arrays. The tesselator only needs the reallocation when it +// has found intersecting segments and needs to add new vertex. This defency can be cured by +// allocating some extra vertices beforehand. The 'extraVertices' variable allows to specify +// number of expected extra vertices. +struct TESSalloc +{ + void *(*memalloc)( void *userData, unsigned int size ); + void *(*memrealloc)( void *userData, void* ptr, unsigned int size ); + void (*memfree)( void *userData, void *ptr ); + void* userData; // User data passed to the allocator functions. + int meshEdgeBucketSize; // 512 + int meshVertexBucketSize; // 512 + int meshFaceBucketSize; // 256 + int dictNodeBucketSize; // 512 + int regionBucketSize; // 256 + int extraVertices; // Number of extra vertices allocated for the priority queue. +}; + +// tessNewTess() - Creates a new tesselator. +// Use tessDeleteTess() to delete the tesselator. +// Returns: +// new tesselator object. +TESStesselator* tessNewTess( TESSalloc* alloc ); + +// tessDeleteTess() - Deletes a tesselator. +// Parameters: +// tess - pointer to tesselator object to be deleted. +void tessDeleteTess( TESStesselator *tess ); + +// tessAddContour() - Adds a contour to be tesselated. +// The type of the vertex coordinates is assumed to be TESSreal. +// Parameters: +// tess - pointer to tesselator object. +// size - number of coordinates per vertex. Must be 2 or 3. +// pointer - pointer to the first coordinate of the first vertex in the array. +// stride - defines offset in bytes between consecutive vertices. +// count - number of vertices in contour. +void tessAddContour( TESStesselator *tess, int size, const void* pointer, int stride, int count ); + +// tessTesselate() - tesselate contours. +// Parameters: +// tess - pointer to tesselator object. +// windingRule - winding rules used for tesselation, must be one of TessWindingRule. +// elementType - defines the tesselation result element type, must be one of TessElementType. +// polySize - defines maximum vertices per polygons if output is polygons. +// vertexSize - defines the number of coordinates in tesselation result vertex, must be 2 or 3. +// normal - defines the normal of the input contours, of null the normal is calculated automatically. +// Returns: +// 1 if succeed, 0 if failed. +int tessTesselate( TESStesselator *tess, int windingRule, int elementType, int polySize, int vertexSize, const TESSreal* normal ); + +// tessGetVertexCount() - Returns number of vertices in the tesselated output. +int tessGetVertexCount( TESStesselator *tess ); + +// tessGetVertices() - Returns pointer to first coordinate of first vertex. +const TESSreal* tessGetVertices( TESStesselator *tess ); + +// tessGetVertexIndices() - Returns pointer to first vertex index. +// Vertex indices can be used to map the generated vertices to the original vertices. +// Every point added using tessAddContour() will get a new index starting at 0. +// New vertices generated at the intersections of segments are assigned value TESS_UNDEF. +const TESSindex* tessGetVertexIndices( TESStesselator *tess ); + +// tessGetElementCount() - Returns number of elements in the the tesselated output. +int tessGetElementCount( TESStesselator *tess ); + +// tessGetElements() - Returns pointer to the first element. +const TESSindex* tessGetElements( TESStesselator *tess ); + +#ifdef __cplusplus +} +#endif + +#endif // TESSELATOR_H diff --git a/src/mbgl/annotation/sprite_image.cpp b/src/mbgl/annotation/sprite_image.cpp new file mode 100644 index 000000000..e482d8f13 --- /dev/null +++ b/src/mbgl/annotation/sprite_image.cpp @@ -0,0 +1,29 @@ +#include + +#include + +#include + +namespace mbgl { + +SpriteImage::SpriteImage(const uint16_t width_, + const uint16_t height_, + const float pixelRatio_, + std::string&& data_, + bool sdf_) + : width(width_), + height(height_), + pixelRatio(pixelRatio_), + pixelWidth(std::ceil(width * pixelRatio)), + pixelHeight(std::ceil(height * pixelRatio)), + data(std::move(data_)), + sdf(sdf_) { + const size_t size = pixelWidth * pixelHeight * 4; + if (size == 0) { + throw util::SpriteImageException("Sprite image dimensions may not be zero"); + } else if (size != data.size()) { + throw util::SpriteImageException("Sprite image pixel count mismatch"); + } +} + +} // namespace mbgl diff --git a/src/mbgl/annotation/sprite_parser.cpp b/src/mbgl/annotation/sprite_parser.cpp new file mode 100644 index 000000000..f867b97f4 --- /dev/null +++ b/src/mbgl/annotation/sprite_parser.cpp @@ -0,0 +1,147 @@ +#include +#include + +#include + +#include + +#include + +#include +#include +#include + +namespace mbgl { + +SpriteImagePtr createSpriteImage(const util::Image& image, + const uint16_t srcX, + const uint16_t srcY, + const uint16_t srcWidth, + const uint16_t srcHeight, + const double ratio, + const bool sdf) { + // Disallow invalid parameter configurations. + if (srcWidth == 0 || srcHeight == 0 || ratio <= 0 || ratio > 10 || srcWidth > 1024 || + srcHeight > 1024) { + Log::Warning(Event::Sprite, "Can't create sprite with invalid metrics"); + return nullptr; + } + + const uint16_t width = std::ceil(double(srcWidth) / ratio); + const uint16_t dstWidth = std::ceil(width * ratio); + assert(dstWidth >= srcWidth); + const uint16_t height = std::ceil(double(srcHeight) / ratio); + const uint16_t dstHeight = std::ceil(height * ratio); + assert(dstHeight >= srcHeight); + + std::string data(dstWidth * dstHeight * 4, '\0'); + + auto srcData = reinterpret_cast(image.getData()); + auto dstData = reinterpret_cast(const_cast(data.data())); + + const int32_t maxX = std::min(image.getWidth(), uint32_t(srcWidth + srcX)) - srcX; + assert(maxX <= int32_t(image.getWidth())); + const int32_t maxY = std::min(image.getHeight(), uint32_t(srcHeight + srcY)) - srcY; + assert(maxY <= int32_t(image.getHeight())); + + // Copy from the source image into our individual sprite image + for (uint16_t y = 0; y < maxY; ++y) { + const auto dstRow = y * dstWidth; + const auto srcRow = (y + srcY) * image.getWidth() + srcX; + for (uint16_t x = 0; x < maxX; ++x) { + dstData[dstRow + x] = srcData[srcRow + x]; + } + } + + return std::make_unique(width, height, ratio, std::move(data), sdf); +} + +namespace { + +inline uint16_t getUInt16(const rapidjson::Value& value, const char* name, const uint16_t def = 0) { + if (value.HasMember(name)) { + auto& v = value[name]; + if (v.IsUint() && v.GetUint() <= std::numeric_limits::max()) { + return v.GetUint(); + } else { + Log::Warning(Event::Sprite, "Value of '%s' must be an integer between 0 and 65535", + name); + } + } + + return def; +} + +inline double getDouble(const rapidjson::Value& value, const char* name, const double def = 0) { + if (value.HasMember(name)) { + auto& v = value[name]; + if (v.IsNumber()) { + return v.GetDouble(); + } else { + Log::Warning(Event::Sprite, "Value of '%s' must be a number", name); + } + } + + return def; +} + +inline bool getBoolean(const rapidjson::Value& value, const char* name, const bool def = false) { + if (value.HasMember(name)) { + auto& v = value[name]; + if (v.IsBool()) { + return v.GetBool(); + } else { + Log::Warning(Event::Sprite, "Value of '%s' must be a boolean", name); + } + } + + return def; +} + +} // namespace + +SpriteParseResult parseSprite(const std::string& image, const std::string& json) { + using namespace rapidjson; + + Sprites sprites; + + // Parse the sprite image. + const util::Image raster(image); + if (!raster) { + return std::string("Could not parse sprite image"); + } + + Document doc; + doc.Parse<0>(json.c_str()); + + if (doc.HasParseError()) { + std::stringstream message; + message << "Failed to parse JSON: " << doc.GetParseError() << " at offset " << doc.GetErrorOffset(); + return message.str(); + } else if (!doc.IsObject()) { + return std::string("Sprite JSON root must be an object"); + } else { + for (Value::ConstMemberIterator itr = doc.MemberBegin(); itr != doc.MemberEnd(); ++itr) { + const std::string name = { itr->name.GetString(), itr->name.GetStringLength() }; + const Value& value = itr->value; + + if (value.IsObject()) { + const uint16_t x = getUInt16(value, "x", 0); + const uint16_t y = getUInt16(value, "y", 0); + const uint16_t width = getUInt16(value, "width", 0); + const uint16_t height = getUInt16(value, "height", 0); + const double pixelRatio = getDouble(value, "pixelRatio", 1); + const bool sdf = getBoolean(value, "sdf", false); + + auto sprite = createSpriteImage(raster, x, y, width, height, pixelRatio, sdf); + if (sprite) { + sprites.emplace(name, sprite); + } + } + } + } + + return sprites; +} + +} // namespace mbgl diff --git a/src/mbgl/annotation/sprite_parser.hpp b/src/mbgl/annotation/sprite_parser.hpp new file mode 100644 index 000000000..d7e995335 --- /dev/null +++ b/src/mbgl/annotation/sprite_parser.hpp @@ -0,0 +1,45 @@ +#ifndef MBGL_ANNOTATIONS_SPRITE_PARSER +#define MBGL_ANNOTATIONS_SPRITE_PARSER + +#include +#include +#include + +#include +#include +#include + +namespace mbgl { + +namespace util { + +class Image; + +} // namespace util + +class SpriteImage; + +using SpriteImagePtr = std::shared_ptr; + +// Extracts an individual image from a spritesheet from the given location. +SpriteImagePtr createSpriteImage(const util::Image& image, + uint16_t srcX, + uint16_t srcY, + uint16_t srcWidth, + uint16_t srcHeight, + double ratio, + bool sdf); + +using Sprites = std::map; + + +using SpriteParseResult = mapbox::util::variant< + Sprites, // success + std::string>; // error + +// Parses an image and an associated JSON file and returns the sprite objects. +SpriteParseResult parseSprite(const std::string& image, const std::string& json); + +} // namespace mbgl + +#endif diff --git a/src/mbgl/annotation/sprite_store.cpp b/src/mbgl/annotation/sprite_store.cpp new file mode 100644 index 000000000..8d2231a2b --- /dev/null +++ b/src/mbgl/annotation/sprite_store.cpp @@ -0,0 +1,71 @@ +#include + +#include + +namespace mbgl { + +void SpriteStore::setSprite(const std::string& name, std::shared_ptr sprite) { + std::lock_guard lock(mutex); + _setSprite(name, sprite); +} + +void SpriteStore::_setSprite(const std::string& name, + const std::shared_ptr& sprite) { + if (sprite) { + auto it = sprites.find(name); + if (it != sprites.end()) { + // There is already a sprite with that name in our store. + if ((it->second->width != sprite->width || it->second->height != sprite->height)) { + Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", name.c_str()); + return; + } + it->second = sprite; + } else { + sprites.emplace(name, sprite); + } + + // Always add/replace the value in the dirty list. + auto dirty_it = dirty.find(name); + if (dirty_it != dirty.end()) { + dirty_it->second = sprite; + } else { + dirty.emplace(name, sprite); + } + } else if (sprites.erase(name) > 0) { + dirty.emplace(name, nullptr); + } +} + +void SpriteStore::setSprites(const Sprites& newSprites) { + std::lock_guard lock(mutex); + for (const auto& pair : newSprites) { + _setSprite(pair.first, pair.second); + } +} + +void SpriteStore::removeSprite(const std::string& name) { + std::lock_guard lock(mutex); + _setSprite(name); +} + +std::shared_ptr SpriteStore::getSprite(const std::string& name) { + std::lock_guard lock(mutex); + const auto it = sprites.find(name); + if (it != sprites.end()) { + return it->second; + } else { + if (!sprites.empty()) { + Log::Info(Event::Sprite, "Can't find sprite named '%s'", name.c_str()); + } + return nullptr; + } +} + +SpriteStore::Sprites SpriteStore::getDirty() { + Sprites result; + std::lock_guard lock(mutex); + dirty.swap(result); + return result; +} + +} // namespace mbgl diff --git a/src/mbgl/annotation/sprite_store.hpp b/src/mbgl/annotation/sprite_store.hpp new file mode 100644 index 000000000..78e02ac69 --- /dev/null +++ b/src/mbgl/annotation/sprite_store.hpp @@ -0,0 +1,53 @@ +#ifndef MBGL_ANNOTATION_SPRITE_STORE +#define MBGL_ANNOTATION_SPRITE_STORE + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace mbgl { + +// The SpriteStore object holds Sprite images. +class SpriteStore : private util::noncopyable { + using Sprites = std::map>; + +public: + // Adds/replaces a Sprite image. + void setSprite(const std::string&, std::shared_ptr = nullptr); + + // Adds/replaces mutliple Sprite images. + void setSprites(const Sprites& sprites); + + // Removes a Sprite. + void removeSprite(const std::string&); + + // Obtains a Sprite image. + std::shared_ptr getSprite(const std::string&); + + // Returns Sprite images that changed since the last invocation of this function. + Sprites getDirty(); + +private: + void _setSprite(const std::string&, const std::shared_ptr& = nullptr); + + // Lock for sprites and dirty maps. + std::mutex mutex; + + // Stores all current sprites. + Sprites sprites; + + // Stores all Sprite IDs that changed since the last invocation. + Sprites dirty; +}; + +} // namespace mbgl + +#endif diff --git a/src/mbgl/geometry/anchor.hpp b/src/mbgl/geometry/anchor.hpp new file mode 100644 index 000000000..352f26075 --- /dev/null +++ b/src/mbgl/geometry/anchor.hpp @@ -0,0 +1,26 @@ +#ifndef MBGL_GEOMETRY_ANCHOR +#define MBGL_GEOMETRY_ANCHOR + +#include + +namespace mbgl { + +struct Anchor { + float x = 0.0f; + float y = 0.0f; + float angle = 0.0f; + float scale = 0.0f; + int segment = -1; + + explicit Anchor(float x_, float y_, float angle_, float scale_) + : x(x_), y(y_), angle(angle_), scale(scale_) {} + explicit Anchor(float x_, float y_, float angle_, float scale_, int segment_) + : x(x_), y(y_), angle(angle_), scale(scale_), segment(segment_) {} + +}; + +typedef std::vector Anchors; + +} + +#endif diff --git a/src/mbgl/geometry/binpack.hpp b/src/mbgl/geometry/binpack.hpp new file mode 100644 index 000000000..504417f45 --- /dev/null +++ b/src/mbgl/geometry/binpack.hpp @@ -0,0 +1,104 @@ +#ifndef MBGL_GEOMETRY_BINPACK +#define MBGL_GEOMETRY_BINPACK + +#include +#include +#include +#include + +namespace mbgl { + +template +class BinPack : private util::noncopyable { +public: + BinPack(T width, T height) + : free(1, Rect{ 0, 0, width, height }) {} +public: + Rect allocate(T width, T height) { + // Find the smallest free rect angle + auto smallest = free.end(); + for (auto it = free.begin(); it != free.end(); ++it) { + const Rect& ref = *it; + const Rect& rect = *smallest; + if (width <= ref.w && height <= ref.h) { + if (smallest == free.end() || (ref.y <= rect.y && ref.x <= rect.x)) { + smallest = it; + } else { + // Our current "smallest" rect is already closer to 0/0. + } + } else { + // The rect in the free list is not big enough. + } + } + + if (smallest == free.end()) { + // There's no space left for this char. + return Rect{ 0, 0, 0, 0 }; + } else { + Rect rect = *smallest; + free.erase(smallest); + + // Shorter/Longer Axis Split Rule (SAS) + // http://clb.demon.fi/files/RectangleBinPack.pdf p. 15 + // Ignore the dimension of R and just split long the shorter dimension + // See Also: http://www.cs.princeton.edu/~chazelle/pubs/blbinpacking.pdf + if (rect.w < rect.h) { + // split horizontally + // +--+---+ + // |__|___| <-- b1 + // +------+ <-- b2 + if (rect.w > width) free.emplace_back(rect.x + width, rect.y, rect.w - width, height); + if (rect.h > height) free.emplace_back(rect.x, rect.y + height, rect.w, rect.h - height); + } else { + // split vertically + // +--+---+ + // |__| | <-- b1 + // +--|---+ <-- b2 + if (rect.w > width) free.emplace_back(rect.x + width, rect.y, rect.w - width, rect.h); + if (rect.h > height) free.emplace_back(rect.x, rect.y + height, width, rect.h - height); + } + + return Rect{ rect.x, rect.y, width, height }; + } + } + + + void release(Rect rect) { + // Simple algorithm to recursively merge the newly released cell with its + // neighbor. This doesn't merge more than two cells at a time, and fails + // for complicated merges. + for (auto it = free.begin(); it != free.end(); ++it) { + Rect ref = *it; + if (ref.y == rect.y && ref.h == rect.h && ref.x + ref.w == rect.x) { + ref.w += rect.w; + } + else if (ref.x == rect.x && ref.w == rect.w && ref.y + ref.h == rect.y) { + ref.h += rect.h; + } + else if (rect.y == ref.y && rect.h == ref.h && rect.x + rect.w == ref.x) { + ref.x = rect.x; + ref.w += rect.w; + } + else if (rect.x == ref.x && rect.w == ref.w && rect.y + rect.h == ref.y) { + ref.y = rect.y; + ref.h += rect.h; + } else { + continue; + } + + free.erase(it); + release(ref); + return; + + } + + free.emplace_back(rect); + }; + +private: + std::list> free; +}; + +} + +#endif diff --git a/src/mbgl/geometry/buffer.hpp b/src/mbgl/geometry/buffer.hpp new file mode 100644 index 000000000..c696b5b86 --- /dev/null +++ b/src/mbgl/geometry/buffer.hpp @@ -0,0 +1,127 @@ +#ifndef MBGL_GEOMETRY_BUFFER +#define MBGL_GEOMETRY_BUFFER + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace mbgl { + +template < + size_t item_size, + int bufferType = GL_ARRAY_BUFFER, + size_t defaultLength = 8192, + bool retainAfterUpload = false +> +class Buffer : private util::noncopyable { +public: + ~Buffer() { + cleanup(); + if (buffer != 0) { + util::ThreadContext::getGLObjectStore()->abandonBuffer(buffer); + buffer = 0; + } + } + + // Returns the number of elements in this buffer. This is not the number of + // bytes, but rather the number of coordinates with associated information. + inline size_t index() const { + return pos / itemSize; + } + + inline bool empty() const { + return pos == 0; + } + + // Transfers this buffer to the GPU and binds the buffer to the GL context. + void bind() { + if (buffer) { + MBGL_CHECK_ERROR(glBindBuffer(bufferType, buffer)); + } else { + MBGL_CHECK_ERROR(glGenBuffers(1, &buffer)); + MBGL_CHECK_ERROR(glBindBuffer(bufferType, buffer)); + if (array == nullptr) { + Log::Debug(Event::OpenGL, "Buffer doesn't contain elements"); + pos = 0; + } + MBGL_CHECK_ERROR(glBufferData(bufferType, pos, array, GL_STATIC_DRAW)); + if (!retainAfterUpload) { + cleanup(); + } + } + } + + void cleanup() { + if (array) { + free(array); + array = nullptr; + } + } + + inline GLuint getID() const { + return buffer; + } + + // Uploads the buffer to the GPU to be available when we need it. + inline void upload() { + if (!buffer) { + bind(); + } + } + +protected: + // increase the buffer size by at least /required/ bytes. + inline void *addElement() { + if (buffer != 0) { + throw std::runtime_error("Can't add elements after buffer was bound to GPU"); + } + if (length < pos + itemSize) { + while (length < pos + itemSize) length += defaultLength; + array = realloc(array, length); + if (array == nullptr) { + throw std::runtime_error("Buffer reallocation failed"); + } + } + pos += itemSize; + return reinterpret_cast(array) + (pos - itemSize); + } + + // Get a pointer to the item at a given index. + inline void *getElement(size_t i) { + if (array == nullptr) { + throw std::runtime_error("Buffer was already deleted or doesn't contain elements"); + } + + if (i * itemSize >= pos) { + throw new std::runtime_error("Can't get element after array bounds"); + } else { + return reinterpret_cast(array) + (i * itemSize); + } + } + +public: + static const size_t itemSize = item_size; + +private: + // CPU buffer + void *array = nullptr; + + // Byte position where we are writing. + size_t pos = 0; + + // Number of bytes that are valid in this buffer. + size_t length = 0; + + // GL buffer ID + GLuint buffer = 0; +}; + +} + +#endif diff --git a/src/mbgl/geometry/collision_box_buffer.cpp b/src/mbgl/geometry/collision_box_buffer.cpp new file mode 100644 index 000000000..da9031c89 --- /dev/null +++ b/src/mbgl/geometry/collision_box_buffer.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace mbgl { + +size_t CollisionBoxVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, float maxzoom, float placementZoom) { + const size_t idx = index(); + void *data = addElement(); + + int16_t *shorts = static_cast(data); + shorts[0] /* pos */ = x; + shorts[1] /* pos */ = y; + shorts[2] /* offset */ = ::round(ox); // use 1/64 pixels for placement + shorts[3] /* offset */ = ::round(oy); + + uint8_t *ubytes = static_cast(data); + // a_data1 + ubytes[8] = maxzoom * 10; + ubytes[9] = placementZoom * 10; + + return idx; +} + +} diff --git a/src/mbgl/geometry/collision_box_buffer.hpp b/src/mbgl/geometry/collision_box_buffer.hpp new file mode 100644 index 000000000..098eab13c --- /dev/null +++ b/src/mbgl/geometry/collision_box_buffer.hpp @@ -0,0 +1,23 @@ +#ifndef MBGL_GEOMETRY_COLLISIONBOX_BUFFER +#define MBGL_GEOMETRY_COLLISIONBOX_BUFFER + +#include +#include + +namespace mbgl { + +class CollisionBoxVertexBuffer : public Buffer < + 12, + GL_ARRAY_BUFFER, + 32768 +> { +public: + typedef int16_t vertex_type; + + size_t add(int16_t x, int16_t y, float ex, float ey, float maxzoom, float placementZoom); +}; + + +} + +#endif diff --git a/src/mbgl/geometry/debug_font_buffer.cpp b/src/mbgl/geometry/debug_font_buffer.cpp new file mode 100644 index 000000000..e4af70766 --- /dev/null +++ b/src/mbgl/geometry/debug_font_buffer.cpp @@ -0,0 +1,42 @@ +#include +#include + +#include +#include +#include + +using namespace mbgl; + +void DebugFontBuffer::addText(const char *text, double left, double baseline, double scale) { + uint16_t *coords = nullptr; + + const size_t len = strlen(text); + for (size_t i = 0; i < len; ++i) { + if (text[i] < 32 || (unsigned char)(text[i]) >= 127) { + continue; + } + + const glyph& glyph = simplex[text[i] - 32]; + + int16_t prev_x = -1, prev_y = -1, prev = false; + for (int32_t j = 0; j < glyph.length; j += 2) { + if (glyph.data[j] == -1 && glyph.data[j + 1] == -1) { + prev = false; + } else { + int16_t x = ::round(left + glyph.data[j] * scale); + int16_t y = ::round(baseline - glyph.data[j + 1] * scale); + if (prev) { + coords = static_cast(addElement()); + coords[0] = prev_x; + coords[1] = prev_y; + + coords = static_cast(addElement()); + coords[0] = x; + coords[1] = y; + } + prev_x = x; prev_y = y; prev = true; + } + } + left += glyph.width * scale; + } +} diff --git a/src/mbgl/geometry/debug_font_buffer.hpp b/src/mbgl/geometry/debug_font_buffer.hpp new file mode 100644 index 000000000..802b5dbaa --- /dev/null +++ b/src/mbgl/geometry/debug_font_buffer.hpp @@ -0,0 +1,17 @@ +#ifndef MBGL_GEOMETRY_DEBUG_FONT_BUFFER +#define MBGL_GEOMETRY_DEBUG_FONT_BUFFER + +#include + +namespace mbgl { + +class DebugFontBuffer : public Buffer< + 4 // 2 bytes per coordinate, 2 coordinates +> { +public: + void addText(const char *text, double left, double baseline, double scale = 1); +}; + +} + +#endif diff --git a/src/mbgl/geometry/debug_font_data.hpp b/src/mbgl/geometry/debug_font_data.hpp new file mode 100644 index 000000000..26c54cb48 --- /dev/null +++ b/src/mbgl/geometry/debug_font_data.hpp @@ -0,0 +1,206 @@ +// This is an implementation file, so omit include guards. + +#include +#include + +const int8_t simplex_1[] = { 5, 21, 5, 7, -1, -1, 5, 2, 4, 1, 5, 0, 6, 1, 5, 2 }; +const int8_t simplex_2[] = { 4, 21, 4, 14, -1, -1, 12, 21, 12, 14 }; +const int8_t simplex_3[] = { 11, 25, 4, -7, -1, -1, 17, 25, 10, -7, -1, -1, 4, 12, 18, 12, -1, -1, 3, 6, 17, 6 }; +const int8_t simplex_4[] = { 8, 25, 8, -4, -1, -1, 12, 25, 12, -4, -1, -1, 17, 18, 15, 20, 12, 21, 8, 21, 5, 20, 3, 18, 3, 16, 4, 14, 5, 13, 7, 12, 13, 10, 15, 9, 16, 8, 17, 6, 17, 3, 15, 1, 12, 0, 8, 0, 5, 1, 3, 3 }; +const int8_t simplex_5[] = { 21, 21, 3, 0, -1, -1, 8, 21, 10, 19, 10, 17, 9, 15, 7, 14, 5, 14, 3, 16, 3, 18, 4, 20, 6, 21, 8, 21, 10, 20, 13, 19, 16, 19, 19, 20, 21, 21, -1, -1, 17, 7, 15, 6, 14, 4, 14, 2, 16, 0, 18, 0, 20, 1, 21, 3, 21, 5, 19, 7, 17, 7 }; +const int8_t simplex_6[] = { 23, 12, 23, 13, 22, 14, 21, 14, 20, 13, 19, 11, 17, 6, 15, 3, 13, 1, 11, 0, 7, 0, 5, 1, 4, 2, 3, 4, 3, 6, 4, 8, 5, 9, 12, 13, 13, 14, 14, 16, 14, 18, 13, 20, 11, 21, 9, 20, 8, 18, 8, 16, 9, 13, 11, 10, 16, 3, 18, 1, 20, 0, 22, 0, 23, 1, 23, 2 }; +const int8_t simplex_7[] = { 5, 19, 4, 20, 5, 21, 6, 20, 6, 18, 5, 16, 4, 15 }; +const int8_t simplex_8[] = { 11, 25, 9, 23, 7, 20, 5, 16, 4, 11, 4, 7, 5, 2, 7, -2, 9, -5, 11, -7 }; +const int8_t simplex_9[] = { 3, 25, 5, 23, 7, 20, 9, 16, 10, 11, 10, 7, 9, 2, 7, -2, 5, -5, 3, -7 }; +const int8_t simplex_10[] = { 8, 21, 8, 9, -1, -1, 3, 18, 13, 12, -1, -1, 13, 18, 3, 12 }; +const int8_t simplex_11[] = { 13, 18, 13, 0, -1, -1, 4, 9, 22, 9 }; +const int8_t simplex_12[] = { 6, 1, 5, 0, 4, 1, 5, 2, 6, 1, 6, -1, 5, -3, 4, -4 }; +const int8_t simplex_13[] = { 4, 9, 22, 9 }; +const int8_t simplex_14[] = { 5, 2, 4, 1, 5, 0, 6, 1, 5, 2 }; +const int8_t simplex_15[] = { 20, 25, 2, -7 }; +const int8_t simplex_16[] = { 9, 21, 6, 20, 4, 17, 3, 12, 3, 9, 4, 4, 6, 1, 9, 0, 11, 0, 14, 1, 16, 4, 17, 9, 17, 12, 16, 17, 14, 20, 11, 21, 9, 21 }; +const int8_t simplex_17[] = { 6, 17, 8, 18, 11, 21, 11, 0 }; +const int8_t simplex_18[] = { 4, 16, 4, 17, 5, 19, 6, 20, 8, 21, 12, 21, 14, 20, 15, 19, 16, 17, 16, 15, 15, 13, 13, 10, 3, 0, 17, 0 }; +const int8_t simplex_19[] = { 5, 21, 16, 21, 10, 13, 13, 13, 15, 12, 16, 11, 17, 8, 17, 6, 16, 3, 14, 1, 11, 0, 8, 0, 5, 1, 4, 2, 3, 4 }; +const int8_t simplex_20[] = { 13, 21, 3, 7, 18, 7, -1, -1, 13, 21, 13, 0 }; +const int8_t simplex_21[] = { 15, 21, 5, 21, 4, 12, 5, 13, 8, 14, 11, 14, 14, 13, 16, 11, 17, 8, 17, 6, 16, 3, 14, 1, 11, 0, 8, 0, 5, 1, 4, 2, 3, 4 }; +const int8_t simplex_22[] = { 16, 18, 15, 20, 12, 21, 10, 21, 7, 20, 5, 17, 4, 12, 4, 7, 5, 3, 7, 1, 10, 0, 11, 0, 14, 1, 16, 3, 17, 6, 17, 7, 16, 10, 14, 12, 11, 13, 10, 13, 7, 12, 5, 10, 4, 7 }; +const int8_t simplex_23[] = { 17, 21, 7, 0, -1, -1, 3, 21, 17, 21 }; +const int8_t simplex_24[] = { 8, 21, 5, 20, 4, 18, 4, 16, 5, 14, 7, 13, 11, 12, 14, 11, 16, 9, 17, 7, 17, 4, 16, 2, 15, 1, 12, 0, 8, 0, 5, 1, 4, 2, 3, 4, 3, 7, 4, 9, 6, 11, 9, 12, 13, 13, 15, 14, 16, 16, 16, 18, 15, 20, 12, 21, 8, 21 }; +const int8_t simplex_25[] = { 16, 14, 15, 11, 13, 9, 10, 8, 9, 8, 6, 9, 4, 11, 3, 14, 3, 15, 4, 18, 6, 20, 9, 21, 10, 21, 13, 20, 15, 18, 16, 14, 16, 9, 15, 4, 13, 1, 10, 0, 8, 0, 5, 1, 4, 3 }; +const int8_t simplex_26[] = { 5, 14, 4, 13, 5, 12, 6, 13, 5, 14, -1, -1, 5, 2, 4, 1, 5, 0, 6, 1, 5, 2 }; +const int8_t simplex_27[] = { 5, 14, 4, 13, 5, 12, 6, 13, 5, 14, -1, -1, 6, 1, 5, 0, 4, 1, 5, 2, 6, 1, 6, -1, 5, -3, 4, -4 }; +const int8_t simplex_28[] = { 20, 18, 4, 9, 20, 0 }; +const int8_t simplex_29[] = { 4, 12, 22, 12, -1, -1, 4, 6, 22, 6 }; +const int8_t simplex_30[] = { 4, 18, 20, 9, 4, 0 }; +const int8_t simplex_31[] = { 3, 16, 3, 17, 4, 19, 5, 20, 7, 21, 11, 21, 13, 20, 14, 19, 15, 17, 15, 15, 14, 13, 13, 12, 9, 10, 9, 7, -1, -1, 9, 2, 8, 1, 9, 0, 10, 1, 9, 2 }; +const int8_t simplex_32[] = { 18, 13, 17, 15, 15, 16, 12, 16, 10, 15, 9, 14, 8, 11, 8, 8, 9, 6, 11, 5, 14, 5, 16, 6, 17, 8, -1, -1, 12, 16, 10, 14, 9, 11, 9, 8, 10, 6, 11, 5, -1, -1, 18, 16, 17, 8, 17, 6, 19, 5, 21, 5, 23, 7, 24, 10, 24, 12, 23, 15, 22, 17, 20, 19, 18, 20, 15, 21, 12, 21, 9, 20, 7, 19, 5, 17, 4, 15, 3, 12, 3, 9, 4, 6, 5, 4, 7, 2, 9, 1, 12, 0, 15, 0, 18, 1, 20, 2, 21, 3, -1, -1, 19, 16, 18, 8, 18, 6, 19, 5 }; +const int8_t simplex_33[] = { 9, 21, 1, 0, -1, -1, 9, 21, 17, 0, -1, -1, 4, 7, 14, 7 }; +const int8_t simplex_34[] = { 4, 21, 4, 0, -1, -1, 4, 21, 13, 21, 16, 20, 17, 19, 18, 17, 18, 15, 17, 13, 16, 12, 13, 11, -1, -1, 4, 11, 13, 11, 16, 10, 17, 9, 18, 7, 18, 4, 17, 2, 16, 1, 13, 0, 4, 0 }; +const int8_t simplex_35[] = { 18, 16, 17, 18, 15, 20, 13, 21, 9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5 }; +const int8_t simplex_36[] = { 4, 21, 4, 0, -1, -1, 4, 21, 11, 21, 14, 20, 16, 18, 17, 16, 18, 13, 18, 8, 17, 5, 16, 3, 14, 1, 11, 0, 4, 0 }; +const int8_t simplex_37[] = { 4, 21, 4, 0, -1, -1, 4, 21, 17, 21, -1, -1, 4, 11, 12, 11, -1, -1, 4, 0, 17, 0 }; +const int8_t simplex_38[] = { 4, 21, 4, 0, -1, -1, 4, 21, 17, 21, -1, -1, 4, 11, 12, 11 }; +const int8_t simplex_39[] = { 18, 16, 17, 18, 15, 20, 13, 21, 9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5, 18, 8, -1, -1, 13, 8, 18, 8 }; +const int8_t simplex_40[] = { 4, 21, 4, 0, -1, -1, 18, 21, 18, 0, -1, -1, 4, 11, 18, 11 }; +const int8_t simplex_41[] = { 4, 21, 4, 0 }; +const int8_t simplex_42[] = { 12, 21, 12, 5, 11, 2, 10, 1, 8, 0, 6, 0, 4, 1, 3, 2, 2, 5, 2, 7 }; +const int8_t simplex_43[] = { 4, 21, 4, 0, -1, -1, 18, 21, 4, 7, -1, -1, 9, 12, 18, 0 }; +const int8_t simplex_44[] = { 4, 21, 4, 0, -1, -1, 4, 0, 16, 0 }; +const int8_t simplex_45[] = { 4, 21, 4, 0, -1, -1, 4, 21, 12, 0, -1, -1, 20, 21, 12, 0, -1, -1, 20, 21, 20, 0 }; +const int8_t simplex_46[] = { 4, 21, 4, 0, -1, -1, 4, 21, 18, 0, -1, -1, 18, 21, 18, 0 }; +const int8_t simplex_47[] = { 9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5, 19, 8, 19, 13, 18, 16, 17, 18, 15, 20, 13, 21, 9, 21 }; +const int8_t simplex_48[] = { 4, 21, 4, 0, -1, -1, 4, 21, 13, 21, 16, 20, 17, 19, 18, 17, 18, 14, 17, 12, 16, 11, 13, 10, 4, 10 }; +const int8_t simplex_49[] = { 9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5, 19, 8, 19, 13, 18, 16, 17, 18, 15, 20, 13, 21, 9, 21, -1, -1, 12, 4, 18, -2 }; +const int8_t simplex_50[] = { 4, 21, 4, 0, -1, -1, 4, 21, 13, 21, 16, 20, 17, 19, 18, 17, 18, 15, 17, 13, 16, 12, 13, 11, 4, 11, -1, -1, 11, 11, 18, 0 }; +const int8_t simplex_51[] = { 17, 18, 15, 20, 12, 21, 8, 21, 5, 20, 3, 18, 3, 16, 4, 14, 5, 13, 7, 12, 13, 10, 15, 9, 16, 8, 17, 6, 17, 3, 15, 1, 12, 0, 8, 0, 5, 1, 3, 3 }; +const int8_t simplex_52[] = { 8, 21, 8, 0, -1, -1, 1, 21, 15, 21 }; +const int8_t simplex_53[] = { 4, 21, 4, 6, 5, 3, 7, 1, 10, 0, 12, 0, 15, 1, 17, 3, 18, 6, 18, 21 }; +const int8_t simplex_54[] = { 1, 21, 9, 0, -1, -1, 17, 21, 9, 0 }; +const int8_t simplex_55[] = { 2, 21, 7, 0, -1, -1, 12, 21, 7, 0, -1, -1, 12, 21, 17, 0, -1, -1, 22, 21, 17, 0 }; +const int8_t simplex_56[] = { 3, 21, 17, 0, -1, -1, 17, 21, 3, 0 }; +const int8_t simplex_57[] = { 1, 21, 9, 11, 9, 0, -1, -1, 17, 21, 9, 11 }; +const int8_t simplex_58[] = { 17, 21, 3, 0, -1, -1, 3, 21, 17, 21, -1, -1, 3, 0, 17, 0 }; +const int8_t simplex_59[] = { 4, 25, 4, -7, -1, -1, 5, 25, 5, -7, -1, -1, 4, 25, 11, 25, -1, -1, 4, -7, 11, -7 }; +const int8_t simplex_60[] = { 0, 21, 14, -3 }; +const int8_t simplex_61[] = { 9, 25, 9, -7, -1, -1, 10, 25, 10, -7, -1, -1, 3, 25, 10, 25, -1, -1, 3, -7, 10, -7 }; +const int8_t simplex_62[] = { 6, 15, 8, 18, 10, 15, -1, -1, 3, 12, 8, 17, 13, 12, -1, -1, 8, 17, 8, 0 }; +const int8_t simplex_63[] = { 0, -2, 16, -2 }; +const int8_t simplex_64[] = { 6, 21, 5, 20, 4, 18, 4, 16, 5, 15, 6, 16, 5, 17 }; +const int8_t simplex_65[] = { 15, 14, 15, 0, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3 }; +const int8_t simplex_66[] = { 4, 21, 4, 0, -1, -1, 4, 11, 6, 13, 8, 14, 11, 14, 13, 13, 15, 11, 16, 8, 16, 6, 15, 3, 13, 1, 11, 0, 8, 0, 6, 1, 4, 3 }; +const int8_t simplex_67[] = { 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3 }; +const int8_t simplex_68[] = { 15, 21, 15, 0, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3 }; +const int8_t simplex_69[] = { 3, 8, 15, 8, 15, 10, 14, 12, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3 }; +const int8_t simplex_70[] = { 10, 21, 8, 21, 6, 20, 5, 17, 5, 0, -1, -1, 2, 14, 9, 14 }; +const int8_t simplex_71[] = { 15, 14, 15, -2, 14, -5, 13, -6, 11, -7, 8, -7, 6, -6, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3 }; +const int8_t simplex_72[] = { 4, 21, 4, 0, -1, -1, 4, 10, 7, 13, 9, 14, 12, 14, 14, 13, 15, 10, 15, 0 }; +const int8_t simplex_73[] = { 3, 21, 4, 20, 5, 21, 4, 22, 3, 21, -1, -1, 4, 14, 4, 0 }; +const int8_t simplex_74[] = { 5, 21, 6, 20, 7, 21, 6, 22, 5, 21, -1, -1, 6, 14, 6, -3, 5, -6, 3, -7, 1, -7 }; +const int8_t simplex_75[] = { 4, 21, 4, 0, -1, -1, 14, 14, 4, 4, -1, -1, 8, 8, 15, 0 }; +const int8_t simplex_76[] = { 4, 21, 4, 0 }; +const int8_t simplex_77[] = { 4, 14, 4, 0, -1, -1, 4, 10, 7, 13, 9, 14, 12, 14, 14, 13, 15, 10, 15, 0, -1, -1, 15, 10, 18, 13, 20, 14, 23, 14, 25, 13, 26, 10, 26, 0 }; +const int8_t simplex_78[] = { 4, 14, 4, 0, -1, -1, 4, 10, 7, 13, 9, 14, 12, 14, 14, 13, 15, 10, 15, 0 }; +const int8_t simplex_79[] = { 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3, 16, 6, 16, 8, 15, 11, 13, 13, 11, 14, 8, 14 }; +const int8_t simplex_80[] = { 4, 14, 4, -7, -1, -1, 4, 11, 6, 13, 8, 14, 11, 14, 13, 13, 15, 11, 16, 8, 16, 6, 15, 3, 13, 1, 11, 0, 8, 0, 6, 1, 4, 3 }; +const int8_t simplex_81[] = { 15, 14, 15, -7, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3 }; +const int8_t simplex_82[] = { 4, 14, 4, 0, -1, -1, 4, 8, 5, 11, 7, 13, 9, 14, 12, 14 }; +const int8_t simplex_83[] = { 14, 11, 13, 13, 10, 14, 7, 14, 4, 13, 3, 11, 4, 9, 6, 8, 11, 7, 13, 6, 14, 4, 14, 3, 13, 1, 10, 0, 7, 0, 4, 1, 3, 3 }; +const int8_t simplex_84[] = { 5, 21, 5, 4, 6, 1, 8, 0, 10, 0, -1, -1, 2, 14, 9, 14 }; +const int8_t simplex_85[] = { 4, 14, 4, 4, 5, 1, 7, 0, 10, 0, 12, 1, 15, 4, -1, -1, 15, 14, 15, 0 }; +const int8_t simplex_86[] = { 2, 14, 8, 0, -1, -1, 14, 14, 8, 0 }; +const int8_t simplex_87[] = { 3, 14, 7, 0, -1, -1, 11, 14, 7, 0, -1, -1, 11, 14, 15, 0, -1, -1, 19, 14, 15, 0 }; +const int8_t simplex_88[] = { 3, 14, 14, 0, -1, -1, 14, 14, 3, 0 }; +const int8_t simplex_89[] = { 2, 14, 8, 0, -1, -1, 14, 14, 8, 0, 6, -4, 4, -6, 2, -7, 1, -7 }; +const int8_t simplex_90[] = { 14, 14, 3, 0, -1, -1, 3, 14, 14, 14, -1, -1, 3, 0, 14, 0 }; +const int8_t simplex_91[] = { 9, 25, 7, 24, 6, 23, 5, 21, 5, 19, 6, 17, 7, 16, 8, 14, 8, 12, 6, 10, -1, -1, 7, 24, 6, 22, 6, 20, 7, 18, 8, 17, 9, 15, 9, 13, 8, 11, 4, 9, 8, 7, 9, 5, 9, 3, 8, 1, 7, 0, 6, -2, 6, -4, 7, -6, -1, -1, 6, 8, 8, 6, 8, 4, 7, 2, 6, 1, 5, -1, 5, -3, 6, -5, 7, -6, 9, -7 }; +const int8_t simplex_92[] = { 4, 25, 4, -7 }; +const int8_t simplex_93[] = { 5, 25, 7, 24, 8, 23, 9, 21, 9, 19, 8, 17, 7, 16, 6, 14, 6, 12, 8, 10, -1, -1, 7, 24, 8, 22, 8, 20, 7, 18, 6, 17, 5, 15, 5, 13, 6, 11, 10, 9, 6, 7, 5, 5, 5, 3, 6, 1, 7, 0, 8, -2, 8, -4, 7, -6, -1, -1, 8, 8, 6, 6, 6, 4, 7, 2, 8, 1, 9, -1, 9, -3, 8, -5, 7, -6, 5, -7 }; +const int8_t simplex_94[] = { 3, 6, 3, 8, 4, 11, 6, 12, 8, 12, 10, 11, 14, 8, 16, 7, 18, 7, 20, 8, 21, 10, -1, -1, 3, 8, 4, 10, 6, 11, 8, 11, 10, 10, 14, 7, 16, 6, 18, 6, 20, 7, 21, 10, 21, 12 }; + +struct glyph { + uint8_t width; + uint8_t length; + const int8_t *data; +}; + +// Font data From Hershey Simplex Font +// http://paulbourke.net/dataformats/hershey/ + +const glyph simplex[] = { + /* 32 */ { 16, 0, nullptr }, + /* 33 ! */ { 10, sizeof(simplex_1), simplex_1 }, + /* 34 " */ { 16, sizeof(simplex_2), simplex_2 }, + /* 35 # */ { 21, sizeof(simplex_3), simplex_3 }, + /* 36 $ */ { 20, sizeof(simplex_4), simplex_4 }, + /* 37 % */ { 24, sizeof(simplex_5), simplex_5 }, + /* 38 & */ { 26, sizeof(simplex_6), simplex_6 }, + /* 39 ' */ { 10, sizeof(simplex_7), simplex_7 }, + /* 40 ( */ { 14, sizeof(simplex_8), simplex_8 }, + /* 41 ) */ { 14, sizeof(simplex_9), simplex_9 }, + /* 42 * */ { 16, sizeof(simplex_10), simplex_10 }, + /* 43 + */ { 26, sizeof(simplex_11), simplex_11 }, + /* 44 , */ { 10, sizeof(simplex_12), simplex_12 }, + /* 45 - */ { 26, sizeof(simplex_13), simplex_13 }, + /* 46 . */ { 10, sizeof(simplex_14), simplex_14 }, + /* 47 / */ { 22, sizeof(simplex_15), simplex_15 }, + /* 48 0 */ { 20, sizeof(simplex_16), simplex_16 }, + /* 49 1 */ { 20, sizeof(simplex_17), simplex_17 }, + /* 50 2 */ { 20, sizeof(simplex_18), simplex_18 }, + /* 51 3 */ { 20, sizeof(simplex_19), simplex_19 }, + /* 52 4 */ { 20, sizeof(simplex_20), simplex_20 }, + /* 53 5 */ { 20, sizeof(simplex_21), simplex_21 }, + /* 54 6 */ { 20, sizeof(simplex_22), simplex_22 }, + /* 55 7 */ { 20, sizeof(simplex_23), simplex_23 }, + /* 56 8 */ { 20, sizeof(simplex_24), simplex_24 }, + /* 57 9 */ { 20, sizeof(simplex_25), simplex_25 }, + /* 58 : */ { 10, sizeof(simplex_26), simplex_26 }, + /* 59 ; */ { 10, sizeof(simplex_27), simplex_27 }, + /* 60 < */ { 24, sizeof(simplex_28), simplex_28 }, + /* 61 = */ { 26, sizeof(simplex_29), simplex_29 }, + /* 62 > */ { 24, sizeof(simplex_30), simplex_30 }, + /* 63 ? */ { 18, sizeof(simplex_31), simplex_31 }, + /* 64 @ */ { 27, sizeof(simplex_32), simplex_32 }, + /* 65 A */ { 18, sizeof(simplex_33), simplex_33 }, + /* 66 B */ { 21, sizeof(simplex_34), simplex_34 }, + /* 67 C */ { 21, sizeof(simplex_35), simplex_35 }, + /* 68 D */ { 21, sizeof(simplex_36), simplex_36 }, + /* 69 E */ { 19, sizeof(simplex_37), simplex_37 }, + /* 70 F */ { 18, sizeof(simplex_38), simplex_38 }, + /* 71 G */ { 21, sizeof(simplex_39), simplex_39 }, + /* 72 H */ { 22, sizeof(simplex_40), simplex_40 }, + /* 73 I */ { 8, sizeof(simplex_41), simplex_41 }, + /* 74 J */ { 16, sizeof(simplex_42), simplex_42 }, + /* 75 K */ { 21, sizeof(simplex_43), simplex_43 }, + /* 76 L */ { 17, sizeof(simplex_44), simplex_44 }, + /* 77 M */ { 24, sizeof(simplex_45), simplex_45 }, + /* 78 N */ { 22, sizeof(simplex_46), simplex_46 }, + /* 79 O */ { 22, sizeof(simplex_47), simplex_47 }, + /* 80 P */ { 21, sizeof(simplex_48), simplex_48 }, + /* 81 Q */ { 22, sizeof(simplex_49), simplex_49 }, + /* 82 R */ { 21, sizeof(simplex_50), simplex_50 }, + /* 83 S */ { 20, sizeof(simplex_51), simplex_51 }, + /* 84 T */ { 16, sizeof(simplex_52), simplex_52 }, + /* 85 U */ { 22, sizeof(simplex_53), simplex_53 }, + /* 86 V */ { 18, sizeof(simplex_54), simplex_54 }, + /* 87 W */ { 24, sizeof(simplex_55), simplex_55 }, + /* 88 X */ { 20, sizeof(simplex_56), simplex_56 }, + /* 89 Y */ { 18, sizeof(simplex_57), simplex_57 }, + /* 90 Z */ { 20, sizeof(simplex_58), simplex_58 }, + /* 91 [ */ { 14, sizeof(simplex_59), simplex_59 }, + /* 92 \ */ { 14, sizeof(simplex_60), simplex_60 }, + /* 93 ] */ { 14, sizeof(simplex_61), simplex_61 }, + /* 94 ^ */ { 16, sizeof(simplex_62), simplex_62 }, + /* 95 _ */ { 16, sizeof(simplex_63), simplex_63 }, + /* 96 ` */ { 10, sizeof(simplex_64), simplex_64 }, + /* 97 a */ { 19, sizeof(simplex_65), simplex_65 }, + /* 98 b */ { 19, sizeof(simplex_66), simplex_66 }, + /* 99 c */ { 18, sizeof(simplex_67), simplex_67 }, + /* 100 d */ { 19, sizeof(simplex_68), simplex_68 }, + /* 101 e */ { 18, sizeof(simplex_69), simplex_69 }, + /* 102 f */ { 12, sizeof(simplex_70), simplex_70 }, + /* 103 g */ { 19, sizeof(simplex_71), simplex_71 }, + /* 104 h */ { 19, sizeof(simplex_72), simplex_72 }, + /* 105 i */ { 8, sizeof(simplex_73), simplex_73 }, + /* 106 j */ { 10, sizeof(simplex_74), simplex_74 }, + /* 107 k */ { 17, sizeof(simplex_75), simplex_75 }, + /* 108 l */ { 8, sizeof(simplex_76), simplex_76 }, + /* 109 m */ { 30, sizeof(simplex_77), simplex_77 }, + /* 110 n */ { 19, sizeof(simplex_78), simplex_78 }, + /* 111 o */ { 19, sizeof(simplex_79), simplex_79 }, + /* 112 p */ { 19, sizeof(simplex_80), simplex_80 }, + /* 113 q */ { 19, sizeof(simplex_81), simplex_81 }, + /* 114 r */ { 13, sizeof(simplex_82), simplex_82 }, + /* 115 s */ { 17, sizeof(simplex_83), simplex_83 }, + /* 116 t */ { 12, sizeof(simplex_84), simplex_84 }, + /* 117 u */ { 19, sizeof(simplex_85), simplex_85 }, + /* 118 v */ { 16, sizeof(simplex_86), simplex_86 }, + /* 119 w */ { 22, sizeof(simplex_87), simplex_87 }, + /* 120 x */ { 17, sizeof(simplex_88), simplex_88 }, + /* 121 y */ { 16, sizeof(simplex_89), simplex_89 }, + /* 122 z */ { 17, sizeof(simplex_90), simplex_90 }, + /* 123 { */ { 14, sizeof(simplex_91), simplex_91 }, + /* 124 | */ { 8, sizeof(simplex_92), simplex_92 }, + /* 125 } */ { 14, sizeof(simplex_93), simplex_93 }, + /* 126 ~ */ { 24, sizeof(simplex_94), simplex_94 }, +}; diff --git a/src/mbgl/geometry/elements_buffer.cpp b/src/mbgl/geometry/elements_buffer.cpp new file mode 100644 index 000000000..3e2e2794d --- /dev/null +++ b/src/mbgl/geometry/elements_buffer.cpp @@ -0,0 +1,16 @@ +#include + +using namespace mbgl; + +void TriangleElementsBuffer::add(element_type a, element_type b, element_type c) { + element_type *elements = static_cast(addElement()); + elements[0] = a; + elements[1] = b; + elements[2] = c; +} + +void LineElementsBuffer::add(element_type a, element_type b) { + element_type *elements = static_cast(addElement()); + elements[0] = a; + elements[1] = b; +} diff --git a/src/mbgl/geometry/elements_buffer.hpp b/src/mbgl/geometry/elements_buffer.hpp new file mode 100644 index 000000000..24753ebaf --- /dev/null +++ b/src/mbgl/geometry/elements_buffer.hpp @@ -0,0 +1,49 @@ +#ifndef MBGL_GEOMETRY_TRIANGLE_ELEMENTS_BUFFER +#define MBGL_GEOMETRY_TRIANGLE_ELEMENTS_BUFFER + +#include +#include + +#include + +#include + +namespace mbgl { + +template +struct ElementGroup : public util::noncopyable { + std::array array; + uint32_t vertex_length; + uint32_t elements_length; + + ElementGroup() : vertex_length(0), elements_length(0) {} + ElementGroup(uint32_t vertex_length_, uint32_t elements_length_) + : vertex_length(vertex_length_), + elements_length(elements_length_) { + } +}; + +class TriangleElementsBuffer : public Buffer< + 6, // bytes per triangle (3 * unsigned short == 6 bytes) + GL_ELEMENT_ARRAY_BUFFER +> { +public: + typedef uint16_t element_type; + + void add(element_type a, element_type b, element_type c); +}; + + +class LineElementsBuffer : public Buffer< + 4, // bytes per triangle (2 * unsigned short == 6 bytes) + GL_ELEMENT_ARRAY_BUFFER +> { +public: + typedef uint16_t element_type; + + void add(element_type a, element_type b); +}; + +} + +#endif diff --git a/src/mbgl/geometry/fill_buffer.cpp b/src/mbgl/geometry/fill_buffer.cpp new file mode 100644 index 000000000..339269943 --- /dev/null +++ b/src/mbgl/geometry/fill_buffer.cpp @@ -0,0 +1,13 @@ +#include + +#include + +#include + +using namespace mbgl; + +void FillVertexBuffer::add(vertex_type x, vertex_type y) { + vertex_type *vertices = static_cast(addElement()); + vertices[0] = x; + vertices[1] = y; +} diff --git a/src/mbgl/geometry/fill_buffer.hpp b/src/mbgl/geometry/fill_buffer.hpp new file mode 100644 index 000000000..2cd1637fa --- /dev/null +++ b/src/mbgl/geometry/fill_buffer.hpp @@ -0,0 +1,21 @@ +#ifndef MBGL_GEOMETRY_FILL_BUFFER +#define MBGL_GEOMETRY_FILL_BUFFER + +#include +#include +#include + +namespace mbgl { + +class FillVertexBuffer : public Buffer< + 4 // bytes per coordinates (2 * unsigned short == 4 bytes) +> { +public: + typedef int16_t vertex_type; + + void add(vertex_type x, vertex_type y); +}; + +} + +#endif diff --git a/src/mbgl/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp new file mode 100644 index 000000000..43ea58553 --- /dev/null +++ b/src/mbgl/geometry/glyph_atlas.cpp @@ -0,0 +1,198 @@ +#include + +#include + +#include +#include +#include + +#include +#include + + +using namespace mbgl; + +GlyphAtlas::GlyphAtlas(uint16_t width_, uint16_t height_) + : width(width_), + height(height_), + bin(width_, height_), + data(std::make_unique(width_ * height_)), + dirty(true) { +} + +void GlyphAtlas::addGlyphs(uintptr_t tileUID, + const std::u32string& text, + const std::string& stackName, + const FontStack& fontStack, + GlyphPositions& face) +{ + std::lock_guard lock(mtx); + + const std::map& sdfs = fontStack.getSDFs(); + + for (uint32_t chr : text) + { + auto sdf_it = sdfs.find(chr); + if (sdf_it == sdfs.end()) { + continue; + } + + const SDFGlyph& sdf = sdf_it->second; + Rect rect = addGlyph(tileUID, stackName, sdf); + face.emplace(chr, Glyph{rect, sdf.metrics}); + } +} + +Rect GlyphAtlas::addGlyph(uintptr_t tileUID, + const std::string& stackName, + const SDFGlyph& glyph) +{ + // Use constant value for now. + const uint8_t buffer = 3; + + std::map& face = index[stackName]; + std::map::iterator it = face.find(glyph.id); + + // The glyph is already in this texture. + if (it != face.end()) { + GlyphValue& value = it->second; + value.ids.insert(tileUID); + return value.rect; + } + + // The glyph bitmap has zero width. + if (glyph.bitmap.empty()) { + return Rect{ 0, 0, 0, 0 }; + } + + uint16_t buffered_width = glyph.metrics.width + buffer * 2; + uint16_t buffered_height = glyph.metrics.height + buffer * 2; + + // Add a 1px border around every image. + const uint16_t padding = 1; + uint16_t pack_width = buffered_width + 2 * padding; + uint16_t pack_height = buffered_height + 2 * padding; + + // Increase to next number divisible by 4, but at least 1. + // This is so we can scale down the texture coordinates and pack them + // into 2 bytes rather than 4 bytes. + pack_width += (4 - pack_width % 4); + pack_height += (4 - pack_height % 4); + + Rect rect = bin.allocate(pack_width, pack_height); + if (rect.w == 0) { + Log::Error(Event::OpenGL, "glyph bitmap overflow"); + return rect; + } + + assert(rect.x + rect.w <= width); + assert(rect.y + rect.h <= height); + + face.emplace(glyph.id, GlyphValue { rect, tileUID }); + + // Copy the bitmap + const uint8_t* source = reinterpret_cast(glyph.bitmap.data()); + for (uint32_t y = 0; y < buffered_height; y++) { + uint32_t y1 = width * (rect.y + y + padding) + rect.x + padding; + uint32_t y2 = buffered_width * y; + for (uint32_t x = 0; x < buffered_width; x++) { + data[y1 + x] = source[y2 + x]; + } + } + + dirty = true; + + return rect; +} + +void GlyphAtlas::removeGlyphs(uintptr_t tileUID) { + std::lock_guard lock(mtx); + + for (auto& faces : index) { + std::map& face = faces.second; + for (auto it = face.begin(); it != face.end(); /* we advance in the body */) { + GlyphValue& value = it->second; + value.ids.erase(tileUID); + + if (value.ids.empty()) { + const Rect& rect = value.rect; + + // Clear out the bitmap. + uint8_t *target = data.get(); + for (uint32_t y = 0; y < rect.h; y++) { + uint32_t y1 = width * (rect.y + y) + rect.x; + for (uint32_t x = 0; x < rect.w; x++) { + target[y1 + x] = 0; + } + } + + bin.release(rect); + + // Make sure to post-increment the iterator: This will return the + // current iterator, but will go to the next position before we + // erase the element from the map. That way, the iterator stays + // valid. + face.erase(it++); + } else { + ++it; + } + } + } +} + +void GlyphAtlas::upload() { + if (dirty) { + const bool first = !texture; + bind(); + + std::lock_guard lock(mtx); + + if (first) { + MBGL_CHECK_ERROR(glTexImage2D( + GL_TEXTURE_2D, // GLenum target + 0, // GLint level + GL_ALPHA, // GLint internalformat + width, // GLsizei width + height, // GLsizei height + 0, // GLint border + GL_ALPHA, // GLenum format + GL_UNSIGNED_BYTE, // GLenum type + data.get() // const GLvoid* data + )); + } else { + MBGL_CHECK_ERROR(glTexSubImage2D( + GL_TEXTURE_2D, // GLenum target + 0, // GLint level + 0, // GLint xoffset + 0, // GLint yoffset + width, // GLsizei width + height, // GLsizei height + GL_ALPHA, // GLenum format + GL_UNSIGNED_BYTE, // GLenum type + data.get() // const GLvoid* data + )); + } + + dirty = false; + +#if defined(DEBUG) + // platform::showDebugImage("Glyph Atlas", reinterpret_cast(data.get()), width, height); +#endif + } +} + +void GlyphAtlas::bind() { + if (!texture) { + MBGL_CHECK_ERROR(glGenTextures(1, &texture)); + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); +#ifndef GL_ES_VERSION_2_0 + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); +#endif + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + } else { + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); + } +}; diff --git a/src/mbgl/geometry/glyph_atlas.hpp b/src/mbgl/geometry/glyph_atlas.hpp new file mode 100644 index 000000000..8bc21da09 --- /dev/null +++ b/src/mbgl/geometry/glyph_atlas.hpp @@ -0,0 +1,59 @@ +#ifndef MBGL_GEOMETRY_GLYPH_ATLAS +#define MBGL_GEOMETRY_GLYPH_ATLAS + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace mbgl { + +class GlyphAtlas : public util::noncopyable { +public: + GlyphAtlas(uint16_t width, uint16_t height); + + void addGlyphs(uintptr_t tileUID, + const std::u32string& text, + const std::string& stackName, + const FontStack&, + GlyphPositions&); + void removeGlyphs(uintptr_t tileUID); + + // Binds the atlas texture to the GPU, and uploads data if it is out of date. + void bind(); + + // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; + // the texture is only bound when the data is out of date (=dirty). + void upload(); + + const uint16_t width = 0; + const uint16_t height = 0; + +private: + struct GlyphValue { + GlyphValue(const Rect& rect_, uintptr_t id) + : rect(rect_), ids({ id }) {} + Rect rect; + std::set ids; + }; + + Rect addGlyph(uintptr_t tileID, + const std::string& stackName, + const SDFGlyph&); + + std::mutex mtx; + BinPack bin; + std::map> index; + const std::unique_ptr data; + std::atomic dirty; + uint32_t texture = 0; +}; + +}; + +#endif diff --git a/src/mbgl/geometry/icon_buffer.cpp b/src/mbgl/geometry/icon_buffer.cpp new file mode 100644 index 000000000..831ffc72a --- /dev/null +++ b/src/mbgl/geometry/icon_buffer.cpp @@ -0,0 +1,32 @@ +#include +#include +#include + +#include + +namespace mbgl { + +size_t IconVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, int16_t tx, int16_t ty, float minzoom, float maxzoom, float labelminzoom) { + const size_t idx = index(); + void *data = addElement(); + + int16_t *shorts = static_cast(data); + shorts[0] /* pos */ = x; + shorts[1] /* pos */ = y; + shorts[2] /* offset */ = ::round(ox * 64); // use 1/64 pixels for placement + shorts[3] /* offset */ = ::round(oy * 64); + + uint8_t *ubytes = static_cast(data); + // a_data1 + ubytes[8] /* tex */ = tx / 4; + ubytes[9] /* tex */ = ty / 4; + ubytes[10] /* labelminzoom */ = labelminzoom * 10; + + // a_data2 + ubytes[12] /* minzoom */ = minzoom * 10; // 1/10 zoom levels: z16 == 160. + ubytes[13] /* maxzoom */ = ::fmin(maxzoom, 25) * 10; // 1/10 zoom levels: z16 == 160. + + return idx; +} + +} diff --git a/src/mbgl/geometry/icon_buffer.hpp b/src/mbgl/geometry/icon_buffer.hpp new file mode 100644 index 000000000..95469929c --- /dev/null +++ b/src/mbgl/geometry/icon_buffer.hpp @@ -0,0 +1,20 @@ +#ifndef MBGL_GEOMETRY_ICON_BUFFER +#define MBGL_GEOMETRY_ICON_BUFFER + +#include + +#include + +namespace mbgl { + + class IconVertexBuffer : public Buffer< + 16 + > { + public: + size_t add(int16_t x, int16_t y, float ox, float oy, int16_t tx, int16_t ty, float minzoom, float maxzoom, float labelminzoom); + + }; + +} + +#endif diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp new file mode 100644 index 000000000..aeac3067e --- /dev/null +++ b/src/mbgl/geometry/line_atlas.cpp @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace mbgl; + +LineAtlas::LineAtlas(uint16_t w, uint16_t h) + : width(w), + height(h), + data(std::make_unique(w * h)), + dirty(true) { +} + +LineAtlas::~LineAtlas() { + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + if (texture) { + mbgl::util::ThreadContext::getGLObjectStore()->abandonTexture(texture); + texture = 0; + } +} + +LinePatternPos LineAtlas::getDashPosition(const std::vector &dasharray, bool round) { + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + size_t key = round ? std::numeric_limits::min() : std::numeric_limits::max(); + for (const float part : dasharray) { + boost::hash_combine(key, part); + } + + // Note: We're not handling hash collisions here. + const auto it = positions.find(key); + if (it == positions.end()) { + auto inserted = positions.emplace(key, addDash(dasharray, round)); + assert(inserted.second); + return inserted.first->second; + } else { + return it->second; + } +} + +LinePatternPos LineAtlas::addDash(const std::vector &dasharray, bool round) { + + int n = round ? 7 : 0; + int dashheight = 2 * n + 1; + const uint8_t offset = 128; + + if (nextRow + dashheight > height) { + Log::Warning(Event::OpenGL, "line atlas bitmap overflow"); + return LinePatternPos(); + } + + float length = 0; + for (const float part : dasharray) { + length += part; + } + + float stretch = width / length; + float halfWidth = stretch * 0.5; + // If dasharray has an odd length, both the first and last parts + // are dashes and should be joined seamlessly. + bool oddLength = dasharray.size() % 2 == 1; + + for (int y = -n; y <= n; y++) { + int row = nextRow + n + y; + int index = width * row; + + float left = 0; + float right = dasharray[0]; + unsigned int partIndex = 1; + + if (oddLength) { + left -= dasharray.back(); + } + + for (int x = 0; x < width; x++) { + + while (right < x / stretch) { + left = right; + right = right + dasharray[partIndex]; + + if (oddLength && partIndex == dasharray.size() - 1) { + right += dasharray.front(); + } + + partIndex++; + } + + float distLeft = fabs(x - left * stretch); + float distRight = fabs(x - right * stretch); + float dist = fmin(distLeft, distRight); + bool inside = (partIndex % 2) == 1; + int signedDistance; + + if (round) { + float distMiddle = n ? (float)y / n * (halfWidth + 1) : 0; + if (inside) { + float distEdge = halfWidth - fabs(distMiddle); + signedDistance = sqrt(dist * dist + distEdge * distEdge); + } else { + signedDistance = halfWidth - sqrt(dist * dist + distMiddle * distMiddle); + } + + } else { + signedDistance = int((inside ? 1 : -1) * dist); + } + + data[index + x] = fmax(0, fmin(255, signedDistance + offset)); + } + } + + LinePatternPos position; + position.y = (0.5 + nextRow + n) / height; + position.height = (2.0 * n) / height; + position.width = length; + + nextRow += dashheight; + + dirty = true; + bind(); + + return position; +}; + +void LineAtlas::upload() { + if (dirty) { + bind(); + } +} + +void LineAtlas::bind() { + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + bool first = false; + if (!texture) { + MBGL_CHECK_ERROR(glGenTextures(1, &texture)); + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + first = true; + } else { + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); + } + + if (dirty) { + if (first) { + MBGL_CHECK_ERROR(glTexImage2D( + GL_TEXTURE_2D, // GLenum target + 0, // GLint level + GL_ALPHA, // GLint internalformat + width, // GLsizei width + height, // GLsizei height + 0, // GLint border + GL_ALPHA, // GLenum format + GL_UNSIGNED_BYTE, // GLenum type + data.get() // const GLvoid * data + )); + } else { + MBGL_CHECK_ERROR(glTexSubImage2D( + GL_TEXTURE_2D, // GLenum target + 0, // GLint level + 0, // GLint xoffset + 0, // GLint yoffset + width, // GLsizei width + height, // GLsizei height + GL_ALPHA, // GLenum format + GL_UNSIGNED_BYTE, // GLenum type + data.get() // const GLvoid *pixels + )); + } + + + dirty = false; + } +}; diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp new file mode 100644 index 000000000..3c3b90f75 --- /dev/null +++ b/src/mbgl/geometry/line_atlas.hpp @@ -0,0 +1,44 @@ +#ifndef MBGL_GEOMETRY_LINE_ATLAS +#define MBGL_GEOMETRY_LINE_ATLAS + +#include +#include +#include + +namespace mbgl { + +typedef struct { + float width; + float height; + float y; +} LinePatternPos; + +class LineAtlas { +public: + LineAtlas(uint16_t width, uint16_t height); + ~LineAtlas(); + + // Binds the atlas texture to the GPU, and uploads data if it is out of date. + void bind(); + + // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; + // the texture is only bound when the data is out of date (=dirty). + void upload(); + + LinePatternPos getDashPosition(const std::vector&, bool); + LinePatternPos addDash(const std::vector &dasharray, bool round); + + const int width; + const int height; + +private: + const std::unique_ptr data; + bool dirty; + uint32_t texture = 0; + int nextRow = 0; + std::map positions; +}; + +}; + +#endif diff --git a/src/mbgl/geometry/line_buffer.cpp b/src/mbgl/geometry/line_buffer.cpp new file mode 100644 index 000000000..f475c63b2 --- /dev/null +++ b/src/mbgl/geometry/line_buffer.cpp @@ -0,0 +1,23 @@ +#include +#include + +#include + +using namespace mbgl; + +size_t LineVertexBuffer::add(vertex_type x, vertex_type y, float ex, float ey, int8_t tx, int8_t ty, int32_t linesofar) { + size_t idx = index(); + void *data = addElement(); + + int16_t *coords = static_cast(data); + coords[0] = (x * 2) | tx; + coords[1] = (y * 2) | ty; + + int8_t *extrude = static_cast(data); + extrude[4] = ::round(extrudeScale * ex); + extrude[5] = ::round(extrudeScale * ey); + extrude[6] = static_cast(linesofar / 128); + extrude[7] = static_cast(linesofar % 128); + + return idx; +} diff --git a/src/mbgl/geometry/line_buffer.hpp b/src/mbgl/geometry/line_buffer.hpp new file mode 100644 index 000000000..1c217b59d --- /dev/null +++ b/src/mbgl/geometry/line_buffer.hpp @@ -0,0 +1,39 @@ +#ifndef MBGL_GEOMETRY_LINE_BUFFER +#define MBGL_GEOMETRY_LINE_BUFFER + +#include + +namespace mbgl { + +class LineVertexBuffer : public Buffer< + 8 // 2 coordinates per vertex + 1 linesofar + 1 extrude coord pair == 4 (== 8 bytes) +> { +public: + typedef int16_t vertex_type; + + /* + * Scale the extrusion vector so that the normal length is this value. + * Contains the "texture" normals (-1..1). This is distinct from the extrude + * normals for line joins, because the x-value remains 0 for the texture + * normal array, while the extrude normal actually moves the vertex to create + * the acute/bevelled line join. + */ + static const int8_t extrudeScale = 63; + + /* + * Add a vertex to this buffer + * + * @param {number} x vertex position + * @param {number} y vertex position + * @param {number} ex extrude normal + * @param {number} ey extrude normal + * @param {number} tx texture normal + * @param {number} ty texture normal + */ + size_t add(vertex_type x, vertex_type y, float ex, float ey, int8_t tx, int8_t ty, int32_t linesofar = 0); +}; + + +} + +#endif diff --git a/src/mbgl/geometry/sprite_atlas.cpp b/src/mbgl/geometry/sprite_atlas.cpp new file mode 100644 index 000000000..743848d5f --- /dev/null +++ b/src/mbgl/geometry/sprite_atlas.cpp @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +using namespace mbgl; + +SpriteAtlas::SpriteAtlas(dimension width_, dimension height_, float pixelRatio_, SpriteStore& store_) + : width(width_), + height(height_), + pixelWidth(std::ceil(width * pixelRatio_)), + pixelHeight(std::ceil(height * pixelRatio_)), + pixelRatio(pixelRatio_), + store(store_), + bin(width_, height_), + data(std::make_unique(pixelWidth * pixelHeight)), + dirty(true) { + std::fill(data.get(), data.get() + pixelWidth * pixelHeight, 0); +} + +Rect SpriteAtlas::allocateImage(const size_t pixel_width, const size_t pixel_height) { + // Increase to next number divisible by 4, but at least 1. + // This is so we can scale down the texture coordinates and pack them + // into 2 bytes rather than 4 bytes. + const uint16_t pack_width = (pixel_width + 1) + (4 - (pixel_width + 1) % 4); + const uint16_t pack_height = (pixel_height + 1) + (4 - (pixel_height + 1) % 4); + + // We have to allocate a new area in the bin, and store an empty image in it. + // Add a 1px border around every image. + Rect rect = bin.allocate(pack_width, pack_height); + if (rect.w == 0) { + return rect; + } + + rect.originalW = pixel_width; + rect.originalH = pixel_height; + + return rect; +} + +SpriteAtlasElement SpriteAtlas::getImage(const std::string& name, const bool wrap) { + std::lock_guard lock(mtx); + + auto rect_it = images.find({ name, wrap }); + if (rect_it != images.end()) { + return { rect_it->second.pos, rect_it->second.texture }; + } + + auto sprite = store.getSprite(name); + if (!sprite) { + return { Rect { 0, 0, 0, 0 }, nullptr }; + } + + Rect rect = allocateImage(sprite->width, sprite->height); + if (rect.w == 0) { + if (debug::spriteWarnings) { + Log::Warning(Event::Sprite, "sprite atlas bitmap overflow"); + } + return { Rect { 0, 0, 0, 0 }, nullptr }; + } + + const Holder& holder = images.emplace(Key{ name, wrap }, Holder{ sprite, rect }).first->second; + copy(holder, wrap); + + return { rect, sprite }; +} + +SpriteAtlasPosition SpriteAtlas::getPosition(const std::string& name, bool repeating) { + std::lock_guard lock(mtx); + + auto rect = getImage(name, repeating).pos; + if (repeating) { + // When the image is repeating, get the correct position of the image, rather than the + // one rounded up to 4 pixels. + // TODO: Can't we just use originalW/originalH? + auto sprite = store.getSprite(name); + if (!sprite) { + return SpriteAtlasPosition {}; + } + + rect.w = sprite->width; + rect.h = sprite->height; + } + + const float padding = 1; + + return SpriteAtlasPosition { + {{ float(rect.w), float(rect.h) }}, + {{ float(rect.x + padding) / width, float(rect.y + padding) / height }}, + {{ float(rect.x + padding + rect.w) / width, float(rect.y + padding + rect.h) / height }} + }; +} + +void SpriteAtlas::copy(const Holder& holder, const bool wrap) { + const uint32_t *srcData = reinterpret_cast(holder.texture->data.data()); + if (!srcData) return; + const vec2 srcSize { holder.texture->pixelWidth, holder.texture->pixelHeight }; + const Rect srcPos { 0, 0, srcSize.x, srcSize.y }; + const auto& dst = holder.pos; + + const int offset = 1; + + uint32_t *const dstData = data.get(); + const vec2 dstSize{ pixelWidth, pixelHeight }; + const Rect dstPos{ static_cast((offset + dst.x) * pixelRatio), + static_cast((offset + dst.y) * pixelRatio), + static_cast(dst.originalW * pixelRatio), + static_cast(dst.originalH * pixelRatio) }; + + util::bilinearScale(srcData, srcSize, srcPos, dstData, dstSize, dstPos, wrap); + + // Add borders around the copied image if required. + if (wrap) { + // We're copying from the same image so we don't have to scale again. + const uint32_t border = 1; + const uint32_t borderX = dstPos.x != 0 ? border : 0; + const uint32_t borderY = dstPos.y != 0 ? border : 0; + + // Left border + util::nearestNeighborScale( + dstData, dstSize, { dstPos.x + dstPos.w - borderX, dstPos.y, borderX, dstPos.h }, + dstData, dstSize, { dstPos.x - borderX, dstPos.y, borderX, dstPos.h }); + + // Right border + util::nearestNeighborScale(dstData, dstSize, { dstPos.x, dstPos.y, border, dstPos.h }, + dstData, dstSize, + { dstPos.x + dstPos.w, dstPos.y, border, dstPos.h }); + + // Top border + util::nearestNeighborScale( + dstData, dstSize, { dstPos.x - borderX, dstPos.y + dstPos.h - borderY, + dstPos.w + border + borderX, borderY }, + dstData, dstSize, + { dstPos.x - borderX, dstPos.y - borderY, dstPos.w + 2 * borderX, borderY }); + + // Bottom border + util::nearestNeighborScale( + dstData, dstSize, { dstPos.x - borderX, dstPos.y, dstPos.w + 2 * borderX, border }, + dstData, dstSize, + { dstPos.x - borderX, dstPos.y + dstPos.h, dstPos.w + border + borderX, border }); + } + + dirty = true; +} + +void SpriteAtlas::upload() { + if (dirty) { + bind(); + } +} + +void SpriteAtlas::updateDirty() { + auto dirtySprites = store.getDirty(); + if (dirtySprites.empty()) { + return; + } + + std::lock_guard lock(mtx); + + auto imageIterator = images.begin(); + auto spriteIterator = dirtySprites.begin(); + while (imageIterator != images.end() && spriteIterator != dirtySprites.end()) { + if (imageIterator->first.first < spriteIterator->first) { + ++imageIterator; + } else if (spriteIterator->first < imageIterator->first.first) { + ++spriteIterator; + } else { + // The two names match; + Holder& holder = imageIterator->second; + holder.texture = spriteIterator->second; + copy(holder, imageIterator->first.second); + + ++imageIterator; + // Don't advance the spriteIterator because there might be another sprite with the same + // name, but a different wrap value. + } + } +} + +void SpriteAtlas::bind(bool linear) { + if (!texture) { + MBGL_CHECK_ERROR(glGenTextures(1, &texture)); + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); +#ifndef GL_ES_VERSION_2_0 + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); +#endif + // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures. + // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus. + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + fullUploadRequired = true; + } else { + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); + } + + GLuint filter_val = linear ? GL_LINEAR : GL_NEAREST; + if (filter_val != filter) { + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_val)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_val)); + filter = filter_val; + } + + if (dirty) { + std::lock_guard lock(mtx); + + if (fullUploadRequired) { + MBGL_CHECK_ERROR(glTexImage2D( + GL_TEXTURE_2D, // GLenum target + 0, // GLint level + GL_RGBA, // GLint internalformat + pixelWidth, // GLsizei width + pixelHeight, // GLsizei height + 0, // GLint border + GL_RGBA, // GLenum format + GL_UNSIGNED_BYTE, // GLenum type + data.get() // const GLvoid * data + )); + fullUploadRequired = false; + } else { + MBGL_CHECK_ERROR(glTexSubImage2D( + GL_TEXTURE_2D, // GLenum target + 0, // GLint level + 0, // GLint xoffset + 0, // GLint yoffset + pixelWidth, // GLsizei width + pixelHeight, // GLsizei height + GL_RGBA, // GLenum format + GL_UNSIGNED_BYTE, // GLenum type + data.get() // const GLvoid *pixels + )); + } + + dirty = false; + +#ifndef GL_ES_VERSION_2_0 + // platform::showColorDebugImage("Sprite Atlas", reinterpret_cast(data.get()), + // pixelWidth, pixelHeight, pixelWidth, pixelHeight); +#endif + } +}; + +SpriteAtlas::~SpriteAtlas() { + std::lock_guard lock(mtx); + if (texture) { + mbgl::util::ThreadContext::getGLObjectStore()->abandonTexture(texture); + texture = 0; + } +} + +SpriteAtlas::Holder::Holder(const std::shared_ptr& texture_, + const Rect& pos_) + : texture(texture_), pos(pos_) { +} + +SpriteAtlas::Holder::Holder(Holder&& h) : texture(std::move(h.texture)), pos(h.pos) { +} diff --git a/src/mbgl/geometry/sprite_atlas.hpp b/src/mbgl/geometry/sprite_atlas.hpp new file mode 100644 index 000000000..bfe4f843d --- /dev/null +++ b/src/mbgl/geometry/sprite_atlas.hpp @@ -0,0 +1,103 @@ +#ifndef MBGL_GEOMETRY_SPRITE_ATLAS +#define MBGL_GEOMETRY_SPRITE_ATLAS + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace mbgl { + +class SpriteStore; +class SpriteImage; +class SpritePosition; + +struct SpriteAtlasPosition { + inline SpriteAtlasPosition(const std::array size_ = {{0, 0}}, + const std::array tl_ = {{0, 0}}, + const std::array br_ = {{0, 0}}) + : size(size_), tl(tl_), br(br_) {} + std::array size; + std::array tl; + std::array br; +}; + +struct SpriteAtlasElement { + const Rect pos; + const std::shared_ptr texture; +}; + +class SpriteAtlas : public util::noncopyable { +public: + typedef uint16_t dimension; + + SpriteAtlas(dimension width, dimension height, float pixelRatio, SpriteStore& store); + ~SpriteAtlas(); + + // Returns the coordinates of an image that is sourced from the sprite image. + // This getter attempts to read the image from the sprite if it is already loaded. + // In that case, it copies it into the sprite atlas and returns the dimensions. + // Otherwise, it returns a 0/0/0/0 rect. + // This function is used during bucket creation. + SpriteAtlasElement getImage(const std::string& name, const bool wrap); + + // This function is used for getting the position during render time. + SpriteAtlasPosition getPosition(const std::string& name, bool repeating = false); + + // Binds the atlas texture to the GPU, and uploads data if it is out of date. + void bind(bool linear = false); + + // Updates sprites in the atlas texture that may have changed in the source SpriteStore object. + void updateDirty(); + + // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; + // the texture is only bound when the data is out of date (=dirty). + void upload(); + + inline dimension getWidth() const { return width; } + inline dimension getHeight() const { return height; } + inline dimension getTextureWidth() const { return pixelWidth; } + inline dimension getTextureHeight() const { return pixelHeight; } + inline float getPixelRatio() const { return pixelRatio; } + inline const uint32_t* getData() const { return data.get(); } + +private: + const dimension width, height; + const dimension pixelWidth, pixelHeight; + const float pixelRatio; + + struct Holder : private util::noncopyable { + inline Holder(const std::shared_ptr&, const Rect&); + inline Holder(Holder&&); + std::shared_ptr texture; + const Rect pos; + }; + + using Key = std::pair; + + Rect allocateImage(size_t width, size_t height); + void copy(const Holder& holder, const bool wrap); + + std::recursive_mutex mtx; + SpriteStore& store; + BinPack bin; + std::map images; + std::set uninitialized; + const std::unique_ptr data; + std::atomic dirty; + bool fullUploadRequired = true; + uint32_t texture = 0; + uint32_t filter = 0; + static const int buffer = 1; +}; + +}; + +#endif diff --git a/src/mbgl/geometry/static_vertex_buffer.cpp b/src/mbgl/geometry/static_vertex_buffer.cpp new file mode 100644 index 000000000..c1e8caab9 --- /dev/null +++ b/src/mbgl/geometry/static_vertex_buffer.cpp @@ -0,0 +1,14 @@ +#include +#include + +namespace mbgl { + +StaticVertexBuffer::StaticVertexBuffer(std::initializer_list> init) { + for (const auto& vertex : init) { + vertex_type *vertices = static_cast(addElement()); + vertices[0] = vertex.first; + vertices[1] = vertex.second; + } +} + +} diff --git a/src/mbgl/geometry/static_vertex_buffer.hpp b/src/mbgl/geometry/static_vertex_buffer.hpp new file mode 100644 index 000000000..ce932269f --- /dev/null +++ b/src/mbgl/geometry/static_vertex_buffer.hpp @@ -0,0 +1,26 @@ +#ifndef MBGL_GEOMETRY_STATIC_VERTEX_BUFFER +#define MBGL_GEOMETRY_STATIC_VERTEX_BUFFER + +#include + +#include +#include +#include +#include + +namespace mbgl { + +class StaticVertexBuffer : public Buffer< + 4, // bytes per vertex (2 * signed short == 4 bytes) + GL_ARRAY_BUFFER, + 32 // default length +> { +public: + typedef int16_t vertex_type; + + StaticVertexBuffer(std::initializer_list> init); +}; + +} + +#endif diff --git a/src/mbgl/geometry/text_buffer.cpp b/src/mbgl/geometry/text_buffer.cpp new file mode 100644 index 000000000..8f312c9fa --- /dev/null +++ b/src/mbgl/geometry/text_buffer.cpp @@ -0,0 +1,32 @@ +#include +#include +#include + +#include + +namespace mbgl { + +size_t TextVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, uint16_t tx, uint16_t ty, float minzoom, float maxzoom, float labelminzoom) { + const size_t idx = index(); + void *data = addElement(); + + int16_t *shorts = static_cast(data); + shorts[0] /* pos */ = x; + shorts[1] /* pos */ = y; + shorts[2] /* offset */ = ::round(ox * 64); // use 1/64 pixels for placement + shorts[3] /* offset */ = ::round(oy * 64); + + uint8_t *ubytes = static_cast(data); + // a_data1 + ubytes[8] /* tex */ = tx / 4; + ubytes[9] /* tex */ = ty / 4; + ubytes[10] /* labelminzoom */ = labelminzoom * 10; + + // a_data2 + ubytes[12] /* minzoom */ = minzoom * 10; // 1/10 zoom levels: z16 == 160. + ubytes[13] /* maxzoom */ = ::fmin(maxzoom, 25) * 10; // 1/10 zoom levels: z16 == 160. + + return idx; +} + +} diff --git a/src/mbgl/geometry/text_buffer.hpp b/src/mbgl/geometry/text_buffer.hpp new file mode 100644 index 000000000..895d47237 --- /dev/null +++ b/src/mbgl/geometry/text_buffer.hpp @@ -0,0 +1,23 @@ +#ifndef MBGL_GEOMETRY_TEXT_BUFFER +#define MBGL_GEOMETRY_TEXT_BUFFER + +#include +#include + +namespace mbgl { + +class TextVertexBuffer : public Buffer < + 16, + GL_ARRAY_BUFFER, + 32768 +> { +public: + typedef int16_t vertex_type; + + size_t add(int16_t x, int16_t y, float ox, float oy, uint16_t tx, uint16_t ty, float minzoom, float maxzoom, float labelminzoom); +}; + + +} + +#endif diff --git a/src/mbgl/geometry/vao.cpp b/src/mbgl/geometry/vao.cpp new file mode 100644 index 000000000..ef4cb26db --- /dev/null +++ b/src/mbgl/geometry/vao.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include + +namespace mbgl { + +static gl::ExtensionFunction< + void (GLuint array)> + BindVertexArray({ + {"GL_ARB_vertex_array_object", "glBindVertexArray"}, + {"GL_OES_vertex_array_object", "glBindVertexArrayOES"}, + {"GL_APPLE_vertex_array_object", "glBindVertexArrayAPPLE"} + }); + +static gl::ExtensionFunction< + void (GLsizei n, + const GLuint* arrays)> + DeleteVertexArrays({ + {"GL_ARB_vertex_array_object", "glDeleteVertexArrays"}, + {"GL_OES_vertex_array_object", "glDeleteVertexArraysOES"}, + {"GL_APPLE_vertex_array_object", "glDeleteVertexArraysAPPLE"} + }); + +static gl::ExtensionFunction< + void (GLsizei n, + GLuint* arrays)> + GenVertexArrays({ + {"GL_ARB_vertex_array_object", "glGenVertexArrays"}, + {"GL_OES_vertex_array_object", "glGenVertexArraysOES"}, + {"GL_APPLE_vertex_array_object", "glGenVertexArraysAPPLE"} + }); + +void VertexArrayObject::Unbind() { + if (!BindVertexArray) return; + MBGL_CHECK_ERROR(BindVertexArray(0)); +} + +void VertexArrayObject::Delete(GLsizei n, const GLuint* arrays) { + MBGL_CHECK_ERROR(DeleteVertexArrays(n, arrays)); +} + +VertexArrayObject::VertexArrayObject() { +} + +VertexArrayObject::~VertexArrayObject() { + if (!DeleteVertexArrays) return; + + if (vao) { + util::ThreadContext::getGLObjectStore()->abandonVAO(vao); + } +} + +void VertexArrayObject::bindVertexArrayObject() { + if (!GenVertexArrays || !BindVertexArray) { + static bool reported = false; + if (!reported) { + Log::Warning(Event::OpenGL, "Not using Vertex Array Objects"); + reported = true; + } + return; + } + + if (!vao) { + MBGL_CHECK_ERROR(GenVertexArrays(1, &vao)); + } + MBGL_CHECK_ERROR(BindVertexArray(vao)); +} + +void VertexArrayObject::verifyBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer, + char *offset) { + if (bound_shader != shader.getID()) { + throw std::runtime_error(std::string("trying to rebind VAO to another shader from " + + util::toString(bound_shader) + "(" + bound_shader_name + ") to " + + util::toString(shader.getID()) + "(" + shader.name + ")" )); + } else if (bound_offset != offset) { + throw std::runtime_error("trying to bind VAO to another offset"); + } else if (bound_vertex_buffer != vertexBuffer) { + throw std::runtime_error("trying to bind VAO to another vertex buffer"); + } else if (bound_elements_buffer != elementsBuffer) { + throw std::runtime_error("trying to bind VAO to another elements buffer"); + } +} + +void VertexArrayObject::storeBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer, + char *offset) { + bound_shader = shader.getID(); + bound_shader_name = shader.name; + bound_offset = offset; + bound_vertex_buffer = vertexBuffer; + bound_elements_buffer = elementsBuffer; +} + +} diff --git a/src/mbgl/geometry/vao.hpp b/src/mbgl/geometry/vao.hpp new file mode 100644 index 000000000..e512a3e48 --- /dev/null +++ b/src/mbgl/geometry/vao.hpp @@ -0,0 +1,71 @@ +#ifndef MBGL_GEOMETRY_VAO +#define MBGL_GEOMETRY_VAO + +#include +#include +#include + +#include + +namespace mbgl { + +class VertexArrayObject : public util::noncopyable { +public: + static void Unbind(); + static void Delete(GLsizei n, const GLuint* arrays); + + VertexArrayObject(); + ~VertexArrayObject(); + + template + inline void bind(Shader& shader, VertexBuffer &vertexBuffer, char *offset) { + bindVertexArrayObject(); + if (bound_shader == 0) { + vertexBuffer.bind(); + shader.bind(offset); + if (vao) { + storeBinding(shader, vertexBuffer.getID(), 0, offset); + } + } else { + verifyBinding(shader, vertexBuffer.getID(), 0, offset); + } + } + + template + inline void bind(Shader& shader, VertexBuffer &vertexBuffer, ElementsBuffer &elementsBuffer, char *offset) { + bindVertexArrayObject(); + if (bound_shader == 0) { + vertexBuffer.bind(); + elementsBuffer.bind(); + shader.bind(offset); + if (vao) { + storeBinding(shader, vertexBuffer.getID(), elementsBuffer.getID(), offset); + } + } else { + verifyBinding(shader, vertexBuffer.getID(), elementsBuffer.getID(), offset); + } + } + + inline GLuint getID() const { + return vao; + } + +private: + void bindVertexArrayObject(); + void storeBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer, char *offset); + void verifyBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer, char *offset); + + GLuint vao = 0; + + // For debug reasons, we're storing the bind information so that we can + // detect errors and report + GLuint bound_shader = 0; + const char *bound_shader_name = ""; + GLuint bound_vertex_buffer = 0; + GLuint bound_elements_buffer = 0; + char *bound_offset = 0; +}; + +} + +#endif diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp new file mode 100644 index 000000000..006112704 --- /dev/null +++ b/src/mbgl/gl/debugging.cpp @@ -0,0 +1,190 @@ +#include +#include +#include +#include + +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_DISPLAY_LIST 0x82E7 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TEXTURE 0x1702 +#define GL_RENDERBUFFER 0x8D41 +#define GL_FRAMEBUFFER 0x8D40 + +namespace mbgl { +namespace gl { +namespace debugging { + +typedef void (*GLDEBUGPROC)(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar *message, + const void *userParam); + +static ExtensionFunction< + void (GLenum source, + GLenum type, + GLenum severity, + GLsizei count, + const GLuint *ids, + GLboolean enabled)> + DebugMessageControl({ + {"GL_KHR_debug", "glDebugMessageControl"}, + {"GL_ARB_debug_output", "glDebugMessageControlARB"} + }); + +static ExtensionFunction< + void (GLDEBUGPROC callback, + const void *userParam)> + DebugMessageCallback({ + {"GL_KHR_debug", "glDebugMessageCallback"}, + {"GL_ARB_debug_output", "glDebugMessageCallbackARB"} + }); + +static ExtensionFunction< + void (GLenum source, + GLuint id, + GLsizei length, + const GLchar *message)> + PushDebugGroup({ + {"GL_KHR_debug", "glPushDebugGroup"} + }); + +static ExtensionFunction< + void ()> + PopDebugGroup({ + {"GL_KHR_debug", "glPopDebugGroup"} + }); + +static ExtensionFunction< + void (GLsizei length, + const GLchar *marker)> + PushGroupMarkerEXT({ + {"GL_EXT_debug_marker", "glPushGroupMarkerEXT"} + }); + +static ExtensionFunction< + void ()> + PopGroupMarkerEXT({ + {"GL_EXT_debug_marker", "glPopGroupMarkerEXT"} + }); + +void debugCallback(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei /*length*/, + const GLchar* message, + const void* /*userParam*/) +{ + std::string strSource; + switch (source) { + case GL_DEBUG_SOURCE_API: strSource = "DEBUG_SOURCE_API"; break; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: strSource = "DEBUG_SOURCE_WINDOW_SYSTEM"; break; + case GL_DEBUG_SOURCE_SHADER_COMPILER: strSource = "DEBUG_SOURCE_SHADER_COMPILER"; break; + case GL_DEBUG_SOURCE_THIRD_PARTY: strSource = "DEBUG_SOURCE_THIRD_PARTY"; break; + case GL_DEBUG_SOURCE_APPLICATION: strSource = "DEBUG_SOURCE_APPLICATION"; break; + case GL_DEBUG_SOURCE_OTHER: strSource = "DEBUG_SOURCE_OTHER"; break; + default: strSource = "(unknown)"; break; + } + + std::string strType; + switch (type) { + case GL_DEBUG_TYPE_ERROR: strType = "DEBUG_TYPE_ERROR"; break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: strType = "DEBUG_TYPE_DEPRECATED_BEHAVIOR"; break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: strType = "DEBUG_TYPE_UNDEFINED_BEHAVIOR"; break; + case GL_DEBUG_TYPE_PERFORMANCE: strType = "DEBUG_TYPE_PERFORMANCE"; break; + case GL_DEBUG_TYPE_PORTABILITY: strType = "DEBUG_TYPE_PORTABILITY"; break; + case GL_DEBUG_TYPE_OTHER: strType = "DEBUG_TYPE_OTHER"; break; + case GL_DEBUG_TYPE_MARKER: strType = "DEBUG_TYPE_MARKER"; break; + case GL_DEBUG_TYPE_PUSH_GROUP: strType = "DEBUG_TYPE_OTHER"; break; + case GL_DEBUG_TYPE_POP_GROUP: strType = "DEBUG_TYPE_POP_GROUP"; break; + default: strSource = "(unknown)"; break; + } + + std::string strSeverity; + mbgl::EventSeverity evtSeverity; + switch (severity) { + case GL_DEBUG_SEVERITY_HIGH: strSeverity = "DEBUG_SEVERITY_HIGH"; evtSeverity = mbgl::EventSeverity::Error; break; + case GL_DEBUG_SEVERITY_MEDIUM: strSeverity = "DEBUG_SEVERITY_MEDIUM"; evtSeverity = mbgl::EventSeverity::Warning; break; + case GL_DEBUG_SEVERITY_LOW: strSeverity = "DEBUG_SEVERITY_LOW"; evtSeverity = mbgl::EventSeverity::Info; break; + case GL_DEBUG_SEVERITY_NOTIFICATION: strSeverity = "DEBUG_SEVERITY_NOTIFICATION"; evtSeverity = mbgl::EventSeverity::Debug; break; + default: strSource = "(unknown)"; evtSeverity = mbgl::EventSeverity::Debug; break; + } + + mbgl::Log::Record(evtSeverity, mbgl::Event::OpenGL, "GL_%s GL_%s %u GL_%s - %s", strSource.c_str(), strType.c_str(), id, strSeverity.c_str(), message); +} + +void enable() { + if (!DebugMessageControl || !DebugMessageCallback) { + return; + } + + // This will enable all messages including performance hints + //MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE)); + + // This will only enable high and medium severity messages + MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE)); + MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, GL_TRUE)); + MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE)); + + MBGL_CHECK_ERROR(DebugMessageCallback(debugCallback, nullptr)); +} + +group::group(const std::string& str) { + if (PushDebugGroup) { + PushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, GLsizei(str.size()), str.c_str()); + } else if (PushGroupMarkerEXT) { + PushGroupMarkerEXT(GLsizei(str.size() + 1), str.c_str()); + } +} + +group::~group() { + if (PopDebugGroup) { + PopDebugGroup(); + } else if (PopGroupMarkerEXT) { + PopGroupMarkerEXT(); + } +} + +} +} +} diff --git a/src/mbgl/gl/debugging.hpp b/src/mbgl/gl/debugging.hpp new file mode 100644 index 000000000..046f0169d --- /dev/null +++ b/src/mbgl/gl/debugging.hpp @@ -0,0 +1,29 @@ +#ifndef MBGL_GL_DEBUG_MESSAGES +#define MBGL_GL_DEBUG_MESSAGES + +#include + +#if defined(DEBUG) +#define __MBGL_DEBUG_GROUP_NAME2(counter) __MBGL_DEBUG_GROUP_##counter +#define __MBGL_DEBUG_GROUP_NAME(counter) __MBGL_DEBUG_GROUP_NAME2(counter) +#define MBGL_DEBUG_GROUP(string) ::mbgl::gl::debugging::group __MBGL_DEBUG_GROUP_NAME(__LINE__)(string); +#else +#define MBGL_DEBUG_GROUP(string) +#endif + +namespace mbgl { +namespace gl { +namespace debugging { + +void enable(); + +struct group { + group(const std::string&); + ~group(); +}; + +} +} +} + +#endif diff --git a/src/mbgl/map/annotation.cpp b/src/mbgl/map/annotation.cpp new file mode 100644 index 000000000..874459797 --- /dev/null +++ b/src/mbgl/map/annotation.cpp @@ -0,0 +1,579 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +namespace mbgl { + +Annotation::Annotation(AnnotationType type_, + const AnnotationSegments& geometry_, + const StyleProperties& styleProperties_) + : styleProperties(styleProperties_), + type(type_), + geometry(geometry_), + bounds([this] { + LatLngBounds bounds_; + assert(type != AnnotationType::Any); + if (type == AnnotationType::Point) { + bounds_ = { getPoint(), getPoint() }; + } else { + for (auto& segment : geometry) { + for (auto& point : segment) { + bounds_.extend(point); + } + } + } + return bounds_; + }()) { +} + +LatLng Annotation::getPoint() const { + // Return the first line's first point. Shortcut for point annotations. + assert(!geometry.empty()); + assert(!geometry[0].empty()); + return geometry[0][0]; +} + +AnnotationManager::AnnotationManager() {} + +AnnotationManager::~AnnotationManager() { + // leave this here because the header file doesn't have a definition of + // Annotation so we can't destruct the object with just the header file. +} + +void AnnotationManager::markStaleTiles(std::unordered_set ids) { + std::copy(ids.begin(), ids.end(), std::inserter(staleTiles, staleTiles.begin())); +} + +std::unordered_set AnnotationManager::resetStaleTiles() { + return std::move(staleTiles); +} + +void AnnotationManager::setDefaultPointAnnotationSymbol(const std::string& symbol) { + defaultPointAnnotationSymbol = symbol; +} + +uint32_t AnnotationManager::nextID() { + return nextID_++; +} + +vec2 AnnotationManager::projectPoint(const LatLng& point) { + // Clamp to the latitude limits of Mercator. + const double constrainedLatitude = ::fmin(::fmax(point.latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX); + + // Project a coordinate into unit space in a square map. + const double sine = std::sin(constrainedLatitude * M_PI / 180.0); + const double x = point.longitude / 360.0 + 0.5; + const double y = 0.5 - 0.25 * std::log((1.0 + sine) / (1.0 - sine)) / M_PI; + return { x, y }; +} + +std::unordered_set +AnnotationManager::addTileFeature(const uint32_t annotationID, + const AnnotationSegments& segments, + const std::vector>>& projectedFeature, + const AnnotationType& type, + const StyleProperties& styleProperties, + const std::unordered_map& featureProperties, + const uint8_t maxZoom) { + + assert(type != AnnotationType::Any); + + // track the annotation global ID and its original geometry + auto anno_it = annotations.emplace(annotationID, + std::make_unique(type, segments, styleProperties)); + + std::unordered_set affectedTiles; + + if (type == AnnotationType::Shape) { + + orderedShapeAnnotations.push_back(annotationID); + + using namespace mapbox::util::geojsonvt; + + const uint32_t z2 = 1 << maxZoom; + const double baseTolerance = 3; + const uint16_t extent = 4096; + + const double tolerance = baseTolerance / (z2 * extent); + + ProjectedGeometryContainer rings; + + std::vector points; + + for (size_t i = 0; i < segments[0].size(); ++i) { // first segment for now (no holes) + const double constraintedLatitude = ::fmin(::fmax(segments[0][i].latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX); + points.push_back(LonLat(segments[0][i].longitude, constraintedLatitude)); + } + + ProjectedFeatureType featureType; + + if (styleProperties.is()) { + featureType = ProjectedFeatureType::Polygon; + + if (points.front().lon != points.back().lon || points.front().lat != points.back().lat) { + points.push_back(LonLat(points.front().lon, points.front().lat)); + } + } else { + featureType = ProjectedFeatureType::LineString; + } + + ProjectedGeometryContainer ring = Convert::project(points, tolerance); + + rings.members.push_back(ring); + + std::vector features; + + features.push_back(Convert::create(Tags(), featureType, rings)); + + shapeTilers.emplace(annotationID, std::make_unique(features, maxZoom, 4, 100, 10)); + + } else { + + // side length of map at max zoom + uint32_t z2 = 1 << maxZoom; + + const uint16_t extent = 4096; + + uint32_t x = 0; + uint32_t y = 0; + + for (int8_t z = maxZoom; z >= 0; z--) { + + std::unordered_map featureTiles; + + if (type == AnnotationType::Point) { + auto& pp = projectedFeature[0][0]; + + x = pp.x * z2; + y = pp.y * z2; + + const Coordinate coordinate(extent * (pp.x * z2 - x), extent * (pp.y * z2 - y)); + + GeometryCollection geometries = {{ {{ coordinate }} }}; + + featureTiles.emplace(TileID(z, x, y, z), geometries); + } else { + for (size_t l = 0; l < projectedFeature.size(); ++l) { + for (size_t p = 0; p < projectedFeature[l].size(); ++p) { + + auto& pp = projectedFeature[l][p]; + + x = pp.x * z2; + y = pp.y * z2; + + const Coordinate coordinate(extent * (pp.x * z2 - x), extent * (pp.y * z2 - y)); + + auto tile_it = featureTiles.find(TileID(z, x, y, z)); + + if (tile_it != featureTiles.end()) { + GeometryCollection& geometries = featureTiles.find(TileID(z, x, y, z))->second; + if (!geometries.empty()) { + geometries.back().push_back(coordinate); + } else { + geometries.push_back({{ coordinate }}); + } + } else { + GeometryCollection geometries = {{ {{ coordinate }} }}; + featureTiles.emplace(TileID(z, x, y, z), geometries); + } + } + } + } + + for (auto& featureTile : featureTiles) { + // determine feature type + FeatureType featureType; + if (type == AnnotationType::Point) { + featureType = FeatureType::Point; + } else if (styleProperties.is()) { + featureType = FeatureType::LineString; + } else if (styleProperties.is()) { + featureType = FeatureType::Polygon; + } else { + throw std::runtime_error("Invalid feature type"); + } + + // create tile feature + auto feature = std::make_shared( + featureType, + featureTile.second, + featureProperties + ); + + // check for tile & create if necessary + auto tile_pos = tiles.emplace(featureTile.first, + std::make_pair(std::unordered_set({ annotationID }), + std::make_unique())); + + // check for annotation layer & create if necessary + util::ptr layer; + std::string layerID = ""; + if (type == AnnotationType::Point) { + layerID = PointLayerID; + } else { + layerID = ShapeLayerID + "." + util::toString(annotationID); + } + if (tile_pos.second || tile_pos.first->second.second->getMutableLayer(layerID) == nullptr) { + layer = std::make_shared(); + tile_pos.first->second.second->addLayer(layerID, layer); + } else { + layer = tile_pos.first->second.second->getMutableLayer(layerID); + + // associate annotation with tile + tile_pos.first->second.first.insert(annotationID); + } + + // add feature to layer + layer->addFeature(feature); + + // Record annotation association with tile and tile feature. This is used to determine stale tiles, + // as well as to remove the feature from the tile upon annotation deletion. + anno_it.first->second->tilePointFeatures.emplace(featureTile.first, std::weak_ptr(feature)); + + // track affected tile + affectedTiles.insert(featureTile.first); + } + + // get ready for the next-lower zoom number + z2 /= 2; + x /= 2; + y /= 2; + } + } + + return affectedTiles; +} + +std::pair, AnnotationIDs> +AnnotationManager::addPointAnnotations(const std::vector& points, + const uint8_t maxZoom) { + // We pre-generate tiles to contain each annotation up to the map's max zoom. + // We do this for fast rendering without projection conversions on the fly, as well as + // to simplify bounding box queries of annotations later. Tiles get invalidated when + // annotations are added or removed in order to refresh the map render without + // touching the base map underneath. + + AnnotationIDs annotationIDs; + annotationIDs.reserve(points.size()); + + std::unordered_set affectedTiles; + + for (const PointAnnotation& point : points) { + // projection conversion into unit space + const auto pp = projectPoint(point.position); + const uint32_t pointAnnotationID = nextID(); + + // at render time we style the point according to its {sprite} field + std::unordered_map pointFeatureProperties; + if (point.icon.length()) { + pointFeatureProperties.emplace("sprite", point.icon); + } else { + pointFeatureProperties.emplace("sprite", defaultPointAnnotationSymbol); + } + + // add individual point tile feature + auto featureAffectedTiles = addTileFeature( + pointAnnotationID, + AnnotationSegments({{ point.position }}), + std::vector>>({{ pp }}), + AnnotationType::Point, + {{ }}, + pointFeatureProperties, + maxZoom + ); + + std::copy(featureAffectedTiles.begin(), featureAffectedTiles.end(), std::inserter(affectedTiles, affectedTiles.begin())); + + annotationIDs.push_back(pointAnnotationID); + } + + // Tile:IDs that need refreshed and the annotation identifiers held onto by the client. + return std::make_pair(affectedTiles, annotationIDs); +} + +std::pair, AnnotationIDs> +AnnotationManager::addShapeAnnotations(const std::vector& shapes, + const uint8_t maxZoom) { + // We pre-generate tiles to contain each annotation up to the map's max zoom. + // We do this for fast rendering without projection conversions on the fly, as well as + // to simplify bounding box queries of annotations later. Tiles get invalidated when + // annotations are added or removed in order to refresh the map render without + // touching the base map underneath. + + AnnotationIDs annotationIDs; + annotationIDs.reserve(shapes.size()); + + std::unordered_set affectedTiles; + + for (const ShapeAnnotation& shape : shapes) { + const uint32_t shapeAnnotationID = nextID(); + + // current shape tiles are on-the-fly, so we don't get any "affected tiles" + // and just expire all annotation tiles for shape adds + + addTileFeature( + shapeAnnotationID, + shape.segments, + {{ }}, + AnnotationType::Shape, + shape.styleProperties, + {{ }}, + maxZoom + ); + + annotationIDs.push_back(shapeAnnotationID); + } + + // Tile:IDs that need refreshed and the annotation identifiers held onto by the client. + return std::make_pair(affectedTiles, annotationIDs); +} + +std::unordered_set AnnotationManager::removeAnnotations(const AnnotationIDs& ids, + const uint8_t maxZoom) { + std::unordered_set affectedTiles; + + std::vector z2s; + const uint8_t zoomCount = maxZoom + 1; + z2s.reserve(zoomCount); + for (uint8_t z = 0; z < zoomCount; ++z) { + z2s.emplace_back(1<< z); + } + + LatLng latLng; + vec2 p; + uint32_t x, y; + + // iterate annotation id's passed + for (const auto& annotationID : ids) { + // grab annotation object + const auto& annotation_it = annotations.find(annotationID); + if (annotation_it != annotations.end()) { + const auto& annotation = annotation_it->second; + // remove feature(s) from relevant tiles + if (annotation->type == AnnotationType::Point) { + // calculate annotation's affected tile for each zoom + for (uint8_t z = 0; z < zoomCount; ++z) { + latLng = annotation->getPoint(); + p = projectPoint(latLng); + x = z2s[z] * p.x; + y = z2s[z] * p.y; + TileID tid(z, x, y, z); + // erase annotation from tile's list + auto& tileAnnotations = tiles[tid].first; + tileAnnotations.erase(annotationID); + // remove annotation's features from tile + const auto& features_it = annotation->tilePointFeatures.find(tid); + if (features_it != annotation->tilePointFeatures.end()) { + // points share a layer; remove feature + auto layer = tiles[tid].second->getMutableLayer(PointLayerID); + layer->removeFeature(features_it->second); + affectedTiles.insert(tid); + } + } + } else { + // remove shape layer from tiles if relevant + for (auto tile_it = tiles.begin(); tile_it != tiles.end(); ++tile_it) { + if (tile_it->second.first.count(annotationID)) { + tile_it->second.second->removeLayer(ShapeLayerID + "." + util::toString(annotationID)); + affectedTiles.insert(tile_it->first); + } + } + + // clear shape from render order + auto shape_it = std::find(orderedShapeAnnotations.begin(), orderedShapeAnnotations.end(), annotationID); + orderedShapeAnnotations.erase(shape_it); + + // clear shape tiler + shapeTilers.erase(annotationID); + } + + annotations.erase(annotationID); + } + } + + // TileIDs for tiles that need refreshed. + return affectedTiles; +} + +const StyleProperties AnnotationManager::getAnnotationStyleProperties(uint32_t annotationID) const { + auto anno_it = annotations.find(annotationID); + assert(anno_it != annotations.end()); + + return anno_it->second->styleProperties; +} + +AnnotationIDs AnnotationManager::getAnnotationsInBounds(const LatLngBounds& queryBounds, + const uint8_t maxZoom, + const AnnotationType& type) const { + const uint8_t z = maxZoom; + const uint32_t z2 = 1 << z; + const vec2 swPoint = projectPoint(queryBounds.sw); + const vec2 nePoint = projectPoint(queryBounds.ne); + + // tiles number y from top down + const TileID nwTile(z, swPoint.x * z2, nePoint.y * z2, z); + const TileID seTile(z, nePoint.x * z2, swPoint.y * z2, z); + + std::unordered_set matchingAnnotations; + + for (auto& tile : tiles) { + TileID id = tile.first; + if (id.z == z) { + if (id.x >= nwTile.x && id.x <= seTile.x && id.y >= nwTile.y && id.y <= seTile.y) { + if (id.x > nwTile.x && id.x < seTile.x && id.y > nwTile.y && id.y < seTile.y) { + // Trivial accept; this tile is completely inside the query bounds, so + // we'll return all of its annotations that match type (if specified). + if (type != AnnotationType::Any) { + std::copy_if(tile.second.first.begin(), tile.second.first.end(), + std::inserter(matchingAnnotations, matchingAnnotations.begin()), + [&](const uint32_t annotationID) -> bool { + const auto it = annotations.find(annotationID); + if (it != annotations.end()) { + return (it->second->type == type); + } else { + return false; + } + }); + } else { + std::copy(tile.second.first.begin(), tile.second.first.end(), + std::inserter(matchingAnnotations, matchingAnnotations.begin())); + } + } else { + // This tile is intersected by the query bounds. We need to check the + // tile's annotations' bounding boxes individually. + std::copy_if(tile.second.first.begin(), tile.second.first.end(), + std::inserter(matchingAnnotations, matchingAnnotations.begin()), + [&](const uint32_t annotationID) -> bool { + const auto it = annotations.find(annotationID); + if (it != annotations.end()) { + // check type + if (type != AnnotationType::Any && it->second->type != type) { + return false; + } + + // check bounds + if (it->second->type == AnnotationType::Point) { + return queryBounds.contains(it->second->getPoint()); + } else if (it->second->type == AnnotationType::Shape) { + return queryBounds.intersects(it->second->getBounds()); + } + } + return false; + }); + } + } + } + } + + return AnnotationIDs(matchingAnnotations.begin(), matchingAnnotations.end()); +} + +LatLngBounds AnnotationManager::getBoundsForAnnotations(const AnnotationIDs& ids) const { + LatLngBounds bounds; + for (auto id : ids) { + const auto annotation_it = annotations.find(id); + if (annotation_it != annotations.end()) { + bounds.extend(annotation_it->second->getBounds()); + } + } + + return bounds; +} + +const LiveTile* AnnotationManager::getTile(const TileID& id) { + // look up any existing annotation tile + LiveTile *renderTile = nullptr; + const auto tile_lookup_it = tiles.find(id); + if (tile_lookup_it != tiles.end()) { + // it exists and may have annotations already + renderTile = tile_lookup_it->second.second.get(); + } else if (!orderedShapeAnnotations.empty()) { + // it needs created, but only for on-demand shapes + renderTile = tiles.emplace(id, + std::make_pair(std::unordered_set(), std::make_unique()) + ).first->second.second.get(); + } + + if (renderTile != nullptr && !orderedShapeAnnotations.empty()) { + + // create shape tile layers from GeoJSONVT queries + for (auto& tiler_it : shapeTilers) { + const auto annotationID = tiler_it.first; + const std::string layerID = ShapeLayerID + "." + util::toString(annotationID); + + // check for existing render layer + auto renderLayer = renderTile->getMutableLayer(layerID); + + if (renderLayer == nullptr) { + // we might need to create a tile layer for this shape + const auto& shapeTile = tiler_it.second->getTile(id.z, id.x, id.y); + + if (shapeTile) { + + // shape exists on this tile; let's make a layer + renderLayer = std::make_shared(); + + // convert the features and add to render layer + for (auto& shapeFeature : shapeTile.features) { + + using namespace mapbox::util::geojsonvt; + + FeatureType renderType = FeatureType::Unknown; + + if (shapeFeature.type == TileFeatureType::LineString) { + renderType = FeatureType::LineString; + } else if (shapeFeature.type == TileFeatureType::Polygon) { + renderType = FeatureType::Polygon; + } + + assert(renderType != FeatureType::Unknown); + + GeometryCollection renderGeometry; + + for (auto& shapeGeometry : shapeFeature.geometry) { + + std::vector renderLine; + + auto& shapeRing = shapeGeometry.get(); + + for (auto& shapePoint : shapeRing.points) { + renderLine.emplace_back(shapePoint.x, shapePoint.y); + } + + renderGeometry.push_back(renderLine); + } + + auto renderFeature = std::make_shared(renderType, renderGeometry); + + renderLayer->addFeature(renderFeature); + } + + // move the layer to the render tile + renderTile->addLayer(layerID, renderLayer); + + // associate the annotation with the tile + auto tile_update_it = tiles.find(id); + assert(tile_update_it != tiles.end()); + tile_update_it->second.first.insert(annotationID); + } + } + } + } + + return renderTile; +} + +const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points"; +const std::string AnnotationManager::ShapeLayerID = "com.mapbox.annotations.shape"; + +} diff --git a/src/mbgl/map/annotation.hpp b/src/mbgl/map/annotation.hpp new file mode 100644 index 000000000..745fc779c --- /dev/null +++ b/src/mbgl/map/annotation.hpp @@ -0,0 +1,103 @@ +#ifndef MBGL_MAP_ANNOTATIONS +#define MBGL_MAP_ANNOTATIONS + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace mbgl { + +class Annotation; +class PointAnnotation; +class ShapeAnnotation; +class LiveTile; +class LiveTileFeature; + +using GeoJSONVT = mapbox::util::geojsonvt::GeoJSONVT; + +class Annotation : private util::noncopyable { + friend class AnnotationManager; +public: + Annotation(AnnotationType, const AnnotationSegments&, const StyleProperties&); + +public: + const StyleProperties styleProperties; + +private: + LatLng getPoint() const; + LatLngBounds getBounds() const { return bounds; } + +private: + const AnnotationType type = AnnotationType::Point; + const AnnotationSegments geometry; + std::unordered_map, TileID::Hash> tilePointFeatures; + const LatLngBounds bounds; +}; + +class AnnotationManager : private util::noncopyable { +public: + AnnotationManager(); + ~AnnotationManager(); + + void markStaleTiles(std::unordered_set); + std::unordered_set resetStaleTiles(); + + void setDefaultPointAnnotationSymbol(const std::string& symbol); + + std::pair, AnnotationIDs> + addPointAnnotations(const std::vector&, + const uint8_t maxZoom); + + std::pair, AnnotationIDs> + addShapeAnnotations(const std::vector&, + const uint8_t maxZoom); + + std::unordered_set removeAnnotations(const AnnotationIDs&, const uint8_t maxZoom); + AnnotationIDs getOrderedShapeAnnotations() const { return orderedShapeAnnotations; } + const StyleProperties getAnnotationStyleProperties(uint32_t) const; + + AnnotationIDs getAnnotationsInBounds(const LatLngBounds&, const uint8_t maxZoom, const AnnotationType& = AnnotationType::Any) const; + LatLngBounds getBoundsForAnnotations(const AnnotationIDs&) const; + + const LiveTile* getTile(const TileID& id); + + static const std::string PointLayerID; + static const std::string ShapeLayerID; + +private: + inline uint32_t nextID(); + static vec2 projectPoint(const LatLng& point); + std::unordered_set addTileFeature( + const uint32_t annotationID, + const AnnotationSegments&, + const std::vector>>& projectedFeature, + const AnnotationType&, + const StyleProperties&, + const std::unordered_map& featureProperties, + const uint8_t maxZoom); + +private: + std::string defaultPointAnnotationSymbol; + std::unordered_map> annotations; + std::vector orderedShapeAnnotations; + std::unordered_map, std::unique_ptr>, TileID::Hash> tiles; + std::unordered_map> shapeTilers; + std::unordered_set staleTiles; + uint32_t nextID_ = 0; +}; + +} + +#endif diff --git a/src/mbgl/map/geometry_tile.cpp b/src/mbgl/map/geometry_tile.cpp new file mode 100644 index 000000000..785845b4d --- /dev/null +++ b/src/mbgl/map/geometry_tile.cpp @@ -0,0 +1,17 @@ +#include +#include +#include + +namespace mbgl { + +mapbox::util::optional GeometryTileFeatureExtractor::getValue(const std::string& key) const { + if (key == "$type") { + return Value(uint64_t(feature.getType())); + } + + return feature.getValue(key); +} + +template bool evaluate(const FilterExpression&, const GeometryTileFeatureExtractor&); + +} diff --git a/src/mbgl/map/geometry_tile.hpp b/src/mbgl/map/geometry_tile.hpp new file mode 100644 index 000000000..dc1ef1072 --- /dev/null +++ b/src/mbgl/map/geometry_tile.hpp @@ -0,0 +1,57 @@ +#ifndef MBGL_MAP_GEOMETRY_TILE +#define MBGL_MAP_GEOMETRY_TILE + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace mbgl { + +enum class FeatureType : uint8_t { + Unknown = 0, + Point = 1, + LineString = 2, + Polygon = 3 +}; + +typedef std::vector> GeometryCollection; + +class GeometryTileFeature : private util::noncopyable { +public: + virtual FeatureType getType() const = 0; + virtual mapbox::util::optional getValue(const std::string& key) const = 0; + virtual GeometryCollection getGeometries() const = 0; +}; + +class GeometryTileLayer : private util::noncopyable { +public: + virtual std::size_t featureCount() const = 0; + virtual util::ptr getFeature(std::size_t) const = 0; +}; + +class GeometryTile : private util::noncopyable { +public: + virtual util::ptr getLayer(const std::string&) const = 0; +}; + +class GeometryTileFeatureExtractor { +public: + GeometryTileFeatureExtractor(const GeometryTileFeature& feature_) + : feature(feature_) {} + + mapbox::util::optional getValue(const std::string& key) const; + +private: + const GeometryTileFeature& feature; +}; + +} + +#endif diff --git a/src/mbgl/map/live_tile.cpp b/src/mbgl/map/live_tile.cpp new file mode 100644 index 000000000..f7a70f7d4 --- /dev/null +++ b/src/mbgl/map/live_tile.cpp @@ -0,0 +1,61 @@ +#include +#include + +namespace mbgl { + +LiveTileFeature::LiveTileFeature(FeatureType type_, GeometryCollection geometries_, + std::unordered_map properties_) + : type(type_), + properties(properties_), + geometries(geometries_) {} + +mapbox::util::optional LiveTileFeature::getValue(const std::string& key) const { + auto it = properties.find(key); + if (it != properties.end()) { + return mapbox::util::optional(it->second); + } + return mapbox::util::optional(); +} + +LiveTileLayer::LiveTileLayer() {} + +void LiveTileLayer::prepareToAddFeatures(size_t count) { + features.reserve(features.size() + count); +} + +void LiveTileLayer::addFeature(util::ptr feature) { + features.push_back(std::move(feature)); +} + +void LiveTileLayer::removeFeature(util::ptr feature) { + for (auto it = features.begin(); it != features.end(); ++it) { + if (feature == *it) { + features.erase(it); + return; + } + } +} + +LiveTile::LiveTile() {} + +void LiveTile::addLayer(const std::string& name, util::ptr layer) { + layers.emplace(name, std::move(layer)); +} + +void LiveTile::removeLayer(const std::string& name) { + layers.erase(name); +} + +util::ptr LiveTile::getLayer(const std::string& name) const { + return getMutableLayer(name); +} + +util::ptr LiveTile::getMutableLayer(const std::string& name) const { + auto layer_it = layers.find(name); + if (layer_it != layers.end()) { + return layer_it->second; + } + return nullptr; +} + +} diff --git a/src/mbgl/map/live_tile.hpp b/src/mbgl/map/live_tile.hpp new file mode 100644 index 000000000..5b4c2d1c1 --- /dev/null +++ b/src/mbgl/map/live_tile.hpp @@ -0,0 +1,55 @@ +#ifndef MBGL_MAP_LIVE_TILE +#define MBGL_MAP_LIVE_TILE + +#include +#include + +#include + +namespace mbgl { + +class LiveTileFeature : public GeometryTileFeature { +public: + LiveTileFeature(FeatureType, GeometryCollection, + std::unordered_map properties = {{}}); + + FeatureType getType() const override { return type; } + mapbox::util::optional getValue(const std::string&) const override; + GeometryCollection getGeometries() const override { return geometries; } + +private: + FeatureType type = FeatureType::Unknown; + std::unordered_map properties; + GeometryCollection geometries; +}; + +class LiveTileLayer : public GeometryTileLayer { +public: + LiveTileLayer(); + + void prepareToAddFeatures(size_t count); + void addFeature(util::ptr); + void removeFeature(util::ptr); + std::size_t featureCount() const override { return features.size(); } + util::ptr getFeature(std::size_t i) const override { return features[i]; } + +private: + std::vector> features; +}; + +class LiveTile : public GeometryTile { +public: + LiveTile(); + + void addLayer(const std::string&, util::ptr); + void removeLayer(const std::string&); + util::ptr getLayer(const std::string&) const override; + util::ptr getMutableLayer(const std::string&) const; + +private: + std::map> layers; +}; + +} + +#endif diff --git a/src/mbgl/map/live_tile_data.cpp b/src/mbgl/map/live_tile_data.cpp new file mode 100644 index 000000000..8be918d6d --- /dev/null +++ b/src/mbgl/map/live_tile_data.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace mbgl; + +LiveTileData::LiveTileData(const TileID& id_, + const LiveTile* tile, + Style& style_, + const SourceInfo& source_, + std::function callback) + : TileData(id_), + worker(style_.workers), + tileWorker(id_, + source_.source_id, + source_.max_zoom, + style_, + style_.layers, + state, + std::make_unique(id_.z, 4096, + source_.tile_size * id.overscaling, + 0, false)) { + state = State::loaded; + + if (!tile) { + state = State::parsed; + return; + } + + workRequest = worker.parseLiveTile(tileWorker, *tile, [this, callback] (TileParseResult result) { + if (result.is()) { + state = result.get(); + } else { + error = result.get(); + state = State::obsolete; + } + + callback(); + }); +} + +LiveTileData::~LiveTileData() { + cancel(); +} + +Bucket* LiveTileData::getBucket(const StyleLayer& layer) { + if (!isReady() || !layer.bucket) { + return nullptr; + } + + return tileWorker.getBucket(layer); +} + +void LiveTileData::cancel() { + state = State::obsolete; + workRequest.reset(); +} diff --git a/src/mbgl/map/live_tile_data.hpp b/src/mbgl/map/live_tile_data.hpp new file mode 100644 index 000000000..5c4220fd6 --- /dev/null +++ b/src/mbgl/map/live_tile_data.hpp @@ -0,0 +1,34 @@ +#ifndef MBGL_MAP_LIVE_TILE_DATA +#define MBGL_MAP_LIVE_TILE_DATA + +#include +#include + +namespace mbgl { + +class Style; +class SourceInfo; +class WorkRequest; +class LiveTile; + +class LiveTileData : public TileData { +public: + LiveTileData(const TileID&, + const LiveTile*, + Style&, + const SourceInfo&, + std::function callback); + ~LiveTileData(); + + void cancel() override; + Bucket* getBucket(const StyleLayer&) override; + +private: + Worker& worker; + TileWorker tileWorker; + std::unique_ptr workRequest; +}; + +} + +#endif diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp new file mode 100644 index 000000000..9bfb04841 --- /dev/null +++ b/src/mbgl/map/map.cpp @@ -0,0 +1,450 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace mbgl { + +Map::Map(View& view_, FileSource& fileSource, MapMode mode) + : view(view_), + transform(std::make_unique(view)), + data(std::make_unique(mode, view.getPixelRatio())), + context(std::make_unique>(util::ThreadContext{"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, view, fileSource, *data)) +{ + view.initialize(this); + update(Update::Dimensions); +} + +Map::~Map() { + resume(); + context->invoke(&MapContext::cleanup); +} + +void Map::pause() { + assert(data->mode == MapMode::Continuous); + + if (!paused) { + std::unique_lock lockPause(data->mutexPause); + context->invoke(&MapContext::pause); + data->condPaused.wait(lockPause); + paused = true; + } +} + +void Map::resume() { + data->condResume.notify_all(); + paused = false; +} + +void Map::renderStill(StillImageCallback callback) { + context->invoke(&MapContext::renderStill, transform->getState(), + FrameData{ view.getFramebufferSize() }, callback); +} + +void Map::renderSync() { + if (renderState == RenderState::never) { + view.notifyMapChange(MapChangeWillStartRenderingMap); + } + + view.notifyMapChange(MapChangeWillStartRenderingFrame); + + const bool fullyLoaded = context->invokeSync( + &MapContext::renderSync, transform->getState(), FrameData { view.getFramebufferSize() }); + + view.notifyMapChange(fullyLoaded ? + MapChangeDidFinishRenderingFrameFullyRendered : + MapChangeDidFinishRenderingFrame); + + if (!fullyLoaded) { + renderState = RenderState::partial; + } else if (renderState != RenderState::fully) { + renderState = RenderState::fully; + view.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered); + } +} + +void Map::nudgeTransitions() { + Update flags = transform->updateTransitions(Clock::now()); + if (data->getNeedsRepaint()) { + flags |= Update::Repaint; + } + update(flags); +} + +void Map::update(Update flags) { + if (flags & Update::Dimensions) { + transform->resize(view.getSize()); + } + context->invoke(&MapContext::triggerUpdate, transform->getState(), flags); +} + +#pragma mark - Style + +void Map::setStyleURL(const std::string &url) { + context->invoke(&MapContext::setStyleURL, url); +} + +void Map::setStyleJSON(const std::string& json, const std::string& base) { + context->invoke(&MapContext::setStyleJSON, json, base); +} + +std::string Map::getStyleURL() const { + return context->invokeSync(&MapContext::getStyleURL); +} + +std::string Map::getStyleJSON() const { + return context->invokeSync(&MapContext::getStyleJSON); +} + +#pragma mark - Transitions + +void Map::cancelTransitions() { + transform->cancelTransitions(); + update(Update::Repaint); +} + +void Map::setGestureInProgress(bool inProgress) { + transform->setGestureInProgress(inProgress); + update(Update::Repaint); +} + +#pragma mark - Position + +void Map::moveBy(double dx, double dy, const Duration& duration) { + transform->moveBy(dx, dy, duration); + update(Update::Repaint); +} + +void Map::setLatLng(LatLng latLng, const Duration& duration) { + transform->setLatLng(latLng, duration); + update(Update::Repaint); +} + +LatLng Map::getLatLng() const { + return transform->getLatLng(); +} + +void Map::resetPosition() { + transform->setAngle(0); + transform->setLatLng(LatLng(0, 0)); + transform->setZoom(0); + update(Update::Zoom); +} + + +#pragma mark - Scale + +void Map::scaleBy(double ds, double cx, double cy, const Duration& duration) { + transform->scaleBy(ds, cx, cy, duration); + update(Update::Zoom); +} + +void Map::setScale(double scale, double cx, double cy, const Duration& duration) { + transform->setScale(scale, cx, cy, duration); + update(Update::Zoom); +} + +double Map::getScale() const { + return transform->getScale(); +} + +void Map::setZoom(double zoom, const Duration& duration) { + transform->setZoom(zoom, duration); + update(Update::Zoom); +} + +double Map::getZoom() const { + return transform->getZoom(); +} + +void Map::setLatLngZoom(LatLng latLng, double zoom, const Duration& duration) { + transform->setLatLngZoom(latLng, zoom, duration); + update(Update::Zoom); +} + +void Map::fitBounds(LatLngBounds bounds, EdgeInsets padding, const Duration& duration) { + AnnotationSegment segment = { + {bounds.ne.latitude, bounds.sw.longitude}, + bounds.sw, + {bounds.sw.latitude, bounds.ne.longitude}, + bounds.ne, + }; + fitBounds(segment, padding, duration); +} + +void Map::fitBounds(AnnotationSegment segment, EdgeInsets padding, const Duration& duration) { + if (segment.empty()) { + return; + } + + // Calculate the bounds of the possibly rotated shape with respect to the viewport. + vec2<> nePixel = {-INFINITY, -INFINITY}; + vec2<> swPixel = {INFINITY, INFINITY}; + for (LatLng latLng : segment) { + vec2<> pixel = pixelForLatLng(latLng); + swPixel.x = std::min(swPixel.x, pixel.x); + nePixel.x = std::max(nePixel.x, pixel.x); + swPixel.y = std::min(swPixel.y, pixel.y); + nePixel.y = std::max(nePixel.y, pixel.y); + } + vec2<> size = nePixel - swPixel; + + // Calculate the zoom level. + double scaleX = (getWidth() - padding.left - padding.right) / size.x; + double scaleY = (getHeight() - padding.top - padding.bottom) / size.y; + double minScale = ::fmin(scaleX, scaleY); + double zoom = ::log2(getScale() * minScale); + zoom = ::fmax(::fmin(zoom, getMaxZoom()), getMinZoom()); + + // Calculate the center point of a virtual bounds that is extended in all directions by padding. + vec2<> paddedNEPixel = { + nePixel.x + padding.right / minScale, + nePixel.y + padding.top / minScale, + }; + vec2<> paddedSWPixel = { + swPixel.x - padding.left / minScale, + swPixel.y - padding.bottom / minScale, + }; + vec2<> centerPixel = (paddedNEPixel + paddedSWPixel) * 0.5; + LatLng centerLatLng = latLngForPixel(centerPixel); + + setLatLngZoom(centerLatLng, zoom, duration); +} + +void Map::resetZoom() { + setZoom(0); +} + +double Map::getMinZoom() const { + return transform->getState().getMinZoom(); +} + +double Map::getMaxZoom() const { + return transform->getState().getMaxZoom(); +} + + +#pragma mark - Size + +uint16_t Map::getWidth() const { + return transform->getState().getWidth(); +} + +uint16_t Map::getHeight() const { + return transform->getState().getHeight(); +} + + +#pragma mark - Rotation + +void Map::rotateBy(double sx, double sy, double ex, double ey, const Duration& duration) { + transform->rotateBy(sx, sy, ex, ey, duration); + update(Update::Repaint); +} + +void Map::setBearing(double degrees, const Duration& duration) { + transform->setAngle(-degrees * M_PI / 180, duration); + update(Update::Repaint); +} + +void Map::setBearing(double degrees, double cx, double cy) { + transform->setAngle(-degrees * M_PI / 180, cx, cy); + update(Update::Repaint); +} + +double Map::getBearing() const { + return -transform->getAngle() / M_PI * 180; +} + +void Map::resetNorth() { + transform->setAngle(0, std::chrono::milliseconds(500)); + update(Update::Repaint); +} + + +#pragma mark - Projection + +void Map::getWorldBoundsMeters(ProjectedMeters& sw, ProjectedMeters& ne) const { + Projection::getWorldBoundsMeters(sw, ne); +} + +void Map::getWorldBoundsLatLng(LatLng& sw, LatLng& ne) const { + Projection::getWorldBoundsLatLng(sw, ne); +} + +double Map::getMetersPerPixelAtLatitude(const double lat, const double zoom) const { + return Projection::getMetersPerPixelAtLatitude(lat, zoom); +} + +const ProjectedMeters Map::projectedMetersForLatLng(const LatLng latLng) const { + return Projection::projectedMetersForLatLng(latLng); +} + +const LatLng Map::latLngForProjectedMeters(const ProjectedMeters projectedMeters) const { + return Projection::latLngForProjectedMeters(projectedMeters); +} + +const vec2 Map::pixelForLatLng(const LatLng latLng) const { + return transform->getState().pixelForLatLng(latLng); +} + +const LatLng Map::latLngForPixel(const vec2 pixel) const { + return transform->getState().latLngForPixel(pixel); +} + +#pragma mark - Annotations + +void Map::setDefaultPointAnnotationSymbol(const std::string& symbol) { + data->getAnnotationManager()->setDefaultPointAnnotationSymbol(symbol); +} + +double Map::getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol) { + return context->invokeSync(&MapContext::getTopOffsetPixelsForAnnotationSymbol, symbol); +} + +uint32_t Map::addPointAnnotation(const PointAnnotation& annotation) { + return addPointAnnotations({ annotation }).front(); +} + +AnnotationIDs Map::addPointAnnotations(const std::vector& annotations) { + auto result = data->getAnnotationManager()->addPointAnnotations(annotations, getMaxZoom()); + context->invoke(&MapContext::updateAnnotationTiles, result.first); + return result.second; +} + +uint32_t Map::addShapeAnnotation(const ShapeAnnotation& annotation) { + return addShapeAnnotations({ annotation }).front(); +} + +AnnotationIDs Map::addShapeAnnotations(const std::vector& annotations) { + auto result = data->getAnnotationManager()->addShapeAnnotations(annotations, getMaxZoom()); + context->invoke(&MapContext::updateAnnotationTiles, result.first); + return result.second; +} + +void Map::removeAnnotation(uint32_t annotation) { + removeAnnotations({ annotation }); +} + +void Map::removeAnnotations(const std::vector& annotations) { + auto result = data->getAnnotationManager()->removeAnnotations(annotations, getMaxZoom()); + context->invoke(&MapContext::updateAnnotationTiles, result); +} + +std::vector Map::getAnnotationsInBounds(const LatLngBounds& bounds, const AnnotationType& type) { + return data->getAnnotationManager()->getAnnotationsInBounds(bounds, getMaxZoom(), type); +} + +LatLngBounds Map::getBoundsForAnnotations(const std::vector& annotations) { + return data->getAnnotationManager()->getBoundsForAnnotations(annotations); +} + + +#pragma mark - Sprites + +void Map::setSprite(const std::string& name, std::shared_ptr sprite) { + context->invoke(&MapContext::setSprite, name, sprite); +} + +void Map::removeSprite(const std::string& name) { + setSprite(name, nullptr); +} + + +#pragma mark - Toggles + +void Map::setDebug(bool value) { + data->setDebug(value); + update(Update::Repaint); +} + +void Map::toggleDebug() { + data->toggleDebug(); + update(Update::Repaint); +} + +bool Map::getDebug() const { + return data->getDebug(); +} + +void Map::setNeedsRepaint() { + data->setNeedsRepaint(true); +} + +void Map::setCollisionDebug(bool value) { + data->setCollisionDebug(value); + update(Update::Repaint); +} + +void Map::toggleCollisionDebug() { + data->toggleCollisionDebug(); + update(Update::Repaint); +} + +bool Map::getCollisionDebug() const { + return data->getCollisionDebug(); +} + +bool Map::isFullyLoaded() const { + return context->invokeSync(&MapContext::isLoaded); +} + +void Map::addClass(const std::string& klass) { + if (data->addClass(klass)) { + update(Update::Classes); + } +} + +void Map::removeClass(const std::string& klass) { + if (data->removeClass(klass)) { + update(Update::Classes); + } +} + +void Map::setClasses(const std::vector& classes) { + data->setClasses(classes); + update(Update::Classes); +} + +bool Map::hasClass(const std::string& klass) const { + return data->hasClass(klass); +} + +std::vector Map::getClasses() const { + return data->getClasses(); +} + +void Map::setDefaultTransitionDuration(const Duration& duration) { + data->setDefaultTransitionDuration(duration); + update(Update::DefaultTransition); +} + +Duration Map::getDefaultTransitionDuration() const { + return data->getDefaultTransitionDuration(); +} + +void Map::setDefaultTransitionDelay(const Duration& delay) { + data->setDefaultTransitionDelay(delay); + update(Update::DefaultTransition); +} + +Duration Map::getDefaultTransitionDelay() const { + return data->getDefaultTransitionDelay(); +} + +void Map::setSourceTileCacheSize(size_t size) { + context->invoke(&MapContext::setSourceTileCacheSize, size); +} + +void Map::onLowMemory() { + context->invoke(&MapContext::onLowMemory); +} + +} diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp new file mode 100644 index 000000000..19e8d02ec --- /dev/null +++ b/src/mbgl/map/map_context.cpp @@ -0,0 +1,428 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace mbgl { + +MapContext::MapContext(View& view_, FileSource& fileSource, MapData& data_) + : view(view_), + data(data_), + asyncUpdate(std::make_unique(util::RunLoop::getLoop(), [this] { update(); })), + texturePool(std::make_unique()), + viewInvalidated(false) { + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + util::ThreadContext::setFileSource(&fileSource); + util::ThreadContext::setGLObjectStore(&glObjectStore); + + asyncUpdate->unref(); + + view.activate(); +} + +MapContext::~MapContext() { + // Make sure we call cleanup() before deleting this object. + assert(!style); +} + +void MapContext::cleanup() { + view.notify(); + + if (styleRequest) { + FileSource* fs = util::ThreadContext::getFileSource(); + fs->cancel(styleRequest); + styleRequest = nullptr; + } + + // Explicit resets currently necessary because these abandon resources that need to be + // cleaned up by glObjectStore.performCleanup(); + style.reset(); + painter.reset(); + texturePool.reset(); + + glObjectStore.performCleanup(); + + view.deactivate(); +} + +void MapContext::pause() { + MBGL_CHECK_ERROR(glFinish()); + + viewInvalidated = false; + + view.deactivate(); + + std::unique_lock lockPause(data.mutexPause); + data.condPaused.notify_all(); + data.condResume.wait(lockPause); + + view.activate(); + + invalidateView(); +} + +void MapContext::triggerUpdate(const TransformState& state, const Update flags) { + transformState = state; + updateFlags |= flags; + + asyncUpdate->send(); +} + +void MapContext::setStyleURL(const std::string& url) { + FileSource* fs = util::ThreadContext::getFileSource(); + + if (styleRequest) { + fs->cancel(styleRequest); + } + + styleURL = url; + styleJSON.clear(); + + style = std::make_unique