[Pkg-javascript-commits] [node-mapnik] 01/08: New upstream version 3.7.0+dfsg

Bas Couwenberg sebastic at debian.org
Sun Mar 4 12:56:23 UTC 2018


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository node-mapnik.

commit f648fb94e4ca224ea80249653ffcf48f9fd6a5d3
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sun Mar 4 13:17:58 2018 +0100

    New upstream version 3.7.0+dfsg
---
 .gitignore                                         |   4 +-
 .npmignore                                         |   2 +-
 .travis.yml                                        |  52 ++-
 CHANGELOG.md                                       |   9 +
 Makefile                                           |  39 ++-
 README.md                                          |  60 ++--
 appveyor.yml                                       |  45 ---
 binding.gyp                                        |  39 +--
 gen_settings.py                                    |  39 ---
 package.json                                       |  14 +-
 scripts/build-appveyor.bat                         | 136 --------
 scripts/build-local.bat                            |  65 ----
 ...uild_against_sdk_02-copy-deps-to-bindingdir.ps1 |  40 ---
 .../build_against_sdk_03-write-mapnik.settings.ps1 |  24 --
 scripts/check_glibcxx.sh                           |  33 ++
 install_mason.sh => scripts/install_deps.sh        |  20 +-
 scripts/postinstall.sh                             |  24 ++
 scripts/setup.sh                                   |   6 +-
 src/glibc_workaround.cpp                           |  26 ++
 src/mapnik_color.cpp                               |  29 +-
 src/mapnik_datasource.cpp                          |   4 +-
 src/mapnik_feature.cpp                             |   8 +-
 src/mapnik_featureset.cpp                          |  10 +-
 src/mapnik_geometry.cpp                            |   4 +-
 src/mapnik_grid_view.cpp                           |   6 +-
 src/mapnik_image.cpp                               | 361 ++++++++++++---------
 src/mapnik_image_view.cpp                          |  13 +-
 src/mapnik_layer.cpp                               |  26 +-
 src/mapnik_map.cpp                                 |  36 +-
 src/mapnik_memory_datasource.cpp                   |   5 +-
 src/mapnik_projection.cpp                          |   4 +-
 src/mapnik_vector_tile.cpp                         |  18 +-
 test/data/images/san-marino.svg                    |  92 ++++++
 .../vector_tile/compositing/expected/2-1-1b.png    | Bin 154739 -> 154748 bytes
 .../expected/world-reencode-max-extent.png         | Bin 7993 -> 7992 bytes
 .../compositing/expected/world-reencode.png        | Bin 7981 -> 7980 bytes
 test/data/vector_tile/nz-1.png                     | Bin 26701 -> 26699 bytes
 test/data/vector_tile/nz-1b.png                    | Bin 25817 -> 25832 bytes
 test/data/vector_tile/tile-raster.expected.jpg     | Bin 5247 -> 5230 bytes
 test/data/vector_tile/tile0-c.expected.png         | Bin 13780 -> 13783 bytes
 .../data/vector_tile/tile0-simple_and_distance.mvt | Bin 55751 -> 55744 bytes
 test/data/vector_tile/tile0-simplify_distance.mvt  | Bin 55751 -> 55744 bytes
 test/datasource.test.js                            |  13 +-
 test/image.svg.test.js                             |  14 +-
 test/vector-tile.test.js                           |  10 +-
 45 files changed, 654 insertions(+), 676 deletions(-)

diff --git a/.gitignore b/.gitignore
index 2eeb206..7ce2ec1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,5 +19,7 @@ foo
 iwyu.sh
 package
 documentation
-mason/
+.mason/
+.toolchain/
+local.env
 mason_packages/
diff --git a/.npmignore b/.npmignore
index c8ee462..aa6642d 100644
--- a/.npmignore
+++ b/.npmignore
@@ -11,7 +11,6 @@ test
 benchmark
 configure
 Makefile
-scripts
 .travis.yml
 appveyor.yml
 examples
@@ -31,3 +30,4 @@ mason_packages
 deps/wagyu/tests
 deps/wagyu/docs
 deps/geometry/tests
+.toolchain
diff --git a/.travis.yml b/.travis.yml
index c2eb0d4..6e8b138 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,6 +33,7 @@ install:
 # we use before_script rather than script to ensure fast failure (the script section continues even after an error)
 # https://docs.travis-ci.com/user/customizing-the-build#Breaking-the-Build
 before_script:
+  - ./scripts/check_glibcxx.sh
   - npm test
   # after successful tests, publish binaries if specified in commit message
   - ./scripts/publish.sh --toolset=${TOOLSET:-} --debug=$([ "${BUILDTYPE}" == 'debug' ] && echo "true" || echo "false")
@@ -41,7 +42,7 @@ before_script:
 script:
   - true
 
-# the matrix allows you to specify different operating systems and environments to 
+# the matrix allows you to specify different operating systems and environments to
 # run your tests and build binaries
 matrix:
   include:
@@ -73,6 +74,10 @@ matrix:
     - os: linux
       env: BUILDTYPE=release
       node_js: 8
+    # linux publishable node v9
+    - os: linux
+      env: BUILDTYPE=release
+      node_js: 9
     # osx publishable node v0.10
     - os: osx
       osx_image: xcode8.3
@@ -83,22 +88,37 @@ matrix:
       osx_image: xcode8.3
       env: BUILDTYPE=release
       node_js: 4
+    # osx publishable node v4/debug
+    - os: osx
+      osx_image: xcode8.3
+      env: BUILDTYPE=debug
+      node_js: 4
     # osx publishable node v6
     - os: osx
       osx_image: xcode8.3
       env: BUILDTYPE=release
       node_js: 6
+    # osx publishable node v6/debug
+    - os: osx
+      osx_image: xcode8.3
+      env: BUILDTYPE=debug
+      node_js: 6
     # osx publishable node v7
     - os: osx
-      osx_image: xcode8.2
+      osx_image: xcode8.3
       env: BUILDTYPE=release
       node_js: 7
     # osx publishable node v8
     - os: osx
-      osx_image: xcode8.2
+      osx_image: xcode8.3
       env: BUILDTYPE=release
       node_js: 8
-    # Sanitizer build node v4/Debug
+    # osx publishable node v9
+    - os: osx
+      osx_image: xcode8.3
+      env: BUILDTYPE=release
+      node_js: 9
+    # Sanitizer build linux node v4/Debug
     - os: linux
       env: BUILDTYPE=debug TOOLSET=-asan
       node_js: 4
@@ -121,6 +141,30 @@ matrix:
         - unset LD_PRELOAD
         # after successful tests, publish binaries if specified in commit message
         - ./scripts/publish.sh --toolset=${TOOLSET:-} --debug=$([ "${BUILDTYPE}" == 'debug' ] && echo "true" || echo "false")
+    # Sanitizer build osx node v4/Debug
+    - os: osx
+      osx_image: xcode8.3
+      env: BUILDTYPE=debug TOOLSET=-asan
+      node_js: 4
+      # Overrides `install` to set up custom asan flags
+      install:
+        - ./scripts/setup.sh --config local.env
+        # put mason and clang++ on PATH
+        - source local.env
+        # Note: to build without stopping on errors remove the -fno-sanitize-recover=all flag
+        # You might want to do this if there are multiple errors and you want to see them all before fixing
+        - export CXXFLAGS="${MASON_SANITIZE_CXXFLAGS} -fno-sanitize-recover=all"
+        - export LDFLAGS="${MASON_SANITIZE_LDFLAGS}"
+        - make ${BUILDTYPE}
+      # Overrides `script` to disable asan LD_PRELOAD before publishing
+      before_script:
+        - export DYLD_INSERT_LIBRARIES=${MASON_LLVM_RT_PRELOAD}
+        # TODO: re-enable detect_leaks=0 once we can build and test against an asan sanitized libc++
+        - export ASAN_OPTIONS=fast_unwind_on_malloc=0:detect_leaks=0:${ASAN_OPTIONS}
+        - node ./node_modules/.bin/_mocha test/  --timeout 100000
+        - unset DYLD_INSERT_LIBRARIES
+        # after successful tests, publish binaries if specified in commit message
+        - ./scripts/publish.sh --toolset=${TOOLSET:-} --debug=$([ "${BUILDTYPE}" == 'debug' ] && echo "true" || echo "false")
     # g++ build (default builds all use clang++)
     - os: linux
       env: BUILDTYPE=debug CXX="g++-6" CC="gcc-6"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b363a5b..38cb854 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Changelog
 
+## 3.7.0
+
+Updated to 3.0.18 of mapnik. See [here](https://github.com/mapnik/mapnik/blob/master/CHANGELOG.md).
+
+- Updated to mapnik-vector-tile at 1.6.1
+- Removed windows support (https://github.com/mapnik/node-mapnik/issues/848)
+
 ## 3.6.2
 
 Updated to 3.0.15 of mapnik. The full changelog for this release is located [here](https://github.com/mapnik/mapnik/blob/master/CHANGELOG.md#3015). 
@@ -20,6 +27,7 @@ Due to changes in the mapnik core version during this update you should see some
 - Fixed tests around zlib compression and decompression when comparing to node's implementation
 - Fixes rare situation of seg faults during mapnik-vector-tile image processing.
 - Corrects the resolution of images in mapnik-vector-tile when using parameters from postgis plugin.
+- Updated to use `font_engine` `instance()` method explicitely, reflecting on changes brought by [3688](https://github.com/mapnik/mapnik/pull/3688)
 
 ## 3.6.0
 
@@ -31,6 +39,7 @@ The second largest change is the update of all major C/C++ dependencies. The cha
 
 The third most important set of changes were to node-mapnik directly: for performance many functions now can premultiply as part of another async operation (to avoid needing an additional threadpool access for async premultiply - this matters under load when the threadpool may be full since access can block). And many functions that allocate images now protect from extreme allocation that could hang a machine and result in OOM. Additionally the address sanitizer caught several cases of u [...]
 
+- No longer installing node-pre-gyp in `preinstall` target, now bundling again as a bundledDep (https://github.com/mapbox/node-pre-gyp/issues/260).
 - Added support for node v7
 - Updated to 1.3.0 of Mapnik Vector Tile (https://github.com/mapbox/mapnik-vector-tile/blob/master/CHANGELOG.md#130)
 - Removed Angus Clipper and replaced with Wagyu v0.4.2 (https://github.com/mapbox/wagyu)
diff --git a/Makefile b/Makefile
index c634041..003a1f4 100755
--- a/Makefile
+++ b/Makefile
@@ -2,32 +2,47 @@ MODULE_NAME := $(shell node -e "console.log(require('./package.json').binary.mod
 
 default: release
 
+ifneq (,$(findstring clang,$(CXX)))
+    PROFILING_FLAG += -gline-tables-only
+else
+    PROFILING_FLAG += -g
+endif
+
 deps/geometry/include/mapbox/geometry.hpp:
 	git submodule update --init
 
-mason_packages/.link/bin/mapnik-config: deps/geometry/include/mapbox/geometry.hpp
-	./install_mason.sh
-
-node_modules: mason_packages/.link/bin/mapnik-config
-	# install deps but for now ignore our own install script
-	# so that we can run it directly in either debug or release
+node_modules:
 	npm install --ignore-scripts --clang
 
-release: node_modules
-	PATH="./mason_packages/.link/bin/:${PATH}" && V=1 ./node_modules/.bin/node-pre-gyp configure build --loglevel=error --clang
+mason_packages/.link/bin/mapnik-config:
+	./scripts/install_deps.sh
+
+pre_build_check:
+	@node -e "console.log('\033[94mNOTICE: to build from source you need mapnik >=',require('./package.json').mapnik_version,'\033[0m');"
+	@echo "Looking for mapnik-config on your PATH..."
+	mapnik-config -v
+
+release_base: pre_build_check deps/geometry/include/mapbox/geometry.hpp node_modules
+	V=1 CXXFLAGS="-fno-omit-frame-pointer $(PROFILING_FLAG)" ./node_modules/.bin/node-pre-gyp configure build --ENABLE_GLIBC_WORKAROUND=true --loglevel=error --clang
 	@echo "run 'make clean' for full rebuild"
 
-debug: node_modules
-	PATH="./mason_packages/.link/bin/:${PATH}" && V=1 ./node_modules/.bin/node-pre-gyp configure build --loglevel=error --debug --clang
+debug_base: pre_build_check deps/geometry/include/mapbox/geometry.hpp node_modules
+	V=1 ./node_modules/.bin/node-pre-gyp configure build --ENABLE_GLIBC_WORKAROUND=true --loglevel=error --debug --clang
 	@echo "run 'make clean' for full rebuild"
 
+release: mason_packages/.link/bin/mapnik-config
+	CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" PATH="./mason_packages/.link/bin/:${PATH}" $(MAKE) release_base
+
+debug: mason_packages/.link/bin/mapnik-config
+	CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" PATH="./mason_packages/.link/bin/:${PATH}" $(MAKE) debug_base
+
 coverage:
 	./scripts/coverage.sh
 
 clean:
 	rm -rf lib/binding
 	rm -rf build
-	rm -rf mason
+	rm -rf .mason
 	find test/ -name *actual* -exec rm {} \;
 	echo "run make distclean to also remove mason_packages and node_modules"
 
@@ -50,6 +65,8 @@ docs:
 test:
 	npm test
 
+check: test
+
 testpack:
 	rm -f ./*tgz
 	npm pack
diff --git a/README.md b/README.md
index a89deee..6ff6430 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,6 @@ Bindings to [Mapnik](http://mapnik.org) for [node](http://nodejs.org).
 [![NPM](https://nodei.co/npm/mapnik.png?downloads=true&downloadRank=true)](https://nodei.co/npm/mapnik/)
 
 [![Build Status](https://secure.travis-ci.org/mapnik/node-mapnik.png)](https://travis-ci.org/mapnik/node-mapnik)
-[![Build status](https://ci.appveyor.com/api/projects/status/ju29v1vcpif2iww8?svg=true)](https://ci.appveyor.com/project/Mapbox/node-mapnik)
 [![Coverage Status](https://coveralls.io/repos/mapnik/node-mapnik/badge.svg)](https://coveralls.io/r/mapnik/node-mapnik)
 
 ## Usage
@@ -71,22 +70,22 @@ For more sample code see [the tests](./test) and [sample code](https://github.co
 
 OS|Node.js|C++ minimum requirements|OS versions
 ---|---|---|---
-Mac|v0.10.x, v4, v5, v6|C++11|Mac OS X > 10.10
-Linux|v0.10.x, v4, v5, v6|C++11|Ubuntu Linux > 16.04 or other Linux distributions with g++ >= 5 toolchain (>= GLIBCXX_3.4.21 from libstdc++)
-Windows|v0.10.x, v4, v5|C++11|See the [Windows requirements](https://github.com/mapnik/node-mapnik#windows-specific) section
+Mac|v0.10.x, v4, v6, v8|C++11|Mac OS X > 10.10
+Linux|v0.10.x, v4, v6, v8|C++11|Ubuntu Linux > 14.04 (trusty) or Centos >= 7 or other Linux distributions with a libstdc++ recent enough to contain >= GLIBCXX_3.4.19 symbols (libstdc++ that comes with at least g++ 4.8).
+Windows|v0.10.x, v4, v6, v8|C++11|See the [Windows requirements](https://github.com/mapnik/node-mapnik#windows-specific) section
 
 An installation error like below indicates your system does not have a modern enough libstdc++/gcc-base toolchain:
 
 ```
-Error: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.21 not found (required by /node_modules/osrm/lib/binding/osrm.node)
+Error: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found
 ```
 
-If you are running Ubuntu older than 16.04 you can easily upgrade your libstdc++ version like:
+If you are running Ubuntu older than 14.04 you can easily upgrade your libstdc++ version like:
 
 ```
 sudo add-apt-repository ppa:ubuntu-toolchain-r/test
 sudo apt-get update -y
-sudo apt-get install -y libstdc++-5-dev
+sudo apt-get install -y libstdc++6
 ```
 
 To upgrade libstdc++ on travis (without sudo) you can do:
@@ -115,16 +114,15 @@ Note: This will install the latest node-mapnik 3.x series, which is recommended.
 
 By default, binaries are provided for:
 
- - 64 bit OS X 10.9, 64 bit Linux (>= Ubuntu Trusty), and 64/32 bit Windows
+ - 64 bit OS X >= 10.10, 64 bit Linux (>= Ubuntu Trusty)
  - several node versions:
-   - [versions forLinux/Mac](<https://github.com/mapnik/node-mapnik/blob/master/.travis.yml#L19-L47>)
-   - [versions for Windows](<https://github.com/mapnik/node-mapnik/blob/master/appveyor.yml#L9-L32>)
+   - [versions for Linux/Mac](<https://github.com/mapnik/node-mapnik/blob/master/.travis.yml#L19-L47>)
 
 On those platforms no external dependencies are needed.
 
 Other platforms will fall back to a source compile: see [Source Build](#source-build) for details.
 
-Binaries started being provided at node-mapnik >= 1.4.2 for OSX and Linux and at 1.4.8 for Windows.
+Binaries started being provided at node-mapnik >= 1.4.2 for OSX and Linux and at 1.4.8 for Windows. After 3.6.2 no Windows binaries are provided.
 
 ### Windows specific
 
@@ -142,22 +140,46 @@ The **1.x** series require the Visual C++ Redistributable Packages for **Visual
 
 ## Source Build
 
-To build from source you need:
+There are two ways to build from source. These work on both OS X and Linux:
 
- - Mapnik >= v3.0.10
+ - A) Against a binary package from Mapnik from [mason](https://github.com/mapbox/mason)
+ - B) Against an existing version of Mapnik on your system
 
-Install Mapnik using the instructions at: https://github.com/mapnik/mapnik/wiki/Mapnik-Installation
+Using `A)` is recommended. You do not need to have Mapnik installed already, so this is the easiest and most predictable approach. When you use the route a binary package of Mapnik is download dynamically from [mason](https://github.com/mapbox/mason).
 
-Confirm that the `mapnik-config` program is available and on your `${PATH}`.
+You can invoke this method simply by running:
+
+  make release
+
+Or, for debug builds:
+
+  make debug
+
+If you want to do a full rebuild do:
+
+  make distclean
+
+And then re-run the build:
+
+  make release
+
+Using `B)` is also possible, if you would like to build node-mapnik against an external, already installed Mapnik version.
+
+In this case you need to have a Mapnik version installed that is at least as recent as the `mapnik_version` property in the [`package.json`](./package.json) for the branch of node-mapnik you want to build.
+
+And you need to have the `mapnik-config` program is available and on your `${PATH}`.
 
 Then run (within the cloned `node-mapnik` directory:
 
-    npm install --build-from-source
+    make release_base
 
-### Windows specific
+#### Note on SSE:
 
-Windows builds are maintained in https://github.com/mapbox/windows-builds
+By default node mapnik is built with SSE support. If you are building on a platform that is not `x86_64` you will need to disable feature by setting the environment variable `SSE_MATH=false`.
 
+```
+SSE_MATH=false make
+```
 
 ## Using node-mapnik from your node app
 
@@ -173,4 +195,4 @@ To run the tests do:
 
 ## License
 
-  BSD, see LICENSE.txt
+BSD, see LICENSE.txt
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 21c3ccc..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,45 +0,0 @@
-environment:
-  node_pre_gyp_accessKeyId:
-    secure: 7DrSVc5eIGtmMcki5H+iRft+Tk3MJTwDBQEUuJHWaQ4=
-  node_pre_gyp_secretAccessKey:
-    secure: 1amwJJw9fu0j6dXnc5KsAQbSYf7Cjw/dapT6OZWABa6nc52grkKeLQ+DGaOfQz8i
-  matrix:
-    - nodejs_version: 0.10
-      msvs_toolset: 14
-      platform: x64
-    - nodejs_version: 0.10
-      msvs_toolset: 14
-      platform: x86
-    - nodejs_version: 4
-      msvs_toolset: 14
-      platform: x64
-    - nodejs_version: 4
-      msvs_toolset: 14
-      platform: x86
-    - nodejs_version: 6
-      msvs_toolset: 14
-      platform: x64
-    - nodejs_version: 6
-      msvs_toolset: 14
-      platform: x86
-    - nodejs_version: 8
-      msvs_toolset: 14
-      platform: x64
-    - nodejs_version: 8
-      msvs_toolset: 14
-      platform: x86
-
-os: Visual Studio 2015
-
-clone_depth: 20
-
-install:
-  - scripts\build-appveyor.bat
-
-artifacts:
-  - path: build\stage\**\*.gz
-    name: package
-
-build: off
-test: off
-deploy: off
diff --git a/binding.gyp b/binding.gyp
index dd58659..6bdf3b1 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -1,32 +1,12 @@
 {
   'includes': [ 'common.gypi' ],
+  'variables': {
+      'ENABLE_GLIBC_WORKAROUND%':'false', # can be overriden by a command line variable because of the % sign
+      'enable_sse%':'true' 
+  },
   'targets': [
     {
-      'target_name': 'make_vector_tile',
-      'hard_dependency': 1,
-      'type': 'none',
-      'actions': [
-        {
-          'action_name': 'generate_setting',
-          'inputs': [
-            'gen_settings.py'
-          ],
-          'outputs': [
-            '<(SHARED_INTERMEDIATE_DIR)/mapnik_settings.js'
-          ],
-          'action': ['python', 'gen_settings.py', '<(SHARED_INTERMEDIATE_DIR)/mapnik_settings.js']
-        }
-      ],
-      'copies': [
-        {
-          'files': [ '<(SHARED_INTERMEDIATE_DIR)/mapnik_settings.js' ],
-          'destination': '<(module_path)'
-        }
-      ]
-    },
-    {
       'target_name': '<(module_name)',
-      'dependencies': [ 'make_vector_tile' ],
       'product_dir': '<(module_path)',
       'sources': [
         "src/mapnik_logger.cpp",
@@ -70,6 +50,11 @@
           'MAPNIK_GIT_REVISION="<!@(mapnik-config --git-describe)"',
       ],
       'conditions': [
+        ['ENABLE_GLIBC_WORKAROUND != "false"', {
+            'sources': [
+              "src/glibc_workaround.cpp"
+            ]
+        }],
         ['OS=="win"',
           {
             'include_dirs':[
@@ -97,7 +82,6 @@
             'cflags_cc!': ['-fno-rtti', '-fno-exceptions'],
             'cflags_cc' : [
               '<!@(mapnik-config --cflags)',
-              '-D_GLIBCXX_USE_CXX11_ABI=0'
             ],
             'libraries':[
               '<!@(mapnik-config --libs)',
@@ -129,7 +113,10 @@
               'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0'
             }
           },
-        ]
+        ],
+        ['enable_sse == "true"', {
+          'defines' : [ 'SSE_MATH' ]
+        }]
       ]
     },
     {
diff --git a/gen_settings.py b/gen_settings.py
deleted file mode 100644
index 3aa3e38..0000000
--- a/gen_settings.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import os
-import sys
-
-settings = os.path.abspath(sys.argv[1])
-
-# this goes into a mapnik_settings.js file beside the C++ _mapnik.node
-settings_template = """
-module.exports.paths = {
-    'fonts': %s,
-    'input_plugins': %s
-};
-"""
-
-def write_mapnik_settings(fonts='undefined',input_plugins='undefined'):
-    global settings_template
-    if '__dirname' in fonts or '__dirname' in input_plugins:
-        settings_template = "var path = require('path');\n" + settings_template
-    open(settings,'w').write(settings_template % (fonts,input_plugins))
-
-
-if __name__ == '__main__':
-    settings_dict = {}
-    
-    # settings for fonts and input plugins
-    # environment settings are for windows tilemill packaging:
-    # https://github.com/mapbox/tilemill/blob/master/platforms/windows/package.bat#L37
-    ip = os.environ.get('MAPNIK_INPUT_PLUGINS')
-    if ip:
-        settings_dict['input_plugins'] = ip
-    else:
-        settings_dict['input_plugins'] = '\'%s\'' % os.popen("./mason_packages/.link/bin/mapnik-config --input-plugins").readline().strip()
-    
-    mf = os.environ.get('MAPNIK_FONTS')
-    if mf:
-        settings_dict['fonts'] = mf
-    else:
-        settings_dict['fonts'] = '\'%s\'' % os.popen("./mason_packages/.link/bin/mapnik-config --fonts").readline().strip()
-
-    write_mapnik_settings(**settings_dict)
diff --git a/package.json b/package.json
index 06dbe48..221b70c 100644
--- a/package.json
+++ b/package.json
@@ -4,8 +4,8 @@
   "url": "http://github.com/mapnik/node-mapnik",
   "homepage": "http://mapnik.org",
   "author": "Dane Springmeyer <dane at mapbox.com> (mapnik.org)",
-  "version": "3.6.2",
-  "mapnik_version":"v3.0.15",
+  "version": "3.7.0",
+  "mapnik_version":"v3.0.18",
   "main": "./lib/mapnik.js",
   "binary": {
     "module_name": "mapnik",
@@ -36,27 +36,27 @@
   ],
   "license": "BSD-3-Clause",
   "dependencies": {
-    "mapnik-vector-tile": "1.4.0",
+    "mapnik-vector-tile": "1.6.1",
     "protozero": "1.5.1",
-    "nan": "~2.5.0",
+    "nan": "~2.8.0",
     "node-pre-gyp": "~0.6.30"
   },
   "bundledDependencies": [
-      "node-pre-gyp"
+    "node-pre-gyp"
   ],
   "bin": {
+    "mapnik-index.js": "./bin/mapnik-index.js",
     "mapnik-inspect.js": "./bin/mapnik-inspect.js",
     "mapnik-render.js": "./bin/mapnik-render.js",
     "mapnik-shapeindex.js": "./bin/mapnik-shapeindex.js"
   },
   "scripts": {
-    "prepublish": "npm ls",
+    "prepublishOnly": "npm ls",
     "test": "jshint bin lib/index.js lib/mapnik.js && mocha -R spec --timeout 50000",
     "install": "node-pre-gyp install --fallback-to-build",
     "docs": "documentation build src/*.cpp src/mapnik_plugins.hpp --polyglot -o documentation -f html --github --name Mapnik"
   },
   "devDependencies": {
-    "node-gyp": "^3.6.1",
     "aws-sdk": "2.0.12",
     "jshint": "^2.5.10",
     "mocha": "2.x",
diff --git a/scripts/build-appveyor.bat b/scripts/build-appveyor.bat
deleted file mode 100644
index e25df5e..0000000
--- a/scripts/build-appveyor.bat
+++ /dev/null
@@ -1,136 +0,0 @@
- at ECHO OFF
-SETLOCAL
-SET EL=0
-
-ECHO =========== %~f0 ===========
-
-git submodule update --init
-IF %ERRORLEVEL% NEQ 0 ECHO could not update submodules && GOTO ERROR
-
-:: only run Install-Product on AppVeyor
-:: TODO: check requested node version on local builds and bail if it doesn't match
-IF /I "%APPVEYOR%"=="True" powershell Install-Product node %nodejs_version% %PLATFORM%
-IF %ERRORLEVEL% NEQ 0 ECHO could not install requested node version && GOTO ERROR
-
-SET MAPNIK_GIT=
-FOR /F "tokens=*" %%i in ('node -e "console.log(require(""./package.json"").mapnik_version)"') DO SET MAPNIK_GIT=%%i
-
-:: use 64 bit python if platform is 64 bit
-IF /I "%PLATFORM%" == "x64" set PATH=C:\Python27-x64;%PATH%
-:: put 7z on path (needed for unpacking mapnik sdk)
-SET PATH=C:\Program Files\7-Zip;%PATH%
-
-:: TODO - dist/dev/ is intended for dev releases of mapnik
-:: We ideally want to get in the habit of only using Mapnik official releases
-:: which will be uploaded to dist/
-SET MAPNIK_SDK_URL=https://mapnik.s3.amazonaws.com/dist/dev/mapnik-win-sdk-%MAPNIK_GIT%-%platform%-%msvs_toolset%.0.7z
-ECHO fetching mapnik sdk^: %MAPNIK_SDK_URL%
-IF EXIST mapnik-sdk.7z (ECHO already downloaded) ELSE (powershell Invoke-WebRequest "${env:MAPNIK_SDK_URL}" -OutFile mapnik-sdk.7z)
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-ECHO extracting mapnik sdk
-IF EXIST mapnik-sdk (ECHO already extracted) ELSE (7z -y x mapnik-sdk.7z | %windir%\system32\FIND "ing archive")
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-:: HACK!! to make node at 4.x x86 builds work
-:: see: https://github.com/mapbox/node-pre-gyp/issues/209#issuecomment-217690537
-CALL npm config set -g cafile=package.json
-CALL npm config set -g strict-ssl=false
-
-ECHO activating VS command prompt...
-IF /I %platform% == x64 CALL "C:\Program Files (x86)\Microsoft Visual Studio %msvs_toolset%.0\VC\vcvarsall.bat" amd64
-IF /I %platform% == x86 CALL "C:\Program Files (x86)\Microsoft Visual Studio %msvs_toolset%.0\VC\vcvarsall.bat" x86
-
-ECHO available node.exe:
-where node
-ECHO available npm^:
-where npm
-
-ECHO node -v && CALL node -v
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-ECHO node that gets called && CALL node -e "console.log(process.arch,process.execPath)"
-ECHO npm -v && CALL npm -v
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-ECHO ===== where npm puts stuff START ============
-ECHO npm root && CALL npm root
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-ECHO npm root -g && CALL npm root -g
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-ECHO npm bin && CALL npm bin
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-ECHO npm bin -g && CALL npm bin -g
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-SET NPM_BIN_DIR=
-FOR /F "tokens=*" %%i in ('CALL npm bin -g') DO SET NPM_BIN_DIR=%%i
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-IF /I "%NPM_BIN_DIR%"=="%CD%" ECHO ERROR npm bin -g equals local directory && SET ERRORLEVEL=1 && GOTO ERROR
-ECHO ===== where npm puts stuff END ============
-
-:: get ready to build agains the mapnik SDK
-SET MAPNIK_SDK=%CD%\mapnik-sdk
-SET PATH=%MAPNIK_SDK%\bin;%MAPNIK_SDK%\lib;%PATH%
-SET PROJ_LIB=%MAPNIK_SDK%\share\proj
-SET GDAL_DATA=%MAPNIK_SDK%\share\gdal
-SET ICU_DATA=%MAPNIK_SDK%\share\icu
-
-:: actually install deps + compile node-mapnik
-ECHO building node-mapnik
-:: --msvs_version=2015 is passed along to node-gyp here
-CALL npm install --build-from-source --msvs_version=2015 --loglevel=http --node_shared=true
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-FOR /F "tokens=*" %%i in ('CALL node_modules\.bin\node-pre-gyp reveal module_path --silent') DO SET NODEMAPNIK_BINDING_DIR=%%i
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-ECHO NODEMAPNIK_BINDING_DIR^: %NODEMAPNIK_BINDING_DIR%
-IF "%NODEMAPNIK_BINDING_DIR%"=="" ECHO ERROR could not determine binding dir && SET ERRORLEVEL=1 && GOTO ERROR
-
-powershell scripts\build_against_sdk_02-copy-deps-to-bindingdir.ps1
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-powershell scripts\show_module_runtime.ps1 %CD%
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-powershell scripts\build_against_sdk_03-write-mapnik.settings.ps1
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-CALL npm test
-:: uncomment to allow build to work even if tests do not pass
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-ECHO APPVEYOR_REPO_COMMIT_MESSAGE^: %APPVEYOR_REPO_COMMIT_MESSAGE%
-SET CM=%APPVEYOR_REPO_COMMIT_MESSAGE%
-
-:: publish binaries to v140 path
-IF NOT "%CM%" == "%CM:[publish binary]=%" (ECHO publishing v140... && CALL node_modules\.bin\node-pre-gyp package publish --toolset=v140) ELSE (ECHO not publishing)
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-IF NOT "%CM%" == "%CM:[republish binary]=%" (ECHO republishing v140 ... && CALL node_modules\.bin\node-pre-gyp package unpublish publish --toolset=v140) ELSE (ECHO not republishing)
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-ECHO packaging ...
-CALL node_modules\.bin\node-pre-gyp package
-IF %ERRORLEVEL% NEQ 0 ECHO error during packaging && GOTO ERROR
-
-:: publish binaries to default path
-:: in the future this may change depending on:
-:: 1) what visual studio versions we support
-:: 2) how visual studio binaries are or are not compatible with each other
-:: more details: https://github.com/mapnik/node-mapnik/issues/756
-IF NOT "%CM%" == "%CM:[publish binary]=%" (ECHO publishing... && CALL node_modules\.bin\node-pre-gyp publish) ELSE (ECHO not publishing)
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-IF NOT "%CM%" == "%CM:[republish binary]=%" (ECHO republishing ... && CALL node_modules\.bin\node-pre-gyp unpublish publish) ELSE (ECHO not republishing)
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-
-GOTO DONE
-
-:ERROR
-ECHO =========== ERROR %~f0 ===========
-ECHO ERRORLEVEL^: %ERRORLEVEL%
-SET EL=%ERRORLEVEL%
-
-:DONE
-ECHO =========== DONE %~f0 ===========
-
-EXIT /b %EL%
diff --git a/scripts/build-local.bat b/scripts/build-local.bat
deleted file mode 100644
index 803c20d..0000000
--- a/scripts/build-local.bat
+++ /dev/null
@@ -1,65 +0,0 @@
- at ECHO OFF
-SETLOCAL
-SET EL=0
-
-ECHO =========== %~f0 ===========
-
-::build system (https://github.com/mapbox/windows-builds) has to be setup up
-::and mapnik and all its dependencies have to be built already
-::and settings.bat must have been run to have all env vars available
-SET USE_LOCAL_MAPNIK_SDK=0
-
-SET APPVEYOR_REPO_COMMIT_MESSAGE=no commit message provided
-SET MAPNIK_GIT=
-FOR /F "tokens=*" %%i in ('node -e "console.log(require(""./package.json"").mapnik_version)"') DO SET MAPNIK_GIT=%%i
-SET nodejs_version=5.1.0
-SET platform=x64
-SET msvs_toolset=14
-SET TOOLSET_ARGS=--dist-url=https://s3.amazonaws.com/mapbox/node-cpp11 --toolset=v140
-
-
-:::::::::::::: OVERRIDE PARAMETERS
-:NEXT-ARG
-
-IF '%1'=='' GOTO ARGS-DONE
-ECHO setting %1
-SET %1
-SHIFT
-GOTO NEXT-ARG
-
-:ARGS-DONE
-
-
-IF %USE_LOCAL_MAPNIK_SDK% EQU 0 GOTO START_BUILD
-
-SET LOCAL_MAPNIK_SDK_DIR=%PKGDIR%\mapnik-%MAPNIKBRANCH%\mapnik-gyp\mapnik-sdk
-ECHO ----------- using local mapnik build !!!!!!!!!!!!!!!!!! && ECHO copying mapnik SDK...
-ECHO %LOCAL_MAPNIK_SDK_DIR%
-XCOPY /Y /Q /S /E %LOCAL_MAPNIK_SDK_DIR%\*.* .\mapnik-sdk\
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-:START_BUILD
-
-ECHO APPVEYOR_REPO_COMMIT_MESSAGE^: %APPVEYOR_REPO_COMMIT_MESSAGE%
-ECHO MAPNIK_GIT^: %MAPNIK_GIT%
-ECHO nodejs_version^: %nodejs_version%
-ECHO platform^: %platform%
-ECHO msvs_toolset^: %msvs_toolset%
-ECHO TOOLSET_ARGS^: %TOOLSET_ARGS%
-ECHO USE_LOCAL_MAPNIK_SDK^: %USE_LOCAL_MAPNIK_SDK%
-
-
-ECHO calling build-appveyor.bat... && CALL scripts\build-appveyor.bat
-ECHO build-appveyor.bat finshed, ERRORLEVEL^: %ERRORLEVEL%
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-GOTO DONE
-
-:ERROR
-ECHO ~~~~~~~~~~~~~~~ ERROR %~f0 ~~~~~~~~~~~~~~~
-SET EL=%ERRORLEVEL%
-ECHO ERRORLEVEL^: %EL%
-
-:DONE
-ECHO =========== DONE %~f0 ===========
-EXIT /B %EL%
\ No newline at end of file
diff --git a/scripts/build_against_sdk_02-copy-deps-to-bindingdir.ps1 b/scripts/build_against_sdk_02-copy-deps-to-bindingdir.ps1
deleted file mode 100644
index 791c17f..0000000
--- a/scripts/build_against_sdk_02-copy-deps-to-bindingdir.ps1
+++ /dev/null
@@ -1,40 +0,0 @@
-$msg_prefix='====================== '
-
-Try{
-
-    Write-Output "copy binding libs"
-    Write-Output "from: $env:MAPNIK_SDK"
-    Write-Output "to: $env:NODEMAPNIK_BINDING_DIR"
-
-    Copy-Item $env:MAPNIK_SDK\bin\shapeindex.exe $env:NODEMAPNIK_BINDING_DIR\ -ErrorAction Stop
-    Copy-Item $env:MAPNIK_SDK\bin\mapnik-index.exe $env:NODEMAPNIK_BINDING_DIR\ -ErrorAction Stop
-
-    $deps = Get-ChildItem -Path $env:MAPNIK_SDK\lib -Filter *.dll | % { $_.FullName }
-
-	##COPY DEPENDENCIES TO BINDING DIR
-	Write-Output "$msg_prefix copying dependencies to binding dir:"
-	foreach($dep in $deps){
-    	Write-Output $dep
-        Copy-Item $dep $env:NODEMAPNIK_BINDING_DIR -ErrorAction Stop
-	}
-
-	###COPY FONTS AND INPUT PLUGINS TO BINDING DIR
-    $srcDir="$env:MAPNIK_SDK\lib\mapnik\"
-    $destDir="$env:NODEMAPNIK_BINDING_DIR\mapnik\"
-	Write-Output "$msg_prefix copying fonts and input plugins to binding dir:"
-	Write-Output "$srcDir --> $destDir"
-    Copy-Item -Path $srcDir -Destination $destDir -Force -Recurse -ErrorAction Stop
-
-    ##COPY GDAL AND PROJ TO BINDING DIR
-    $srcDir="$env:MAPNIK_SDK\share"
-    $destDir="$env:NODEMAPNIK_BINDING_DIR\share"
-	Write-Output "$msg_prefix copying gdal and proj to binding dir:"
-	Write-Output "$srcDir --> $destDir"
-    Copy-Item -Path $srcDir -Destination $destDir -Force -Recurse -ErrorAction Stop
-
-}
-Catch {
-	Write-Output "`n`n$msg_prefix`n!!!!EXCEPTION!!!`n$msg_prefix`n`n"
-	Write-Output "$_.Exception.Message`n"
-	Exit 1
-}
diff --git a/scripts/build_against_sdk_03-write-mapnik.settings.ps1 b/scripts/build_against_sdk_03-write-mapnik.settings.ps1
deleted file mode 100644
index 97d0923..0000000
--- a/scripts/build_against_sdk_03-write-mapnik.settings.ps1
+++ /dev/null
@@ -1,24 +0,0 @@
-$msg_prefix='====================== '
-
-Try{
-    $file="$env:NODEMAPNIK_BINDING_DIR\mapnik_settings.js"
-    Write-Output "writing settings to --> $file"
-"var path = require('path');
-module.exports.paths = {
-    'fonts': path.join(__dirname, 'mapnik/fonts'),
-    'input_plugins': path.join(__dirname, 'mapnik/input'),
-    'mapnik_index': path.join(__dirname, 'mapnik/bin/mapnik-index'),
-    'shape_index': path.join(__dirname, 'mapnik/bin/shapeindex')
-};
-module.exports.env = {
-    'ICU_DATA': path.join(__dirname, 'share/icu'),
-    'GDAL_DATA': path.join(__dirname, 'share/gdal'),
-    'PROJ_LIB': path.join(__dirname, 'share/proj'),
-    'PATH': __dirname
-};" | Out-File -Encoding UTF8 $file
-}
-Catch {
-	Write-Output "`n`n$msg_prefix`n!!!!EXCEPTION!!!`n$msg_prefix`n`n"
-	Write-Output "$_.Exception.Message`n"
-	Exit 1
-}
diff --git a/scripts/check_glibcxx.sh b/scripts/check_glibcxx.sh
new file mode 100755
index 0000000..b7b6d05
--- /dev/null
+++ b/scripts/check_glibcxx.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -eu
+set -o pipefail
+shopt -s nullglob
+
+: '
+
+Ensure no GLIBCXX_3.4.2x symbols are present in the binary
+
+If symbols >= 3.4.20 then it returns error code 1. This means
+the binaries would not run on ubuntu trusty without upgrading libstdc++
+
+'
+
+FINAL_RETURN_CODE=0
+
+function check() {
+    local RESULT=0
+    nm ${1} | grep "GLIBCXX_3.4.2[0-9]" > /tmp/out.txt || RESULT=$?
+    if [[ ${RESULT} != 0 ]]; then
+        echo "Success: GLIBCXX_3.4.2[0-9] symbols not present in binary (as expected)"
+    else
+        echo "$(cat /tmp/out.txt | c++filt)"
+        FINAL_RETURN_CODE=1
+    fi
+}
+
+
+echo "checking ./lib/binding/mapnik.node"
+check "lib/binding/mapnik.node"
+
+exit ${FINAL_RETURN_CODE}
diff --git a/install_mason.sh b/scripts/install_deps.sh
similarity index 62%
rename from install_mason.sh
rename to scripts/install_deps.sh
index 28b4f5d..9fd2a26 100755
--- a/install_mason.sh
+++ b/scripts/install_deps.sh
@@ -4,16 +4,14 @@ set -eu
 set -o pipefail
 
 function install() {
-    ./mason/mason install $1 $2
-    ./mason/mason link $1 $2
+    mason install $1 $2
+    mason link $1 $2
 }
 
 ICU_VERSION="57.1"
 
-if [ ! -f ./mason/mason.sh ]; then
-    mkdir -p ./mason
-    curl -sSfL https://github.com/mapbox/mason/archive/c1948184d9430226e36f1bc1f8f081268b6bc2ba.tar.gz | tar --gunzip --extract --strip-components=1 --exclude="*md" --exclude="test*" --directory=./mason
-fi
+./scripts/setup.sh --config local.env
+source local.env
 
 if [ ! -f ./mason_packages/.link/bin/mapnik-config ]; then
 
@@ -27,10 +25,10 @@ if [ ! -f ./mason_packages/.link/bin/mapnik-config ]; then
     install cairo 1.14.8
     install webp 0.6.0
     install libgdal 2.1.3
-    install boost 1.63.0
-    install boost_libsystem 1.63.0
-    install boost_libfilesystem 1.63.0
-    install boost_libregex_icu57 1.63.0
+    install boost 1.65.1
+    install boost_libsystem 1.65.1
+    install boost_libfilesystem 1.65.1
+    install boost_libregex_icu57 1.65.1
     install freetype 2.7.1
     install harfbuzz 1.4.2-ft
 
@@ -38,5 +36,5 @@ if [ ! -f ./mason_packages/.link/bin/mapnik-config ]; then
     # NOTE: sync this version with the `mapnik_version` in package.json (which is used for windows builds)
     # In the future we could pull from that version automatically if mason were to support knowing the right dep
     # versions to install automatically. Until then there is not much point since the deps are still hardcoded here.
-    install mapnik 3.0.15
+    install mapnik 3.0.18
 fi
diff --git a/scripts/postinstall.sh b/scripts/postinstall.sh
index ba6aae3..23ec528 100755
--- a/scripts/postinstall.sh
+++ b/scripts/postinstall.sh
@@ -5,6 +5,30 @@ set -o pipefail
 MODULE_PATH=./lib/binding
 MAPNIK_SDK=./mason_packages/.link
 
+# Check if we are using Mason's mapnik
+if [[ ! "$(which mapnik-config)" -ef "$MAPNIK_SDK/bin/mapnik-config" ]]; then
+  echo "
+var path = require('path');
+module.exports.paths = {
+    'fonts':         '$(mapnik-config --fonts)',
+    'input_plugins': '$(mapnik-config --input-plugins)',
+    'mapnik_index':  '$(which mapnik-index)',
+    'shape_index':   '$(which shapeindex)'
+};
+" > ${MODULE_PATH}/mapnik_settings.js
+# once https://github.com/mapnik/mapnik/pull/3759 is fixed
+# this can be enabled
+#  echo "
+#module.exports.env = {
+#    'ICU_DATA':      '$(mapnik-config --icu-data)',
+#    'GDAL_DATA':     '$(mapnik-config --gdal-data)',
+#    'PROJ_LIB':      '$(mapnik-config --proj-lib)'
+#};
+#" >> ${MODULE_PATH}/mapnik_settings.js
+
+  exit 0;
+fi
+
 mkdir -p ${MODULE_PATH}/bin/
 
 # the below switch is used since on osx the default cp
diff --git a/scripts/setup.sh b/scripts/setup.sh
index 90b7de3..61a0d1d 100755
--- a/scripts/setup.sh
+++ b/scripts/setup.sh
@@ -3,8 +3,8 @@
 set -eu
 set -o pipefail
 
-export MASON_RELEASE="${MASON_RELEASE:-0.7.0}"
-export MASON_LLVM_RELEASE="${MASON_LLVM_RELEASE:-3.9.1}"
+export MASON_RELEASE="${MASON_RELEASE:-89d9b31}"
+export MASON_LLVM_RELEASE="${MASON_LLVM_RELEASE:-5.0.0}"
 
 PLATFORM=$(uname | tr A-Z a-z)
 if [[ ${PLATFORM} == 'darwin' ]]; then
@@ -58,7 +58,7 @@ function run() {
       local mason_release=${2}
       if [[ ! -d ${install_dir} ]]; then
           mkdir -p ${install_dir}
-          curl -sSfL https://github.com/mapbox/mason/archive/v${mason_release}.tar.gz | tar --gunzip --extract --strip-components=1 --directory=${install_dir}
+          curl -sSfL https://github.com/mapbox/mason/archive/${mason_release}.tar.gz | tar --gunzip --extract --strip-components=1 --directory=${install_dir}
       fi
     }
 
diff --git a/src/glibc_workaround.cpp b/src/glibc_workaround.cpp
new file mode 100644
index 0000000..c02cfe0
--- /dev/null
+++ b/src/glibc_workaround.cpp
@@ -0,0 +1,26 @@
+#ifdef __linux__
+
+#ifdef MAPNIK_ENABLE_GLIBC_WORKAROUND
+
+#include <stdexcept>
+
+// https://github.com/bitcoin/bitcoin/pull/4042
+// allows building against libstdc++-dev-4.9 while avoiding
+// GLIBCXX_3.4.20 dep
+// This is needed because libstdc++ itself uses this API - its not
+// just an issue of your code using it, ughhh
+
+namespace std
+{
+
+void __throw_out_of_range_fmt(const char *, ...) __attribute__((__noreturn__));
+void __throw_out_of_range_fmt(const char *err, ...)
+{
+    // Safe and over-simplified version. Ignore the format and print it as-is.
+    __throw_out_of_range(err);
+}
+}
+
+#endif // MAPNIK_ENABLE_GLIBC_WORKAROUND
+
+#endif // __linux__
\ No newline at end of file
diff --git a/src/mapnik_color.cpp b/src/mapnik_color.cpp
index dcfa962..7be4ff2 100644
--- a/src/mapnik_color.cpp
+++ b/src/mapnik_color.cpp
@@ -13,7 +13,7 @@ Nan::Persistent<v8::FunctionTemplate> Color::constructor;
 /**
  * **`mapnik.Color`**
  *
- * A `mapnik.Color` object used for handling and converting colors 
+ * A `mapnik.Color` object used for handling and converting colors
  *
  * @class Color
  * @param {string|number} value either an array of [r, g, b, a],
@@ -81,12 +81,12 @@ NAN_METHOD(Color::New)
     color_ptr c_p;
     try
     {
-        if (info.Length() == 1 && 
+        if (info.Length() == 1 &&
             info[0]->IsString())
         {
             c_p = std::make_shared<mapnik::color>(TOSTR(info[0]));
         }
-        else if (info.Length() == 2 && 
+        else if (info.Length() == 2 &&
                  info[0]->IsString() &&
                  info[1]->IsBoolean())
         {
@@ -95,7 +95,7 @@ NAN_METHOD(Color::New)
         else if (info.Length() == 3 &&
                  info[0]->IsNumber() &&
                  info[1]->IsNumber() &&
-                 info[2]->IsNumber()) 
+                 info[2]->IsNumber())
         {
             int r = info[0]->IntegerValue();
             int g = info[1]->IntegerValue();
@@ -106,12 +106,12 @@ NAN_METHOD(Color::New)
                 return;
             }
             c_p = std::make_shared<mapnik::color>(r,g,b);
-        } 
+        }
         else if (info.Length() == 4 &&
                  info[0]->IsNumber() &&
                  info[1]->IsNumber() &&
                  info[2]->IsNumber() &&
-                 info[3]->IsBoolean()) 
+                 info[3]->IsBoolean())
         {
             int r = info[0]->IntegerValue();
             int g = info[1]->IntegerValue();
@@ -122,12 +122,12 @@ NAN_METHOD(Color::New)
                 return;
             }
             c_p = std::make_shared<mapnik::color>(r,g,b,255,info[3]->BooleanValue());
-        } 
+        }
         else if (info.Length() == 4 &&
                  info[0]->IsNumber() &&
                  info[1]->IsNumber() &&
                  info[2]->IsNumber() &&
-                 info[3]->IsNumber()) 
+                 info[3]->IsNumber())
         {
             int r = info[0]->IntegerValue();
             int g = info[1]->IntegerValue();
@@ -139,13 +139,13 @@ NAN_METHOD(Color::New)
                 return;
             }
             c_p = std::make_shared<mapnik::color>(r,g,b,a);
-        } 
+        }
         else if (info.Length() == 5 &&
                  info[0]->IsNumber() &&
                  info[1]->IsNumber() &&
                  info[2]->IsNumber() &&
                  info[3]->IsNumber() &&
-                 info[4]->IsBoolean()) 
+                 info[4]->IsBoolean())
         {
             int r = info[0]->IntegerValue();
             int g = info[1]->IntegerValue();
@@ -157,8 +157,8 @@ NAN_METHOD(Color::New)
                 return;
             }
             c_p = std::make_shared<mapnik::color>(r,g,b,a,info[4]->BooleanValue());
-        } 
-        else 
+        }
+        else
         {
             Nan::ThrowTypeError("invalid arguments: colors can be created from a string, integer r,g,b values, or integer r,g,b,a values");
             return;
@@ -183,10 +183,11 @@ v8::Local<v8::Value> Color::NewInstance(mapnik::color const& color) {
     Color* c = new Color();
     c->this_ = std::make_shared<mapnik::color>(color);
     v8::Local<v8::Value> ext = Nan::New<v8::External>(c);
-    return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Color instance");
+    return scope.Escape(maybe_local.ToLocalChecked());
 }
 
-
 NAN_GETTER(Color::get_prop)
 {
     Color* c = Nan::ObjectWrap::Unwrap<Color>(info.Holder());
diff --git a/src/mapnik_datasource.cpp b/src/mapnik_datasource.cpp
index 1f5fd22..881249a 100644
--- a/src/mapnik_datasource.cpp
+++ b/src/mapnik_datasource.cpp
@@ -147,7 +147,9 @@ v8::Local<v8::Value> Datasource::NewInstance(mapnik::datasource_ptr ds_ptr) {
     Datasource* d = new Datasource();
     d->datasource_ = ds_ptr;
     v8::Local<v8::Value> ext = Nan::New<v8::External>(d);
-    return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Datasource instance");
+    return scope.Escape(maybe_local.ToLocalChecked());
 }
 
 NAN_METHOD(Datasource::parameters)
diff --git a/src/mapnik_feature.cpp b/src/mapnik_feature.cpp
index be0a9ab..d2ac6a1 100644
--- a/src/mapnik_feature.cpp
+++ b/src/mapnik_feature.cpp
@@ -114,7 +114,9 @@ NAN_METHOD(Feature::fromJSON)
         }
         Feature* feat = new Feature(f);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(feat);
-        info.GetReturnValue().Set(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+        Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Feature instance");
+        else info.GetReturnValue().Set(maybe_local.ToLocalChecked());
     }
     catch (std::exception const& ex)
     {
@@ -132,7 +134,9 @@ v8::Local<v8::Value> Feature::NewInstance(mapnik::feature_ptr f_ptr)
     Nan::EscapableHandleScope scope;
     Feature* f = new Feature(f_ptr);
     v8::Local<v8::Value> ext = Nan::New<v8::External>(f);
-    return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Feature instance");
+    return scope.Escape(maybe_local.ToLocalChecked());
 }
 
 /**
diff --git a/src/mapnik_featureset.cpp b/src/mapnik_featureset.cpp
index 0b306b0..3e1e50a 100644
--- a/src/mapnik_featureset.cpp
+++ b/src/mapnik_featureset.cpp
@@ -5,7 +5,7 @@ Nan::Persistent<v8::FunctionTemplate> Featureset::constructor;
 
 /**
  * **`mapnik.Featureset`**
- * 
+ *
  * An iterator of {@link mapnik.Feature} objects.
  *
  * @class Featureset
@@ -74,10 +74,10 @@ NAN_METHOD(Featureset::next)
         }
         catch (std::exception const& ex)
         {
-            // It is not immediately obvious how this could cause an exception, a check of featureset plugin 
+            // It is not immediately obvious how this could cause an exception, a check of featureset plugin
             // implementations resulted in no obvious way that an exception could be raised. Therefore, it
             // is not obvious currently what could raise this exception. However, since a plugin could possibly
-            // be developed outside of mapnik core plugins that could raise here we are probably best still 
+            // be developed outside of mapnik core plugins that could raise here we are probably best still
             // wrapping this in a try catch.
             /* LCOV_EXCL_START */
             Nan::ThrowError(ex.what());
@@ -98,5 +98,7 @@ v8::Local<v8::Value> Featureset::NewInstance(mapnik::featureset_ptr fsp)
     Featureset* fs = new Featureset();
     fs->this_ = fsp;
     v8::Local<v8::Value> ext = Nan::New<v8::External>(fs);
-    return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Featureset instance");
+    return scope.Escape(maybe_local.ToLocalChecked());
 }
diff --git a/src/mapnik_geometry.cpp b/src/mapnik_geometry.cpp
index f122867..1512c21 100644
--- a/src/mapnik_geometry.cpp
+++ b/src/mapnik_geometry.cpp
@@ -88,7 +88,9 @@ v8::Local<v8::Value> Geometry::NewInstance(mapnik::feature_ptr f) {
     Nan::EscapableHandleScope scope;
     Geometry* g = new Geometry(f);
     v8::Local<v8::Value> ext = Nan::New<v8::External>(g);
-    return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Geometry instance");
+    return scope.Escape(maybe_local.ToLocalChecked());
 }
 
 /**
diff --git a/src/mapnik_grid_view.cpp b/src/mapnik_grid_view.cpp
index 0b7cae3..3d66882 100644
--- a/src/mapnik_grid_view.cpp
+++ b/src/mapnik_grid_view.cpp
@@ -83,7 +83,9 @@ v8::Local<v8::Value> GridView::NewInstance(Grid * JSGrid,
     GridView* gv = new GridView(JSGrid);
     gv->this_ = std::make_shared<mapnik::grid_view>(JSGrid->get()->get_view(x,y,w,h));
     v8::Local<v8::Value> ext = Nan::New<v8::External>(gv);
-    return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new GridView instance");
+    return scope.Escape(maybe_local.ToLocalChecked());
 }
 
 NAN_METHOD(GridView::width)
@@ -301,7 +303,7 @@ NAN_METHOD(GridView::encodeSync)
             }
 
             resolution = bind_opt->IntegerValue();
-            
+
             if (resolution == 0)
             {
                 Nan::ThrowTypeError("'resolution' can not be zero");
diff --git a/src/mapnik_image.cpp b/src/mapnik_image.cpp
index f9eee0e..4aff65f 100644
--- a/src/mapnik_image.cpp
+++ b/src/mapnik_image.cpp
@@ -49,7 +49,7 @@ Nan::Persistent<v8::FunctionTemplate> Image::constructor;
 
 /**
  * **`mapnik.Image`**
- * 
+ *
  * Create a new image object (surface) that can be used for rendering data to.
  * @class Image
  * @param {number} width - width in pixels
@@ -109,7 +109,7 @@ void Image::Initialize(v8::Local<v8::Object> target) {
     Nan::SetPrototypeMethod(lcons, "resize", resize);
     Nan::SetPrototypeMethod(lcons, "resizeSync", resizeSync);
     Nan::SetPrototypeMethod(lcons, "data", data);
-    
+
     // properties
     ATTR(lcons, "scaling", get_scaling, set_scaling);
     ATTR(lcons, "offset", get_offset, set_offset);
@@ -265,7 +265,7 @@ NAN_METHOD(Image::New)
                 return;
             }
         }
-        
+
         try {
             Image* im = new Image(info[0]->IntegerValue(),
                                   info[1]->IntegerValue(),
@@ -360,7 +360,7 @@ struct visitor_get_pixel
         std::uint32_t val = mapnik::get_pixel<std::uint32_t>(data, x_, y_);
         return scope.Escape(Nan::New<v8::Uint32>(val));
     }
-    
+
     v8::Local<v8::Value> operator() (mapnik::image_gray32s const& data)
     {
         Nan::EscapableHandleScope scope;
@@ -406,7 +406,7 @@ struct visitor_get_pixel
   private:
     int x_;
     int y_;
-        
+
 };
 
 /**
@@ -535,11 +535,11 @@ NAN_METHOD(Image::setPixel)
     else if (info[2]->IsObject())
     {
         v8::Local<v8::Object> obj = info[2]->ToObject();
-        if (obj->IsNull() || obj->IsUndefined() || !Nan::New(Color::constructor)->HasInstance(obj)) 
+        if (obj->IsNull() || obj->IsUndefined() || !Nan::New(Color::constructor)->HasInstance(obj))
         {
             Nan::ThrowTypeError("A numeric or color value is expected as third arg");
         }
-        else 
+        else
         {
             Color * color = Nan::ObjectWrap::Unwrap<Color>(obj);
             mapnik::set_pixel(*im->this_,x,y,*(color->get()));
@@ -553,9 +553,9 @@ NAN_METHOD(Image::setPixel)
 }
 
 /**
- * Compare the pixels of one image to the pixels of another. Returns the number 
- * of pixels that are different. So, if the images are identical then it returns `0`. 
- * And if the images share no common pixels it returns the total number of pixels 
+ * Compare the pixels of one image to the pixels of another. Returns the number
+ * of pixels that are different. So, if the images are identical then it returns `0`.
+ * And if the images share no common pixels it returns the total number of pixels
  * in an image which is equivalent to `im.width()*im.height()`.
  *
  * @name compare
@@ -563,10 +563,10 @@ NAN_METHOD(Image::setPixel)
  * @memberof Image
  * @param {mapnik.Image} image - another {@link mapnik.Image} instance to compare to
  * @param {Object} [options]
- * @param {number} [options.threshold=16] - A value that should be `0` or greater to 
- * determine if the pixels match. Defaults to 16 which means that `rgba(0,0,0,0)` 
+ * @param {number} [options.threshold=16] - A value that should be `0` or greater to
+ * determine if the pixels match. Defaults to 16 which means that `rgba(0,0,0,0)`
  * would be considered the same as `rgba(15,15,15,0)`.
- * @param {boolean} [options.alpha=true] - `alpha` value, along with `rgb`, is considered 
+ * @param {boolean} [options.alpha=true] - `alpha` value, along with `rgb`, is considered
  * when comparing pixels
  * @returns {number} quantified visual difference between these two images in "number of
  * pixels" (i.e. `80` pixels are different);
@@ -574,20 +574,20 @@ NAN_METHOD(Image::setPixel)
  * // start with the exact same images
  * var img1 = new mapnik.Image(2,2);
  * var img2 = new mapnik.Image(2,2);
- * console.log(img1.compare(img2)); // 0 
- * 
+ * console.log(img1.compare(img2)); // 0
+ *
  * // change 1 pixel in img2
  * img2.setPixel(0,0, new mapnik.Color('green'));
- * console.log(img1.compare(img2)); // 1 
- * 
+ * console.log(img1.compare(img2)); // 1
+ *
  * // difference in color at first pixel
  * img1.setPixel(0,0, new mapnik.Color('red'));
- * console.log(img1.compare(img2)); // 1 
- * 
+ * console.log(img1.compare(img2)); // 1
+ *
  * // two pixels different
  * img2.setPixel(0,1, new mapnik.Color('red'));
- * console.log(img1.compare(img2)); // 2 
- * 
+ * console.log(img1.compare(img2)); // 2
+ *
  * // all pixels different
  * img2.setPixel(1,1, new mapnik.Color('blue'));
  * img2.setPixel(1,0, new mapnik.Color('blue'));
@@ -653,7 +653,7 @@ NAN_METHOD(Image::compare)
  * @name filterSync
  * @instance
  * @memberof Image
- * @param {string} filter - can be `blur`, `emboss`, `sharpen`, 
+ * @param {string} filter - can be `blur`, `emboss`, `sharpen`,
  * `sobel`, or `gray`.
  * @example
  * var img = new mapnik.Image(5, 5);
@@ -704,7 +704,7 @@ typedef struct {
  * @name filter
  * @instance
  * @memberof Image
- * @param {string} filter - can be `blur`, `emboss`, `sharpen`, 
+ * @param {string} filter - can be `blur`, `emboss`, `sharpen`,
  * `sobel`, or `gray`.
  * @param {Function} callback - `function(err, img)`
  * @example
@@ -726,7 +726,7 @@ NAN_METHOD(Image::filter)
         Nan::ThrowTypeError("last argument must be a callback function");
         return;
     }
-    
+
     Image* im = Nan::ObjectWrap::Unwrap<Image>(info.Holder());
     if (!info[0]->IsString())
     {
@@ -735,7 +735,7 @@ NAN_METHOD(Image::filter)
     }
     filter_image_baton_t *closure = new filter_image_baton_t();
     closure->filter = TOSTR(info[0]);
-    
+
     // ensure callback is a function
     v8::Local<v8::Value> callback = info[info.Length()-1];
     closure->request.data = closure;
@@ -828,11 +828,11 @@ v8::Local<v8::Value> Image::_fillSync(Nan::NAN_METHOD_ARGS_TYPE info) {
         else if (info[0]->IsObject())
         {
             v8::Local<v8::Object> obj = info[0]->ToObject();
-            if (obj->IsNull() || obj->IsUndefined() || !Nan::New(Color::constructor)->HasInstance(obj)) 
+            if (obj->IsNull() || obj->IsUndefined() || !Nan::New(Color::constructor)->HasInstance(obj))
             {
                 Nan::ThrowTypeError("A numeric or color value is expected");
             }
-            else 
+            else
             {
                 Color * color = Nan::ObjectWrap::Unwrap<Color>(obj);
                 mapnik::fill(*im->this_,*(color->get()));
@@ -886,9 +886,9 @@ typedef struct {
  *   if (err) throw err;
  *   var colors = img.getPixel(0,0, {get_color: true});
  *   pixel is colored blue
- *   console.log(color.b); // 255   
+ *   console.log(color.b); // 255
  * });
- * 
+ *
  * // or fill with rgb string
  * img.fill('rgba(255,255,255,0)', function(err, img) { ... });
  */
@@ -898,7 +898,7 @@ NAN_METHOD(Image::fill)
         info.GetReturnValue().Set(_fillSync(info));
         return;
     }
-    
+
     Image* im = Nan::ObjectWrap::Unwrap<Image>(info.Holder());
     fill_image_baton_t *closure = new fill_image_baton_t();
     if (info[0]->IsUint32())
@@ -919,13 +919,13 @@ NAN_METHOD(Image::fill)
     else if (info[0]->IsObject())
     {
         v8::Local<v8::Object> obj = info[0]->ToObject();
-        if (obj->IsNull() || obj->IsUndefined() || !Nan::New(Color::constructor)->HasInstance(obj)) 
+        if (obj->IsNull() || obj->IsUndefined() || !Nan::New(Color::constructor)->HasInstance(obj))
         {
             delete closure;
             Nan::ThrowTypeError("A numeric or color value is expected");
             return;
         }
-        else 
+        else
         {
             Color * color = Nan::ObjectWrap::Unwrap<Color>(obj);
             closure->c = *(color->get());
@@ -1219,7 +1219,7 @@ v8::Local<v8::Value> Image::_premultiplySync(Nan::NAN_METHOD_ARGS_TYPE info) {
  * @example
  * var img = new mapnik.Image(5,5);
  * img.premultiply(function(err, img) {
- *   if (err) throw err;   
+ *   if (err) throw err;
  *   // your custom code with premultiplied img
  * })
  */
@@ -1342,7 +1342,7 @@ typedef struct {
  * @example
  * var img = new mapnik.Image(2,2);
  * console.log(img.isSolid()); // true
- * 
+ *
  * // change a pixel
  * img.setPixel(0,0, new mapnik.Color('green'));
  * console.log(img.isSolid()); // false
@@ -1450,7 +1450,7 @@ typedef struct {
     uv_work_t request;
     Image* im1;
     image_ptr im2;
-    mapnik::image_dtype type;  
+    mapnik::image_dtype type;
     double offset;
     double scaling;
     Nan::Persistent<v8::Function> cb;
@@ -1483,14 +1483,14 @@ NAN_METHOD(Image::copy)
         info.GetReturnValue().Set(_copySync(info));
         return;
     }
-    
+
     Image* im1 = Nan::ObjectWrap::Unwrap<Image>(info.Holder());
     double offset = 0.0;
     bool scaling_or_offset_set = false;
     double scaling = 1.0;
     mapnik::image_dtype type = im1->this_->get_dtype();
     v8::Local<v8::Object> options = Nan::New<v8::Object>();
-    
+
     if (info.Length() >= 2)
     {
         if (info[0]->IsNumber())
@@ -1524,7 +1524,7 @@ NAN_METHOD(Image::copy)
             return;
         }
     }
-    
+
     if (options->Has(Nan::New("scaling").ToLocalChecked()))
     {
         v8::Local<v8::Value> scaling_val = options->Get(Nan::New("scaling").ToLocalChecked());
@@ -1539,7 +1539,7 @@ NAN_METHOD(Image::copy)
             return;
         }
     }
-    
+
     if (options->Has(Nan::New("offset").ToLocalChecked()))
     {
         v8::Local<v8::Value> offset_val = options->Get(Nan::New("offset").ToLocalChecked());
@@ -1560,7 +1560,7 @@ NAN_METHOD(Image::copy)
         scaling = im1->this_->get_scaling();
         offset = im1->this_->get_offset();
     }
-    
+
     copy_image_baton_t *closure = new copy_image_baton_t();
     closure->request.data = closure;
     closure->im1 = im1;
@@ -1615,8 +1615,9 @@ void Image::EIO_AfterCopy(uv_work_t* req)
     {
         Image* im = new Image(closure->im2);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(im);
-        v8::Local<v8::Object> image_obj = Nan::New(constructor)->GetFunction()->NewInstance(1, &ext);
-        v8::Local<v8::Value> argv[2] = { Nan::Null(), image_obj };
+        Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+        v8::Local<v8::Value> argv[2] = { Nan::Null(), maybe_local.ToLocalChecked() };
         Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(closure->cb), 2, argv);
     }
     closure->im1->Unref();
@@ -1686,7 +1687,7 @@ v8::Local<v8::Value> Image::_copySync(Nan::NAN_METHOD_ARGS_TYPE info)
             return scope.Escape(Nan::Undefined());
         }
     }
-    
+
     if (options->Has(Nan::New("scaling").ToLocalChecked()))
     {
         v8::Local<v8::Value> scaling_val = options->Get(Nan::New("scaling").ToLocalChecked());
@@ -1701,7 +1702,7 @@ v8::Local<v8::Value> Image::_copySync(Nan::NAN_METHOD_ARGS_TYPE info)
             return scope.Escape(Nan::Undefined());
         }
     }
-    
+
     if (options->Has(Nan::New("offset").ToLocalChecked()))
     {
         v8::Local<v8::Value> offset_val = options->Get(Nan::New("offset").ToLocalChecked());
@@ -1733,7 +1734,9 @@ v8::Local<v8::Value> Image::_copySync(Nan::NAN_METHOD_ARGS_TYPE info)
                                                     );
         Image* new_im = new Image(imagep);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(new_im);
-        return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+        Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+        return scope.Escape(maybe_local.ToLocalChecked());
     }
     catch (std::exception const& ex)
     {
@@ -1779,7 +1782,7 @@ typedef struct {
  * });
  */
 NAN_METHOD(Image::resize)
-{    
+{
     // ensure callback is a function
     v8::Local<v8::Value> callback = info[info.Length() - 1];
     if (!info[info.Length()-1]->IsFunction()) {
@@ -1794,7 +1797,7 @@ NAN_METHOD(Image::resize)
     double filter_factor = 1.0;
     mapnik::scaling_method_e scaling_method = mapnik::SCALING_NEAR;
     v8::Local<v8::Object> options = Nan::New<v8::Object>();
-    
+
     if (info.Length() >= 3)
     {
         if (info[0]->IsNumber())
@@ -1845,7 +1848,7 @@ NAN_METHOD(Image::resize)
             return;
         }
     }
-    if (options->Has(Nan::New("offset_x").ToLocalChecked())) 
+    if (options->Has(Nan::New("offset_x").ToLocalChecked()))
     {
         v8::Local<v8::Value> bind_opt = options->Get(Nan::New("offset_x").ToLocalChecked());
         if (!bind_opt->IsNumber())
@@ -1855,7 +1858,7 @@ NAN_METHOD(Image::resize)
         }
         offset_x = bind_opt->IntegerValue();
     }
-    if (options->Has(Nan::New("offset_y").ToLocalChecked())) 
+    if (options->Has(Nan::New("offset_y").ToLocalChecked()))
     {
         v8::Local<v8::Value> bind_opt = options->Get(Nan::New("offset_y").ToLocalChecked());
         if (!bind_opt->IsNumber())
@@ -1884,7 +1887,7 @@ NAN_METHOD(Image::resize)
             return;
         }
     }
-    
+
     if (options->Has(Nan::New("filter_factor").ToLocalChecked()))
     {
         v8::Local<v8::Value> ff_val = options->Get(Nan::New("filter_factor").ToLocalChecked());
@@ -1917,7 +1920,7 @@ NAN_METHOD(Image::resize)
 struct resize_visitor
 {
 
-    resize_visitor(mapnik::image_any const& im1, 
+    resize_visitor(mapnik::image_any const& im1,
                    mapnik::scaling_method_e scaling_method,
                    double image_ratio_x,
                    double image_ratio_y,
@@ -1938,7 +1941,7 @@ struct resize_visitor
         {
             throw std::runtime_error("RGBA8 images must be premultiplied prior to using resize");
         }
-        mapnik::scale_image_agg(im2, 
+        mapnik::scale_image_agg(im2,
                                 mapnik::util::get<mapnik::image_rgba8>(im1_),
                                 scaling_method_,
                                 image_ratio_x_,
@@ -1951,7 +1954,7 @@ struct resize_visitor
     template <typename T>
     void operator()(T & im2) const
     {
-        mapnik::scale_image_agg(im2, 
+        mapnik::scale_image_agg(im2,
                                 mapnik::util::get<T>(im1_),
                                 scaling_method_,
                                 image_ratio_x_,
@@ -1960,7 +1963,7 @@ struct resize_visitor
                                 offset_y_,
                                 filter_factor_);
     }
-    
+
     void operator()(mapnik::image_null &) const
     {
         // Should be caught earlier so no test coverage should reach here.
@@ -1968,7 +1971,7 @@ struct resize_visitor
         throw std::runtime_error("Can not resize null images");
         /* LCOV_EXCL_STOP */
     }
-    
+
     void operator()(mapnik::image_gray8s &) const
     {
         throw std::runtime_error("Mapnik currently does not support resizing signed 8 bit integer rasters");
@@ -1978,27 +1981,27 @@ struct resize_visitor
     {
         throw std::runtime_error("Mapnik currently does not support resizing signed 16 bit integer rasters");
     }
-    
+
     void operator()(mapnik::image_gray32 &) const
     {
         throw std::runtime_error("Mapnik currently does not support resizing unsigned 32 bit integer rasters");
     }
-    
+
     void operator()(mapnik::image_gray32s &) const
     {
         throw std::runtime_error("Mapnik currently does not support resizing signed 32 bit integer rasters");
     }
-    
+
     void operator()(mapnik::image_gray64 &) const
     {
         throw std::runtime_error("Mapnik currently does not support resizing unsigned 64 bit integer rasters");
     }
-    
+
     void operator()(mapnik::image_gray64s &) const
     {
         throw std::runtime_error("Mapnik currently does not support resizing signed 64 bit integer rasters");
     }
-    
+
     void operator()(mapnik::image_gray64f &) const
     {
         throw std::runtime_error("Mapnik currently does not support resizing 64 bit floating point rasters");
@@ -2030,8 +2033,8 @@ void Image::EIO_Resize(uv_work_t* req)
         double offset = closure->im1->this_->get_offset();
         double scaling = closure->im1->this_->get_scaling();
 
-        closure->im2 = std::make_shared<mapnik::image_any>(closure->size_x, 
-                                                           closure->size_y, 
+        closure->im2 = std::make_shared<mapnik::image_any>(closure->size_x,
+                                                           closure->size_y,
                                                            closure->im1->this_->get_dtype(),
                                                            true,
                                                            true,
@@ -2046,7 +2049,7 @@ void Image::EIO_Resize(uv_work_t* req)
             closure->error_name = "Image width or height is zero or less then zero.";
             return;
         }
-        double image_ratio_x = static_cast<double>(closure->size_x) / im_width; 
+        double image_ratio_x = static_cast<double>(closure->size_x) / im_width;
         double image_ratio_y = static_cast<double>(closure->size_y) / im_height;
         resize_visitor visit(*(closure->im1->this_),
                              closure->scaling_method,
@@ -2077,8 +2080,9 @@ void Image::EIO_AfterResize(uv_work_t* req)
     {
         Image* im = new Image(closure->im2);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(im);
-        v8::Local<v8::Object> image_obj = Nan::New(constructor)->GetFunction()->NewInstance(1, &ext);
-        v8::Local<v8::Value> argv[2] = { Nan::Null(), image_obj };
+        Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+        v8::Local<v8::Value> argv[2] = { Nan::Null(), maybe_local.ToLocalChecked() };
         Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(closure->cb), 2, argv);
     }
     closure->im1->Unref();
@@ -2158,7 +2162,7 @@ v8::Local<v8::Value> Image::_resizeSync(Nan::NAN_METHOD_ARGS_TYPE info)
     {
         Nan::ThrowTypeError("Resize requires at least a width and height parameter");
         return scope.Escape(Nan::Undefined());
-    }    
+    }
     if (info.Length() >= 3)
     {
         if (info[2]->IsObject())
@@ -2171,7 +2175,7 @@ v8::Local<v8::Value> Image::_resizeSync(Nan::NAN_METHOD_ARGS_TYPE info)
             return scope.Escape(Nan::Undefined());
         }
     }
-    if (options->Has(Nan::New("offset_x").ToLocalChecked())) 
+    if (options->Has(Nan::New("offset_x").ToLocalChecked()))
     {
         v8::Local<v8::Value> bind_opt = options->Get(Nan::New("offset_x").ToLocalChecked());
         if (!bind_opt->IsNumber())
@@ -2181,7 +2185,7 @@ v8::Local<v8::Value> Image::_resizeSync(Nan::NAN_METHOD_ARGS_TYPE info)
         }
         offset_x = bind_opt->IntegerValue();
     }
-    if (options->Has(Nan::New("offset_y").ToLocalChecked())) 
+    if (options->Has(Nan::New("offset_y").ToLocalChecked()))
     {
         v8::Local<v8::Value> bind_opt = options->Get(Nan::New("offset_y").ToLocalChecked());
         if (!bind_opt->IsNumber())
@@ -2191,7 +2195,7 @@ v8::Local<v8::Value> Image::_resizeSync(Nan::NAN_METHOD_ARGS_TYPE info)
         }
         offset_y = bind_opt->IntegerValue();
     }
-    
+
     if (options->Has(Nan::New("scaling_method").ToLocalChecked()))
     {
         v8::Local<v8::Value> scaling_val = options->Get(Nan::New("scaling_method").ToLocalChecked());
@@ -2211,7 +2215,7 @@ v8::Local<v8::Value> Image::_resizeSync(Nan::NAN_METHOD_ARGS_TYPE info)
             return scope.Escape(Nan::Undefined());
         }
     }
-    
+
     if (options->Has(Nan::New("filter_factor").ToLocalChecked()))
     {
         v8::Local<v8::Value> ff_val = options->Get(Nan::New("filter_factor").ToLocalChecked());
@@ -2243,16 +2247,16 @@ v8::Local<v8::Value> Image::_resizeSync(Nan::NAN_METHOD_ARGS_TYPE info)
         double offset = im->this_->get_offset();
         double scaling = im->this_->get_scaling();
 
-        image_ptr imagep = std::make_shared<mapnik::image_any>(width, 
-                                                           height, 
+        image_ptr imagep = std::make_shared<mapnik::image_any>(width,
+                                                           height,
                                                            im->this_->get_dtype(),
                                                            true,
                                                            true,
                                                            false);
         imagep->set_offset(offset);
         imagep->set_scaling(scaling);
-        double image_ratio_x = static_cast<double>(width) / im_width; 
-        double image_ratio_y = static_cast<double>(height) / im_height; 
+        double image_ratio_x = static_cast<double>(width) / im_width;
+        double image_ratio_y = static_cast<double>(height) / im_height;
         resize_visitor visit(*(im->this_),
                              scaling_method,
                              image_ratio_x,
@@ -2263,7 +2267,9 @@ v8::Local<v8::Value> Image::_resizeSync(Nan::NAN_METHOD_ARGS_TYPE info)
         mapnik::util::apply_visitor(visit, *imagep);
         Image* new_im = new Image(imagep);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(new_im);
-        return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+        Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+        return scope.Escape(maybe_local.ToLocalChecked());
     }
     catch (std::exception const& ex)
     {
@@ -2372,7 +2378,9 @@ v8::Local<v8::Value> Image::_openSync(Nan::NAN_METHOD_ARGS_TYPE info)
                 }
                 Image* im = new Image(imagep);
                 v8::Local<v8::Value> ext = Nan::New<v8::External>(im);
-                return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+                Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+                if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+                return scope.Escape(maybe_local.ToLocalChecked());
             }
         }
         Nan::ThrowTypeError(("Unsupported image format:" + filename).c_str());
@@ -2413,11 +2421,11 @@ typedef struct {
  * @memberof Image
  * @static
  * @param {string} path - path to the image you want to load
- * @param {Function} callback - 
+ * @param {Function} callback -
  * @example
  * mapnik.Image.open('./path/to/image.jpg', function(err, img) {
  *   if (err) throw err;
- *   // img is now an Image object   
+ *   // img is now an Image object
  * });
  */
 NAN_METHOD(Image::open)
@@ -2508,8 +2516,9 @@ void Image::EIO_AfterOpen(uv_work_t* req)
     {
         Image* im = new Image(closure->im);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(im);
-        v8::Local<v8::Object> image_obj = Nan::New(constructor)->GetFunction()->NewInstance(1, &ext);
-        v8::Local<v8::Value> argv[2] = { Nan::Null(), image_obj };
+        Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+        v8::Local<v8::Value> argv[2] = { Nan::Null(), maybe_local.ToLocalChecked() };
         Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(closure->cb), 2, argv);
     }
     closure->cb.Reset();
@@ -2564,13 +2573,13 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
 {
     Nan::EscapableHandleScope scope;
 
-    if (!fromFile && (info.Length() < 1 || !info[0]->IsObject())) 
+    if (!fromFile && (info.Length() < 1 || !info[0]->IsObject()))
     {
         Nan::ThrowTypeError("must provide a buffer argument");
         return scope.Escape(Nan::Undefined());
     }
 
-    if (fromFile && (info.Length() < 1 || !info[0]->IsString())) 
+    if (fromFile && (info.Length() < 1 || !info[0]->IsString()))
     {
         Nan::ThrowTypeError("must provide a filename argument");
         return scope.Escape(Nan::Undefined());
@@ -2579,9 +2588,10 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
 
     double scale = 1.0;
     std::uint32_t max_size = 2048;
-    if (info.Length() >= 2) 
+    bool strict = false;
+    if (info.Length() >= 2)
     {
-        if (!info[1]->IsObject()) 
+        if (!info[1]->IsObject())
         {
             Nan::ThrowTypeError("optional second arg must be an options object");
             return scope.Escape(Nan::Undefined());
@@ -2590,7 +2600,7 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
         if (options->Has(Nan::New("scale").ToLocalChecked()))
         {
             v8::Local<v8::Value> scale_opt = options->Get(Nan::New("scale").ToLocalChecked());
-            if (!scale_opt->IsNumber()) 
+            if (!scale_opt->IsNumber())
             {
                 Nan::ThrowTypeError("'scale' must be a number");
                 return scope.Escape(Nan::Undefined());
@@ -2607,16 +2617,26 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
             v8::Local<v8::Value> opt = options->Get(Nan::New("max_size").ToLocalChecked());
             if (!opt->IsNumber())
             {
-                Nan::ThrowTypeError("max_size must be a positive integer");
+                Nan::ThrowTypeError("'max_size' must be a positive integer");
                 return scope.Escape(Nan::Undefined());
             }
             auto max_size_val = opt->IntegerValue();
             if (max_size_val < 0 || max_size_val > 65535) {
-                Nan::ThrowTypeError("max_size must be a positive integer between 0 and 65535");
+                Nan::ThrowTypeError("'max_size' must be a positive integer between 0 and 65535");
                 return scope.Escape(Nan::Undefined());
             }
             max_size = static_cast<std::uint32_t>(max_size_val);
         }
+        if (options->Has(Nan::New("strict").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> opt = options->Get(Nan::New("strict").ToLocalChecked());
+            if (!opt->IsBoolean())
+            {
+                Nan::ThrowTypeError("'strict' must be a boolean value");
+                return scope.Escape(Nan::Undefined());
+            }
+            strict = opt->BooleanValue();
+        }
     }
 
     try
@@ -2626,15 +2646,15 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
         vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
         svg_path_adapter svg_path(stl_storage);
         svg_converter_type svg(svg_path, marker_path->attributes());
-        svg_parser p(svg);
+        svg_parser p(svg, strict);
         if (fromFile)
         {
-            if (!p.parse(TOSTR(info[0])))
+            p.parse(TOSTR(info[0]));
+            if (!p.err_handler().error_messages().empty())
             {
-                std::ostringstream errorMessage("");
+                std::ostringstream errorMessage;
                 errorMessage << "SVG parse error:" << std::endl;
-                auto const& errors = p.error_messages();
-                for (auto error : errors) {
+                for (auto const& error : p.err_handler().error_messages()) {
                     errorMessage <<  error << std::endl;
                 }
                 Nan::ThrowTypeError(errorMessage.str().c_str());
@@ -2644,18 +2664,18 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
         else
         {
             v8::Local<v8::Object> obj = info[0]->ToObject();
-            if (obj->IsNull() || obj->IsUndefined() || !node::Buffer::HasInstance(obj)) 
+            if (obj->IsNull() || obj->IsUndefined() || !node::Buffer::HasInstance(obj))
             {
                 Nan::ThrowTypeError("first argument is invalid, must be a Buffer");
                 return scope.Escape(Nan::Undefined());
             }
             std::string svg_buffer(node::Buffer::Data(obj),node::Buffer::Length(obj));
-            if (!p.parse_from_string(svg_buffer))
+            p.parse_from_string(svg_buffer);
+            if (!p.err_handler().error_messages().empty())
             {
-                std::ostringstream errorMessage("");
+                std::ostringstream errorMessage;
                 errorMessage << "SVG parse error:" << std::endl;
-                auto const& errors = p.error_messages();
-                for (auto error : errors) {
+                for (auto const& error : p.err_handler().error_messages()) {
                     errorMessage <<  error << std::endl;
                 }
                 Nan::ThrowTypeError(errorMessage.str().c_str());
@@ -2677,7 +2697,7 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
         double opacity = 1;
         double svg_width = svg.width() * scale;
         double svg_height = svg.height() * scale;
-        
+
         if (svg_width <= 0 || svg_height <= 0)
         {
             Nan::ThrowTypeError("image created from svg must have a width and height greater then zero");
@@ -2718,7 +2738,9 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
         image_ptr imagep = std::make_shared<mapnik::image_any>(im);
         Image *im2 = new Image(imagep);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(im2);
-        return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+        Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+        return scope.Escape(maybe_local.ToLocalChecked());
     }
     catch (std::exception const& ex)
     {
@@ -2739,6 +2761,7 @@ typedef struct {
     bool error;
     double scale;
     std::uint32_t max_size;
+    bool strict;
     std::string error_name;
     Nan::Persistent<v8::Function> cb;
 } svg_file_ptr_baton_t;
@@ -2751,6 +2774,7 @@ typedef struct {
     bool error;
     double scale;
     std::uint32_t max_size;
+    bool strict;
     std::string error_name;
     Nan::Persistent<v8::Object> buffer;
     Nan::Persistent<v8::Function> cb;
@@ -2773,7 +2797,7 @@ typedef struct {
  * @example
  * mapnik.Image.fromSVG('./path/to/image.svg', {scale: 0.5}, function(err, img) {
  *   if (err) throw err;
- *   // new img object (at 50% scale)  
+ *   // new img object (at 50% scale)
  * });
  */
 NAN_METHOD(Image::fromSVG)
@@ -2783,7 +2807,7 @@ NAN_METHOD(Image::fromSVG)
         return;
     }
 
-    if (info.Length() < 2 || !info[0]->IsString()) 
+    if (info.Length() < 2 || !info[0]->IsString())
     {
         Nan::ThrowTypeError("must provide a filename argument");
         return;
@@ -2798,9 +2822,10 @@ NAN_METHOD(Image::fromSVG)
 
     double scale = 1.0;
     std::uint32_t max_size = 2048;
-    if (info.Length() >= 3) 
+    bool strict = false;
+    if (info.Length() >= 3)
     {
-        if (!info[1]->IsObject()) 
+        if (!info[1]->IsObject())
         {
             Nan::ThrowTypeError("optional second arg must be an options object");
             return;
@@ -2809,7 +2834,7 @@ NAN_METHOD(Image::fromSVG)
         if (options->Has(Nan::New("scale").ToLocalChecked()))
         {
             v8::Local<v8::Value> scale_opt = options->Get(Nan::New("scale").ToLocalChecked());
-            if (!scale_opt->IsNumber()) 
+            if (!scale_opt->IsNumber())
             {
                 Nan::ThrowTypeError("'scale' must be a number");
                 return;
@@ -2826,16 +2851,26 @@ NAN_METHOD(Image::fromSVG)
             v8::Local<v8::Value> opt = options->Get(Nan::New("max_size").ToLocalChecked());
             if (!opt->IsNumber())
             {
-                Nan::ThrowTypeError("max_size must be a positive integer");
+                Nan::ThrowTypeError("'max_size' must be a positive integer");
                 return;
             }
             auto max_size_val = opt->IntegerValue();
             if (max_size_val < 0 || max_size_val > 65535) {
-                Nan::ThrowTypeError("max_size must be a positive integer between 0 and 65535");
+                Nan::ThrowTypeError("'max_size' must be a positive integer between 0 and 65535");
                 return;
             }
             max_size = static_cast<std::uint32_t>(max_size_val);
         }
+        if (options->Has(Nan::New("strict").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> opt = options->Get(Nan::New("strict").ToLocalChecked());
+            if (!opt->IsBoolean())
+            {
+                Nan::ThrowTypeError("'strict' must be a boolean value");
+                return;
+            }
+            strict = opt->BooleanValue();
+        }
     }
 
     svg_file_ptr_baton_t *closure = new svg_file_ptr_baton_t();
@@ -2844,6 +2879,7 @@ NAN_METHOD(Image::fromSVG)
     closure->error = false;
     closure->scale = scale;
     closure->max_size = max_size;
+    closure->strict = strict;
     closure->cb.Reset(callback.As<v8::Function>());
     uv_queue_work(uv_default_loop(), &closure->request, EIO_FromSVG, (uv_after_work_cb)EIO_AfterFromSVG);
     return;
@@ -2860,13 +2896,13 @@ void Image::EIO_FromSVG(uv_work_t* req)
         vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
         svg_path_adapter svg_path(stl_storage);
         svg_converter_type svg(svg_path, marker_path->attributes());
-        svg_parser p(svg);
-        if (!p.parse(closure->filename))
+        svg_parser p(svg, closure->strict);
+        p.parse(closure->filename);
+        if (!p.err_handler().error_messages().empty())
         {
-            std::ostringstream errorMessage("");
+            std::ostringstream errorMessage;
             errorMessage << "SVG parse error:" << std::endl;
-            auto const& errors = p.error_messages();
-            for (auto error : errors) {
+            for (auto const& error : p.err_handler().error_messages()) {
                 errorMessage <<  error << std::endl;
             }
             closure->error = true;
@@ -2937,7 +2973,7 @@ void Image::EIO_FromSVG(uv_work_t* req)
         // it is a good idea to keep this. Therefore, any exceptions thrown will fail gracefully.
         // LCOV_EXCL_START
         closure->error = true;
-        closure->error_name = "Failed to load: " + closure->filename;
+        closure->error_name = ex.what();
         // LCOV_EXCL_STOP
     }
 }
@@ -2955,8 +2991,9 @@ void Image::EIO_AfterFromSVG(uv_work_t* req)
     {
         Image* im = new Image(closure->im);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(im);
-        v8::Local<v8::Object> image_obj = Nan::New(constructor)->GetFunction()->NewInstance(1, &ext);
-        v8::Local<v8::Value> argv[2] = { Nan::Null(), image_obj };
+        Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+        v8::Local<v8::Value> argv[2] = { Nan::Null(), maybe_local.ToLocalChecked() };
         Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(closure->cb), 2, argv);
     }
     closure->cb.Reset();
@@ -2973,12 +3010,13 @@ void Image::EIO_AfterFromSVG(uv_work_t* req)
  * @param {number} [options.scale] - scale the image. For example passing `0.5` as scale would render
  * your SVG at 50% the original size.
  * @param {number} [options.max_size] - the maximum allowed size of the svg dimensions * scale. The default is 2048.
+ * @param {boolean} [options.strict] - enable `strict` parsing mode e.g throw on unsupported element/attribute. The default is `false`.
  * This option can be passed a smaller or larger size in order to control the final size of the image allocated for
  * rasterizing the SVG.
  * @param {Function} callback = `function(err, img)`
  * @example
  * var buffer = fs.readFileSync('./path/to/image.svg');
- * mapnik.Image.fromSVGBytesSync(buffer, function(err, img) {
+ * mapnik.Image.fromSVGBytes(buffer, function(err, img) {
  *   if (err) throw err;
  *   // your custom code with `img`
  * });
@@ -3010,9 +3048,10 @@ NAN_METHOD(Image::fromSVGBytes)
 
     double scale = 1.0;
     std::uint32_t max_size = 2048;
-    if (info.Length() >= 3) 
+    bool strict = true;
+    if (info.Length() >= 3)
     {
-        if (!info[1]->IsObject()) 
+        if (!info[1]->IsObject())
         {
             Nan::ThrowTypeError("optional second arg must be an options object");
             return;
@@ -3021,7 +3060,7 @@ NAN_METHOD(Image::fromSVGBytes)
         if (options->Has(Nan::New("scale").ToLocalChecked()))
         {
             v8::Local<v8::Value> scale_opt = options->Get(Nan::New("scale").ToLocalChecked());
-            if (!scale_opt->IsNumber()) 
+            if (!scale_opt->IsNumber())
             {
                 Nan::ThrowTypeError("'scale' must be a number");
                 return;
@@ -3038,16 +3077,26 @@ NAN_METHOD(Image::fromSVGBytes)
             v8::Local<v8::Value> opt = options->Get(Nan::New("max_size").ToLocalChecked());
             if (!opt->IsNumber())
             {
-                Nan::ThrowTypeError("max_size must be a positive integer");
+                Nan::ThrowTypeError("'max_size' must be a positive integer");
                 return;
             }
             auto max_size_val = opt->IntegerValue();
             if (max_size_val < 0 || max_size_val > 65535) {
-                Nan::ThrowTypeError("max_size must be a positive integer between 0 and 65535");
+                Nan::ThrowTypeError("'max_size' must be a positive integer between 0 and 65535");
                 return;
             }
             max_size = static_cast<std::uint32_t>(max_size_val);
         }
+        if (options->Has(Nan::New("strict").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> opt = options->Get(Nan::New("strict").ToLocalChecked());
+            if (!opt->IsBoolean())
+            {
+                Nan::ThrowTypeError("'strict' must be a boolean value");
+                return;
+            }
+            strict = opt->BooleanValue();
+        }
     }
 
     svg_mem_ptr_baton_t *closure = new svg_mem_ptr_baton_t();
@@ -3058,6 +3107,7 @@ NAN_METHOD(Image::fromSVGBytes)
     closure->data = node::Buffer::Data(obj);
     closure->scale = scale;
     closure->max_size = max_size;
+    closure->strict = strict;
     closure->dataLength = node::Buffer::Length(obj);
     uv_queue_work(uv_default_loop(), &closure->request, EIO_FromSVGBytes, (uv_after_work_cb)EIO_AfterFromSVGBytes);
     return;
@@ -3074,15 +3124,15 @@ void Image::EIO_FromSVGBytes(uv_work_t* req)
         vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
         svg_path_adapter svg_path(stl_storage);
         svg_converter_type svg(svg_path, marker_path->attributes());
-        svg_parser p(svg);
+        svg_parser p(svg, closure->strict);
 
         std::string svg_buffer(closure->data,closure->dataLength);
-        if (!p.parse_from_string(svg_buffer))
+        p.parse_from_string(svg_buffer);
+        if (!p.err_handler().error_messages().empty())
         {
-            std::ostringstream errorMessage("");
+            std::ostringstream errorMessage;
             errorMessage << "SVG parse error:" << std::endl;
-            auto const& errors = p.error_messages();
-            for (auto error : errors) {
+            for (auto const& error : p.err_handler().error_messages()) {
                 errorMessage <<  error << std::endl;
             }
             closure->error = true;
@@ -3180,9 +3230,9 @@ void Image::EIO_AfterFromSVGBytes(uv_work_t* req)
 }
 
 /**
- * Create an image of the existing buffer. 
- * 
- * Note: the buffer must live as long as the image. 
+ * Create an image of the existing buffer.
+ *
+ * Note: the buffer must live as long as the image.
  * It is recommended that you do not use this method. Be warned!
  *
  * @name fromBufferSync
@@ -3214,7 +3264,7 @@ v8::Local<v8::Value> Image::_fromBufferSync(Nan::NAN_METHOD_ARGS_TYPE info)
     unsigned width = info[0]->IntegerValue();
     unsigned height = info[1]->IntegerValue();
 
-    if (width <= 0 || height <= 0) 
+    if (width <= 0 || height <= 0)
     {
         Nan::ThrowTypeError("width and height must be greater then zero");
         return scope.Escape(Nan::Undefined());
@@ -3288,10 +3338,11 @@ v8::Local<v8::Value> Image::_fromBufferSync(Nan::NAN_METHOD_ARGS_TYPE info)
         image_ptr imagep = std::make_shared<mapnik::image_any>(im_wrapper);
         Image* im = new Image(imagep);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(im);
-        v8::Local<v8::Value> image_instance = Nan::New(constructor)->GetFunction()->NewInstance(1, &ext);
-        v8::Local<v8::Object> image_obj = image_instance->ToObject();
+        Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+        v8::Local<v8::Object> image_obj = maybe_local.ToLocalChecked()->ToObject();
         image_obj->Set(Nan::New("_buffer").ToLocalChecked(),obj);
-        return scope.Escape(image_instance);
+        return scope.Escape(maybe_local.ToLocalChecked());
     }
     catch (std::exception const& ex)
     {
@@ -3343,7 +3394,9 @@ v8::Local<v8::Value> Image::_fromBytesSync(Nan::NAN_METHOD_ARGS_TYPE info)
             image_ptr imagep = std::make_shared<mapnik::image_any>(reader->read(0,0,reader->width(),reader->height()));
             Image* im = new Image(imagep);
             v8::Local<v8::Value> ext = Nan::New<v8::External>(im);
-            return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+            Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+            if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+            return scope.Escape(maybe_local.ToLocalChecked());
         }
         // The only way this is ever reached is if the reader factory in
         // mapnik was not providing an image type it should. This should never
@@ -3361,7 +3414,7 @@ v8::Local<v8::Value> Image::_fromBytesSync(Nan::NAN_METHOD_ARGS_TYPE info)
 }
 
 /**
- * Create an image from a byte stream buffer. 
+ * Create an image from a byte stream buffer.
  *
  * @name fromBytes
  * @param {Buffer} buffer - image buffer
@@ -3373,9 +3426,9 @@ v8::Local<v8::Value> Image::_fromBytesSync(Nan::NAN_METHOD_ARGS_TYPE info)
  * @memberof Image
  * @example
  * var buffer = fs.readFileSync('./path/to/image.png');
- * mapnik.Image.fromBytesSync(buffer, function(err, img) {
+ * mapnik.Image.fromBytes(buffer, function(err, img) {
  *   if (err) throw err;
- *   // your custom code with `img` object   
+ *   // your custom code with `img` object
  * });
  */
 NAN_METHOD(Image::fromBytes)
@@ -3502,7 +3555,7 @@ void Image::EIO_AfterFromBytes(uv_work_t* req)
     else if (closure->im == nullptr)
     {
         /* LCOV_EXCL_START */
-        // The only way this is ever reached is if the reader factory in 
+        // The only way this is ever reached is if the reader factory in
         // mapnik was not providing an image type it should. This should never
         // be occuring so marking this out from coverage
         v8::Local<v8::Value> argv[1] = { Nan::Error("Failed to load from buffer") };
@@ -3512,8 +3565,9 @@ void Image::EIO_AfterFromBytes(uv_work_t* req)
     {
         Image* im = new Image(closure->im);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(im);
-        v8::Local<v8::Object> image_obj = Nan::New(constructor)->GetFunction()->NewInstance(1, &ext);
-        v8::Local<v8::Value> argv[2] = { Nan::Null(), image_obj };
+        Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+        v8::Local<v8::Value> argv[2] = { Nan::Null(), maybe_local.ToLocalChecked() };
         Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(closure->cb), 2, argv);
     }
     closure->cb.Reset();
@@ -3622,17 +3676,17 @@ typedef struct {
  * @example
  * var img = new mapnik.Image.open('./path/to/image.png');
  * myImage.encode('png', function(err, encoded) {
- *   if (err) throw err;   
+ *   if (err) throw err;
  *   // write buffer to new file
  *   fs.writeFileSync('myimage.png', encoded);
  * });
- * 
+ *
  * // encoding an image object with a mapnik.Palette
  * var im = new mapnik.Image(256, 256);
  * var pal = new mapnik.Palette(new Buffer('\xff\x09\x93\xFF\x01\x02\x03\x04','ascii'));
  * im.encode('png', {palette: pal}, function(err, encode) {
  *   if (err) throw err;
- *   // your custom code with `encode` image buffer  
+ *   // your custom code with `encode` image buffer
  * });
  */
 NAN_METHOD(Image::encode)
@@ -3794,12 +3848,12 @@ NAN_METHOD(Image::saveSync)
 v8::Local<v8::Value> Image::_saveSync(Nan::NAN_METHOD_ARGS_TYPE info) {
     Nan::EscapableHandleScope scope;
     Image* im = Nan::ObjectWrap::Unwrap<Image>(info.Holder());
-    
+
     if (info.Length() == 0 || !info[0]->IsString()){
         Nan::ThrowTypeError("filename required to save file");
         return scope.Escape(Nan::Undefined());
     }
-    
+
     std::string filename = TOSTR(info[0]);
     std::string format("");
 
@@ -3854,13 +3908,13 @@ typedef struct {
  * @example
  * img.save('image.png', 'png', function(err) {
  *   if (err) throw err;
- *   // your custom code   
+ *   // your custom code
  * });
  */
 NAN_METHOD(Image::save)
 {
     Image* im = Nan::ObjectWrap::Unwrap<Image>(info.Holder());
-    
+
     if (info.Length() == 0 || !info[0]->IsString()){
         Nan::ThrowTypeError("filename required to save file");
         return;
@@ -3872,7 +3926,7 @@ NAN_METHOD(Image::save)
     }
     // ensure callback is a function
     v8::Local<v8::Value> callback = info[info.Length()-1];
-    
+
     std::string filename = TOSTR(info[0]);
     std::string format("");
 
@@ -3912,7 +3966,7 @@ void Image::EIO_Save(uv_work_t* req)
     try
     {
         mapnik::save_to_file(*(closure->im->this_),
-                             closure->filename, 
+                             closure->filename,
                              closure->format);
     }
     catch (std::exception const& ex)
@@ -4157,7 +4211,7 @@ void Image::EIO_AfterComposite(uv_work_t* req)
 
     composite_image_baton_t *closure = static_cast<composite_image_baton_t *>(req->data);
 
-    if (closure->error) 
+    if (closure->error)
     {
         v8::Local<v8::Value> argv[1] = { Nan::Error(closure->error_name.c_str()) };
         Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(closure->cb), 1, argv);
@@ -4190,8 +4244,8 @@ NAN_SETTER(Image::set_scaling)
     if (!value->IsNumber())
     {
         Nan::ThrowError("Must provide a number");
-    } 
-    else 
+    }
+    else
     {
         double val = value->NumberValue();
         if (val == 0.0)
@@ -4209,8 +4263,8 @@ NAN_SETTER(Image::set_offset)
     if (!value->IsNumber())
     {
         Nan::ThrowError("Must provide a number");
-    } 
-    else 
+    }
+    else
     {
         double val = value->NumberValue();
         im->this_->set_offset(val);
@@ -4234,4 +4288,3 @@ NAN_METHOD(Image::data)
     // TODO - make this zero copy
     info.GetReturnValue().Set(Nan::CopyBuffer(reinterpret_cast<const char *>(im->this_->bytes()), im->this_->size()).ToLocalChecked());
 }
-
diff --git a/src/mapnik_image_view.cpp b/src/mapnik_image_view.cpp
index f0fad3f..36a18c4 100644
--- a/src/mapnik_image_view.cpp
+++ b/src/mapnik_image_view.cpp
@@ -1,4 +1,3 @@
-
 // mapnik
 #include <mapnik/color.hpp>             // for color
 #include <mapnik/image_view.hpp>        // for image_view, etc
@@ -99,7 +98,9 @@ v8::Local<v8::Value> ImageView::NewInstance(Image * JSImage ,
     ImageView* imv = new ImageView(JSImage);
     imv->this_ = std::make_shared<mapnik::image_view_any>(mapnik::create_view(*(JSImage->get()),x,y,w,h));
     v8::Local<v8::Value> ext = Nan::New<v8::External>(imv);
-    return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new ImageView instance");
+    return scope.Escape(maybe_local.ToLocalChecked());
 }
 
 typedef struct {
@@ -155,7 +156,7 @@ struct visitor_get_pixel_view
 {
     visitor_get_pixel_view(int x, int y)
         : x_(x), y_(y) {}
-    
+
     v8::Local<v8::Value> operator() (mapnik::image_view_null const& data)
     {
         // This should never be reached because the width and height of 0 for a null
@@ -200,7 +201,7 @@ struct visitor_get_pixel_view
         std::uint32_t val = mapnik::get_pixel<std::uint32_t>(data, x_, y_);
         return scope.Escape(Nan::New<v8::Uint32>(val));
     }
-    
+
     v8::Local<v8::Value> operator() (mapnik::image_view_gray32s const& data)
     {
         Nan::EscapableHandleScope scope;
@@ -246,7 +247,7 @@ struct visitor_get_pixel_view
   private:
     int x_;
     int y_;
-        
+
 };
 
 void ImageView::EIO_AfterIsSolid(uv_work_t* req)
@@ -585,5 +586,3 @@ NAN_METHOD(ImageView::save)
     }
     return;
 }
-
-
diff --git a/src/mapnik_layer.cpp b/src/mapnik_layer.cpp
index 4129a3a..d580195 100644
--- a/src/mapnik_layer.cpp
+++ b/src/mapnik_layer.cpp
@@ -111,7 +111,9 @@ v8::Local<v8::Value> Layer::NewInstance(mapnik::layer const& lay_ref) {
     // copy new mapnik::layer into the shared_ptr
     l->layer_ = std::make_shared<mapnik::layer>(lay_ref);
     v8::Local<v8::Value> ext = Nan::New<v8::External>(l);
-    return scope.Escape(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Layer instance");
+    return scope.Escape(maybe_local.ToLocalChecked());
 }
 
 NAN_GETTER(Layer::get_prop)
@@ -147,25 +149,25 @@ NAN_GETTER(Layer::get_prop)
         }
         return;
     }
-    else if (a == "minimum_scale_denominator") 
+    else if (a == "minimum_scale_denominator")
     {
-        info.GetReturnValue().Set(Nan::New<v8::Number>(l->layer_->minimum_scale_denominator()));   
+        info.GetReturnValue().Set(Nan::New<v8::Number>(l->layer_->minimum_scale_denominator()));
     }
-    else if (a == "maximum_scale_denominator") 
+    else if (a == "maximum_scale_denominator")
     {
-        info.GetReturnValue().Set(Nan::New<v8::Number>(l->layer_->maximum_scale_denominator()));   
+        info.GetReturnValue().Set(Nan::New<v8::Number>(l->layer_->maximum_scale_denominator()));
     }
-    else if (a == "queryable") 
+    else if (a == "queryable")
     {
-        info.GetReturnValue().Set(Nan::New<v8::Boolean>(l->layer_->queryable()));   
+        info.GetReturnValue().Set(Nan::New<v8::Boolean>(l->layer_->queryable()));
     }
-    else if (a == "clear_label_cache") 
+    else if (a == "clear_label_cache")
     {
-        info.GetReturnValue().Set(Nan::New<v8::Boolean>(l->layer_->clear_label_cache()));   
+        info.GetReturnValue().Set(Nan::New<v8::Boolean>(l->layer_->clear_label_cache()));
     }
-    else // if (a == "active") 
+    else // if (a == "active")
     {
-        info.GetReturnValue().Set(Nan::New<v8::Boolean>(l->layer_->active()));   
+        info.GetReturnValue().Set(Nan::New<v8::Boolean>(l->layer_->active()));
     }
 }
 
@@ -283,7 +285,7 @@ NAN_METHOD(Layer::describe)
 
     v8::Local<v8::Object> description = Nan::New<v8::Object>();
     mapnik::layer const& layer = *l->layer_;
-        
+
     description->Set(Nan::New("name").ToLocalChecked(), Nan::New<v8::String>(layer.name()).ToLocalChecked());
 
     description->Set(Nan::New("srs").ToLocalChecked(), Nan::New<v8::String>(layer.srs()).ToLocalChecked());
diff --git a/src/mapnik_map.cpp b/src/mapnik_map.cpp
index d92cb5f..a14c5be 100644
--- a/src/mapnik_map.cpp
+++ b/src/mapnik_map.cpp
@@ -611,7 +611,7 @@ typedef struct {
  * @param {String|number} [options.layer] - layer name (string) or index (positive integer, 0 index)
  * to query. If left blank, will query all layers.
  * @param {Function} callback
- * @returns {Array} array - An array of `Featureset` objects and layer names, which each contain their own 
+ * @returns {Array} array - An array of `Featureset` objects and layer names, which each contain their own
  * `Feature` objects.
  * @example
  * // iterate over the first layer returned and get all attribute information for each feature
@@ -626,7 +626,7 @@ typedef struct {
  *   }
  *   console.log(attributes); // => [{"attr_key": "attr_value"}, {...}, {...}]
  * });
- * 
+ *
  */
 NAN_METHOD(Map::queryMapPoint)
 {
@@ -635,7 +635,7 @@ NAN_METHOD(Map::queryMapPoint)
 }
 
 /**
- * Query a `Mapnik#Map` object to retrieve layer and feature data based on geographic 
+ * Query a `Mapnik#Map` object to retrieve layer and feature data based on geographic
  * coordinates of the source data (use `Map#queryMapPoint` to query with XY coordinates).
  *
  * @name queryPoint
@@ -647,7 +647,7 @@ NAN_METHOD(Map::queryMapPoint)
  * @param {String|number} [options.layer] - layer name (string) or index (positive integer, 0 index)
  * to query. If left blank, will query all layers.
  * @param {Function} callback
- * @returns {Array} array - An array of `Featureset` objects and layer names, which each contain their own 
+ * @returns {Array} array - An array of `Featureset` objects and layer names, which each contain their own
  * `Feature` objects.
  * @example
  * // query based on web mercator coordinates
@@ -662,7 +662,7 @@ NAN_METHOD(Map::queryMapPoint)
  *   }
  *   console.log(attributes); // => [{"attr_key": "attr_value"}, {...}, {...}]
  * });
- * 
+ *
  */
 NAN_METHOD(Map::queryPoint)
 {
@@ -1456,7 +1456,9 @@ NAN_METHOD(Map::clone)
     Map* m2 = new Map();
     m2->map_ = std::make_shared<mapnik::Map>(*m->map_);
     v8::Local<v8::Value> ext = Nan::New<v8::External>(m2);
-    info.GetReturnValue().Set(Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Map instance");
+    else info.GetReturnValue().Set(maybe_local.ToLocalChecked());
 }
 
 /**
@@ -1667,8 +1669,8 @@ struct vector_tile_baton_t {
  * @param {Object} [options={}]
  * @param {Number} [options.buffer_size=0] size of the buffer on the image
  * @param {Number} [options.scale=1.0] scale the image
- * @param {Number} [options.scale_denominator=0.0] 
- * @param {Number} [options.offset_x=0] pixel offset along the x-axis 
+ * @param {Number} [options.scale_denominator=0.0]
+ * @param {Number} [options.offset_x=0] pixel offset along the x-axis
  * @param {Number} [options.offset_y=0] pixel offset along the y-axis
  * @param {String} [options.image_scaling] must be a valid scaling method (used when rendering a vector tile)
  * @param {String} [options.image_format] must be a string and valid image format (used when rendering a vector tile)
@@ -1676,23 +1678,23 @@ struct vector_tile_baton_t {
  * @param {Boolean} [options.strictly_simple=] ensure all geometry is valid according to
  * OGC Simple definition (used when rendering a vector tile)
  * @param {Boolean} [options.multi_polygon_union] union all multipolygons (used when rendering a vector tile)
- * @param {String} [options.fill_type] the fill type used in determining what are holes and what are outer rings. See the 
+ * @param {String} [options.fill_type] the fill type used in determining what are holes and what are outer rings. See the
  * [Clipper documentation](http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/PolyFillType.htm)
  * to learn more about fill types. (used when rendering a vector tile)
  * @param {String} [options.threading_mode] (used when rendering a vector tile)
- * @param {Number} [options.simplify_distance] Simplification works to generalize 
- * geometries before encoding into vector tiles.simplification distance The 
+ * @param {Number} [options.simplify_distance] Simplification works to generalize
+ * geometries before encoding into vector tiles.simplification distance The
  * `simplify_distance` value works in integer space over a 4096 pixel grid and uses
  * the [Douglas-Peucker algorithm](https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm).
  * (used when rendering a vector tile)
- * @param {Object} [options.variables] Mapnik 3.x ONLY: A javascript object 
- * containing key value pairs that should be passed into Mapnik as variables 
- * for rendering and for datasource queries. For example if you passed 
+ * @param {Object} [options.variables] Mapnik 3.x ONLY: A javascript object
+ * containing key value pairs that should be passed into Mapnik as variables
+ * for rendering and for datasource queries. For example if you passed
  * `vtile.render(map,image,{ variables : {zoom:1} },cb)` then the `@zoom`
  * variable would be usable in Mapnik symbolizers like `line-width:"@zoom"`
- * and as a token in Mapnik postgis sql sub-selects like 
+ * and as a token in Mapnik postgis sql sub-selects like
  * `(select * from table where some_field > @zoom)` as tmp (used when rendering a vector tile)
- * @param {Boolean} [options.process_all_rings] if `true`, don't assume winding order and ring order of 
+ * @param {Boolean} [options.process_all_rings] if `true`, don't assume winding order and ring order of
  * polygons are correct according to the [`2.0` Mapbox Vector Tile specification](https://github.com/mapbox/vector-tile-spec)
  * (used when rendering a vector tile)
  * @returns {mapnik.Map} rendered image tile
@@ -1714,7 +1716,7 @@ struct vector_tile_baton_t {
  * var vtile = new mapnik.VectorTile(9,112,195);
  * map.render(vtile, {}, function(err, vtile) {
  *     if (err) throw err;
- *     console.log(vtile); // => vector tile object with data from xml 
+ *     console.log(vtile); // => vector tile object with data from xml
  * });
  */
 NAN_METHOD(Map::render)
diff --git a/src/mapnik_memory_datasource.cpp b/src/mapnik_memory_datasource.cpp
index b6f774f..3a1c51c 100644
--- a/src/mapnik_memory_datasource.cpp
+++ b/src/mapnik_memory_datasource.cpp
@@ -46,6 +46,7 @@ MemoryDatasource::~MemoryDatasource()
 
 NAN_METHOD(MemoryDatasource::New)
 {
+    std::clog << "WARNING: MemoryDatasource is deprecated and will be removed in node-mapnik >= 3.7.x\n";
     if (!info.IsConstructCall())
     {
         Nan::ThrowError("Cannot call constructor as function, you need to use 'new' keyword");
@@ -112,7 +113,9 @@ v8::Local<v8::Value> MemoryDatasource::NewInstance(mapnik::datasource_ptr ds_ptr
     MemoryDatasource* d = new MemoryDatasource();
     d->datasource_ = ds_ptr;
     v8::Local<v8::Value> ext = Nan::New<v8::External>(d);
-    return scope.Escape( Nan::New(constructor)->GetFunction()->NewInstance(1, &ext));
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new MemoryDatasource instance");
+    return scope.Escape(maybe_local.ToLocalChecked());
 }
 
 NAN_METHOD(MemoryDatasource::parameters)
diff --git a/src/mapnik_projection.cpp b/src/mapnik_projection.cpp
index efd5b80..e047e2e 100644
--- a/src/mapnik_projection.cpp
+++ b/src/mapnik_projection.cpp
@@ -10,7 +10,7 @@ Nan::Persistent<v8::FunctionTemplate> Projection::constructor;
 
 /**
  * **`mapnik.Projection`**
- * 
+ *
  * A geographical projection: this class makes it possible to translate between
  * locations in different projections
  *
@@ -79,7 +79,7 @@ NAN_METHOD(Projection::New)
             lazy = lazy_opt->BooleanValue();
         }
     }
-            
+
     try
     {
         Projection* p = new Projection(TOSTR(info[0]), lazy);
diff --git a/src/mapnik_vector_tile.cpp b/src/mapnik_vector_tile.cpp
index 1985c37..15ab6c5 100644
--- a/src/mapnik_vector_tile.cpp
+++ b/src/mapnik_vector_tile.cpp
@@ -1396,8 +1396,9 @@ NAN_METHOD(VectorTile::layer)
         }
     }
     v8::Local<v8::Value> ext = Nan::New<v8::External>(v);
-    v8::Local<v8::Object> vt_obj = Nan::New(constructor)->GetFunction()->NewInstance(1, &ext);
-    info.GetReturnValue().Set(vt_obj);
+    Nan::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+    if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Layer instance");
+    else info.GetReturnValue().Set(maybe_local.ToLocalChecked());
     return;
 }
 
@@ -5143,20 +5144,17 @@ void VectorTile::EIO_RenderTile(uv_work_t* req)
     try
     {
         mapnik::Map const& map_in = *closure->m->get();
-        mapnik::vector_tile_impl::spherical_mercator merc(closure->d->tile_size());
-        double minx,miny,maxx,maxy;
+        mapnik::box2d<double> map_extent;
         if (closure->zxy_override)
         {
-            merc.xyz(closure->x,closure->y,closure->z,minx,miny,maxx,maxy);
+            map_extent = mapnik::vector_tile_impl::tile_mercator_bbox(closure->x,closure->y,closure->z);
         } 
         else 
         {
-            merc.xyz(closure->d->get_tile()->x(),
-                     closure->d->get_tile()->y(),
-                     closure->d->get_tile()->z(),
-                     minx,miny,maxx,maxy);
+            map_extent = mapnik::vector_tile_impl::tile_mercator_bbox(closure->d->get_tile()->x(),
+                                                                      closure->d->get_tile()->y(),
+                                                                      closure->d->get_tile()->z());
         }
-        mapnik::box2d<double> map_extent(minx,miny,maxx,maxy);
         mapnik::request m_req(closure->width, closure->height, map_extent);
         m_req.set_buffer_size(closure->buffer_size);
         mapnik::projection map_proj(map_in.srs(),true);
diff --git a/test/data/images/san-marino.svg b/test/data/images/san-marino.svg
new file mode 100644
index 0000000..6ba0116
--- /dev/null
+++ b/test/data/images/san-marino.svg
@@ -0,0 +1,92 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
+  <g fill-rule="evenodd" stroke-width="1pt">
+    <path fill="#19b6ef" d="M0 240h640v240H0z"/>
+    <path fill="#fff" d="M0 0h640v240H0z"/>
+  </g>
+  <path d="M317.07 339.221c52.45-39.239 108.96-119.306 42.74-161.41-12.336-2.388-26.107-1.672-32.713 3.582-3.501-1.99-6.288-1.83-9.79 1.91-2.466-3.025-4.935-4.379-10.028-2.865-10.188-5.173-19.42-6.288-31.517-3.105-57.623 34.622-22.366 116.76 41.308 161.888z" fill-rule="evenodd" stroke="#7d6c00" stroke-width="2.3686254" fill="#fd0"/>
+  <g stroke="#3a9d4f">
+    <path stroke-linejoin="round" d="M414.08 250.106s5.903-7.939 6.106-7.939c5.904-3.46 6.515-7.938 6.515-7.938 5.903-1.833 4.07-6.718 4.477-7.328 2.852-3.053 1.833-6.108 1.426-7.126 0-.812 2.036-8.345-.814-9.362.135-8.008-4.818-7.261-8.754-2.036-4.207 1.221-5.157 4.682-3.664 8.55-5.497 0-5.7 7.939-4.071 12.416-7.328-.203-3.257 7.939-3.461 8.347-2.442 1.221 1.832 12.824 2.24 12.416zM367.857 318.3l3.664 2.239c.746 2.781 3.325 4.547 5.294 4.072.95 4.274 5.563 3.665 8.956 1.221 2.714 3.936  [...]
+    <path stroke-linejoin="round" d="M404.502 266.397c-4.14-3.122-6.446-6.853-5.7-10.586-2.713-3.664-4.614-5.903-2.035-9.16 0 0-2.036-7.329-2.036-7.532-5.292-2.035-3.053-6.513-1.629-8.142-2.51-3.461-2.578-7.126-.203-10.382-.068-6.515 4.546-4.071 8.345 0 0 0 6.311 4.479 1.63 8.55 4.681 1.629 6.107 5.698 3.46 7.327 4.071 1.833 4.681 5.497 2.442 7.94 4.14 3.326 2.579 7.465 3.868 11.196l-8.142 10.789z" fill-rule="evenodd" stroke-width="2.3686254" fill="#4fd46b"/>
+    <path stroke-linejoin="round" d="M411.831 236.064c-.203-.203-6.92-8.753-5.089-9.364-.406-2.647-2.441-5.497-1.22-8.142-3.325-3.325-3.394-7.26-.815-10.38-2.239-3.054-1.221-7.125 1.832-9.772-.95-5.022 2.579-6.175 5.7-7.126 2.307-8.075 6.038-5.971 8.142.203 3.19 2.782 2.715 6.99 1.63 10.18 3.799 2.578 1.492 5.766-.204 7.124l-9.976 27.277z" fill-rule="evenodd" stroke-width="2.3686254" fill="#4fd46b"/>
+    <path stroke-linejoin="round" d="M410.815 193.106l-5.7-5.7c1.473-3.02 2.659-8.344-1.627-10.789-2.364-5.757-14.182-12.892-16.083.815-1.799-4.136-5.563-8.21-8.345-3.46-6.175-5.292-9.5-3.665-6.311 3.053 0 0-2.848 4.478 4.682 7.939.611.61-2.442 8.142 6.515 8.345-1.696 2.579 1.086 6.175 4.682 5.903-2.579 3.19 1.764 6.583 4.477 5.294-1.154 3.528-1.086 5.225 3.868 5.7l5.497 6.31 4.477 6.106 3.868-29.516z" fill-rule="evenodd" stroke-width="2.3686254" fill="#4fd46b"/>
+    <path d="M414.28 246.508c.288-.288 10.938-24.757 12.378-32.243M415.43 203.05s1.726 19.864-3.167 34.545M382.615 182.895s21.879 21.015 23.893 29.651M397.873 180.596s1.439 17.274 7.484 34.259M436.45 243.343s-21.879 18.425-32.53 34.545M415.712 307.84s-28.788 4.03-41.454 4.318M406.218 320.215s-35.698-.864-38.29-3.454M388.361 273.859c0 .287-18.136 30.226-18.712 40.015" stroke-linecap="round" stroke-width="2.2203781" fill="none"/>
+  </g>
+  <path d="M316.87 333.441c-37.768-35.624-76.454-102.482-37.972-136.27 6.84 3.88 14.903.409 26.03-3.98 3.368 3.674 7.654 4.594 11.942 1.837 4.797 2.042 8.37.408 10.718-2.144 10.922 6.33 24.906 9.596 28.172 3.37 37.87 35.93-.511 103.095-38.89 137.187z" fill-rule="evenodd" stroke="#7d6c00" stroke-width="2.3686254" fill="#65c7ff"/>
+  <path d="M317.086 332.408c-16.219-16.307-31.017-34.385-42.347-57.66 1.939-1.632 2.84-2.138 3.861-4.997 5.818.818 8.88 1.021 16.536-.306 1.53 5.717 1.837 10.514 5.511 15.311l7.656-15.005c5.205 1.226 11.637 1.533 16.535 0 3.165 4.288 2.042 10.72 7.656 15.618 3.368-9.9 6.738-10.615 10.106-15.924 5.002 1.736 8.167 1.021 12.25-.307 2.143 2.45 1.072 2.41 4.975 6.007-10.233 20.32-24.265 40.728-42.739 57.263z" fill-rule="evenodd" fill="#8fc753"/>
+  <path d="M272.65 164.304a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM269.158 156.594a3.346 3.346 0 1 1-6.691 0 3.346 3.346 0 0 1 6.691 0zM265.085 149.465a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM262.321 142.482a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM262.757 134.918a3.346 3.346 0 1 1-6.691 0 3.346 3.346 0 0 1 6.691 0zM280.42 122.407a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.1110219000000001" [...]
+  <path d="M273.814 123.571a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM266.54 127.935a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM288.943 122.552a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM298.254 123.28a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM306.546 122.843a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.1110219000000001" fill="#fff"/>
+  <path d="M325.874 117.504a8.583 8.583 0 1 1-17.166 0 8.583 8.583 0 0 1 17.166 0z" fill-rule="evenodd" stroke="#7d6c00" stroke-width="1.110941" fill="#fd0"/>
+  <path d="M334.913 122.698a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM343.642 123.425a3.346 3.346 0 1 1-6.691 0 3.346 3.346 0 0 1 6.691 0zM352.08 122.988a3.346 3.346 0 1 1-6.693 0 3.346 3.346 0 0 1 6.692 0zM359.207 122.698a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM368.082 123.716a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM375.064 128.08a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.1110219000000001" [...]
+  <path d="M269.414 151.697c2.85 5.42 5.698 11.05 8.548 16.47h79.23l9.174-15.846c-5.352-3.683-9.035-6.533-16.68-4.795-4.31-6.185-9.035-7.366-16.054-6.671-2.086-2.154-3.963-3.475-7.508-3.961l-16.678.416c-4.38.416-7.716 3.753-7.924 3.753-7.09-.835-13.552-.627-15.22 6.254-6.463-1.599-11.05.14-16.888 4.38z" fill-rule="evenodd" stroke="#ac0000" stroke-width="2.3686254" fill="#e40000"/>
+  <path d="M377.974 135.354a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM378.556 143.21a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM376.082 150.484a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM373.027 156.448a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM369.39 164.013a3.346 3.346 0 1 1-6.69 0 3.346 3.346 0 0 1 6.69 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.1110219000000001" fill="#fff"/>
+  <path d="M322.566 154.424a4.946 4.946 0 1 1-9.893 0 4.946 4.946 0 0 1 9.893 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.1105424000000002" fill="#fff"/>
+  <path d="M323.546 143.045a5.964 5.964 0 1 1-11.93 0 5.964 5.964 0 0 1 11.93 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.11051072" fill="#fff"/>
+  <path d="M322.685 131.995a5.383 5.383 0 1 1-10.765 0 5.383 5.383 0 0 1 10.765 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.10935854" fill="#fff"/>
+  <path d="M315.487 109.055c0-.926-.028-4.165.037-4.295l-3.572-.064.102-3.175 3.1-.037.037-2.775h4.395v2.544h3.47l-.072 3.378-3.6-.037-.03 4.526-3.867-.065z" fill-rule="evenodd" stroke="#7d6c00" stroke-width="1.1110219000000001" fill="#fd0"/>
+  <path d="M277.56 168.17c-7.092-12.023-17.51-28.367-11.053-35.444 8.955-10.143 29.953-.973 43.367-6.881.972 11.468-2.224 30.44 2.92 34.403l-4.796 4.17c-2.92-3.753-8.418-8.782-15.22.208-3.892-3.403-8.316-2.805-10.4 1.72-1.982.267-1.867 1.06-4.819 1.824zM357.68 167.754c7.09-12.023 17.51-28.367 11.051-35.444-8.955-10.143-29.952-.973-43.366-6.882-.973 11.469 2.223 30.441-2.92 34.404l4.795 4.17c4.614-6.489 10.373-6.699 15.22.207 3.893-3.403 7.925-2.936 10.4 1.721 1.983.267 1.868 1.06 4.82 1. [...]
+  <path d="M277.343 177.132c28.495-2.918 54.904-1.877 79.23 0l3.127-8.967c-27.66-5.003-46.773-5.628-82.982-.624l.625 9.59z" fill-rule="evenodd" stroke="#7d6c00" stroke-width="2.3686254" fill="#fd0"/>
+  <path d="M314.121 329.377c.205-1.43.408-2.762.613-4.191 2.834.763 4.996.468 7.35-.402.815-1.225 1.633-2.45 2.45-3.676l-1.838-2.142c-1.615.348-2.941 1.85-3.98 3.158-1.628.077-3.064-.71-4.595-1.016l-1.53-6.43c-1.52-1.795-4.671-1.668-3.982 1.531l.307 2.45c.613 1.531.841 3.639 1.837 4.785v2.511c1.123 1.141 2.246 2.28 3.368 3.422zM315.337 311.087c-2.13 1.056-4.659-.78-7.349-1.837-2.45-.168-4.419 1.872-7.349 1.224.535-1.59 1.837-1.837 2.757-2.756-.673-4.131 1.53-5.512 2.144-5.512.61 0 3.061. [...]
+  <path d="M300.779 366.089c7.066-11.472 56.259-34.508 102.422-84.251-46.99 45.243-76.357 56.35-114.812 83.974l12.39.277z" fill-rule="evenodd" stroke="#e9bf00" stroke-width="2.3686254" fill="#ffe100"/>
+  <path d="M368.406 313.186a3.582 3.582 0 1 1-7.163 0 3.582 3.582 0 0 1 7.163 0zM402.786 278.323a4.06 4.06 0 1 1-8.118 0 4.06 4.06 0 0 1 8.118 0zM414.252 248.713a3.582 3.582 0 1 1-7.163 0 3.582 3.582 0 0 1 7.163 0zM403.02 210.28a3.582 3.582 0 1 1-7.164 0 3.582 3.582 0 0 1 7.164 0z" fill-rule="evenodd" stroke="#68300e" stroke-width="1.1110219000000001" fill="#9d4916"/>
+  <path d="M279.125 269.595v-15.148l-1.54-1.283v-3.594l2.824-.257.513-16.945-1.797-1.028-.257-2.823s2.054.77 2.054.257.513-3.339.513-3.339-1.282-.256-1.282-.77 1.539-1.796 1.539-1.796-.77-.772-1.026-1.285-.77-2.823-.77-2.823l.77-2.825-.513-1.54-1.285-2.311 1.798-1.797s-.513-2.31-.513-2.824 1.282-2.567 1.539-2.825c.258-.256 2.312-3.08 2.312-3.08l4.364-1.027 5.135.77 2.824 1.798.513 4.62s-.513 2.824-.77 2.824-2.31 1.028-2.31 1.028-2.569.256-2.825 0 .77 3.081.77 3.081v3.08l-.256 3.851s0 1.7 [...]
+  <path fill-rule="evenodd" d="M282.923 269.495v-11.938h6.686v12.416l-6.686-.478zM314.438 270.444l.238-12.178h5.97v11.938l-6.208.24zM345.486 270.211l-.478-11.46 6.448-.24v11.94l-5.97-.24zM284.588 234.149h3.82v6.208h-3.82zM314.92 234.399h5.254v5.97h-5.253zM345.953 234.865h4.537v5.73h-4.537z"/>
+  <path d="M286.57 206.965c4.108 4.62 4.365 4.62 4.365 4.62M317.12 206.965c.769 1.539 2.053 4.877 3.594 5.133M349.984 207.73s1.284 3.595 3.081 4.108" stroke="#a8a8a8" stroke-width="1.1110219000000001" fill="none"/>
+  <path d="M282.206 194.022c12.012-3.883-2.806-11.648-5.267 0-3.886.628-4.389 3.511-12.789 2.259-20.313 33.102-5.267 86.518 54.169 141.816-106.457-90.594-63.194-157.604-33.714-155.077 16.034 1.096 7.945 21.096-2.399 11.002z" fill-rule="evenodd" fill="#b97700"/>
+  <path d="M285.554 177.049s9.781 2.633 9.781 6.77M295.332 176.299s6.771 3.008 8.275 5.642M348.751 177.432s-8.653 1.129-10.534 3.76M335.575 178.181s-4.888 4.138-4.514 5.265M334.46 196.237c-.753-.376-4.138-4.89-3.387-10.533M301.345 193.24s2.257-2.634 2.257-7.525M317.153 183.828l.376 10.909M326.93 193.24c0-.754 3.01-7.9-.376-11.286M306.242 180.447s-2.633 7.147-.75 13.165M325.431 186.843s-4.137 1.128-6.02 3.01M307.742 187.959c0-.375 4.514-1.128 6.018 1.506" stroke="#7d6c00" stroke-width="2. [...]
+  <path d="M300.63 301.86c.19.096 3.745-.674 3.745-2.403 1.826-1.152.48-4.419.48-4.419l-3.361-.673-4.613-5.187c-.223-1.6.322-3.104-.671-4.802-3.17.833-4.995 3.49-6.053 6.531.77.962.866 2.018 2.307 2.882 1.504.257 2.528-.64 3.938-.383.736 1.28.51 2.37.767 3.555 1.923 1.344 2.307 3.266 3.46 4.898zM296.498 279.672v-6.148l-4.419-.193c-.545.93-1.57 1.378-2.21 2.21l-3.074 1.538c1.281 1.537 2.85 2.402 3.843 3.17 2.242.673 4.1.673 5.86-.577zM282.656 288.8l-2.402-4.036c1.473-.48 3.33-.288 4.707.2 [...]
+  <path d="M353.115 193.19c-12.011-3.884 2.807-11.65 5.267 0 3.886.627 4.39 3.51 12.79 2.258 20.313 33.102 5.266 86.518-54.17 141.816 106.457-90.594 63.194-157.604 33.715-155.077-16.034 1.096-7.946 21.096 2.398 11.002z" fill-rule="evenodd" fill="#b97700"/>
+  <path d="M354.331 284.67c-.191 0-3.073 2.112-3.073 2.112-1.378.544-2.753 1.089-4.13 1.634l-4.42.095-.961-3.074 3.363-2.978c-2.85-.416-5.7.705-7.974 2.787 0 0 0 3.361 1.922 4.995 1.153 1.44 4.514 4.035 4.514 4.035 2.114.416 4.131.063 5.476-1.058 1.76-2.85 3.523-5.699 5.283-8.549zM331.078 314.835c1.443.385 11.337-12.776 11.337-12.776-.865-2.465-2.787-4.259-4.9-5.38 0 0-4.805 5.667-4.9 7.589-.767 1.729-2.976 8.357-2.017 9.223-.096.192-.48 2.88.48 1.344z" fill-rule="evenodd" fill="#c76e2e"/>
+  <path stroke-linejoin="round" d="M266.366 317.4c-14.817-12.887-34.809-19.991-62.716-10.35 7.51 3.248 15.628 4.364 22.529 7.915l40.187 2.435z" fill-rule="evenodd" stroke="#004100" stroke-width="2.3686254" fill="#006800"/>
+  <path d="M223.44 308.256c29.227.608 37.752 7.913 36.23 6.696" stroke="#00a400" stroke-linecap="round" stroke-width="2.2203781" fill="none"/>
+  <path stroke-linejoin="round" d="M266.965 318.916c-8.728 1.724-20.804 10.154-24.356 9.741-9.54-1.11-18.454-4.975-27.704-7.915-3.842-1.221-7.713 0-11.57 0 32.78-15.526 43.943-13.396 63.63-1.826z" fill-rule="evenodd" stroke="#004100" stroke-width="2.2203781" fill="#006800"/>
+  <path stroke-linejoin="round" d="M245.361 296.08s-10.959 1.52-15.83 1.825c-4.873-.303-11.955-4.842-19.79-13.09-4.088-4.48-13.395-3.958-13.395-3.958 20.602-4.365 36.634-.204 49.015 15.222zM230.436 274.775c-14.92-.914-33.49-14.308-37.751-30.139-.002.202 5.479 3.45 4.566 4.263 24.457 6.19 26.081 11.161 33.185 25.876zM255.405 300.344c2.13-13.498 2.74-22.427-3.653-30.444-5.277-6.09-6.596-9.743-10.35-18.268-1.116 17.76-4.974 32.474 14.003 48.712zM231.952 262.899c11.06-16.136 12.99-28.314 11. [...]
+  <path stroke-linejoin="round" d="M222.225 184.96c11.06 16.136 9.336 31.36 7.61 50.54-.305-1.523-3.958-10.96-4.26-10.96-16.441-10.351-5.48-29.534-3.35-39.58z" fill-rule="evenodd" stroke="#004100" stroke-width="2.3686254" fill="#006800"/>
+  <path stroke-linejoin="round" d="M231.353 209.93c26.79-13.498 16.438-30.648 21.31-43.84-18.57 13.802-21.006 28.515-21.31 43.84z" fill-rule="evenodd" stroke="#004100" stroke-width="2.3686254" fill="#006800"/>
+  <path d="M235 206.581c3.35-9.437 10.048-25.573 10.656-25.573M227.088 226.37c-.608-6.7-3.956-24.662-4.26-26.488" stroke="#00a400" stroke-linecap="round" stroke-width="2.2203781" fill="none"/>
+  <path stroke-linejoin="round" d="M228.304 256.502c-14.92-.914-31.055-21.31-35.316-37.141-.001.201 5.479 3.45 4.566 4.262 21.412 9.538 23.646 18.165 30.75 32.88zM223.874 242.494c-11.06-16.136-12.99-28.314-11.264-47.494.305 1.522 3.958 10.96 4.261 10.96 16.44 10.35 9.133 26.488 7.003 36.534zM233.785 214.194c27.703-12.28 19.178-25.167 27.399-38.665-18.571 13.802-27.095 23.34-27.4 38.665z" fill-rule="evenodd" stroke="#004100" stroke-width="2.3686254" fill="#006800"/>
+  <path d="M235 211.445c11.266-11.265 15.223-20.703 15.223-20.703" stroke="#00a400" stroke-linecap="round" stroke-width="2.2203781" fill="none"/>
+  <g fill-rule="evenodd">
+    <path d="M333.56 366.355l13.49.275c-44.787-41.942-130.599-60.205-118.667-137.39-12.298 83.701 70.117 91.41 105.177 137.115z" stroke="#e9bf00" stroke-width="2.3686254" fill="#ffe100"/>
+    <path d="M235.417 212.661a4.298 4.298 0 1 1-8.596 0 4.298 4.298 0 0 1 8.596 0zM232.785 236.297a4.06 4.06 0 1 1-8.118 0 4.06 4.06 0 0 1 8.118 0zM236.6 269.978a3.582 3.582 0 1 1-7.164 0 3.582 3.582 0 0 1 7.164 0zM267.876 307.223a3.582 3.582 0 1 1-7.163 0 3.582 3.582 0 0 1 7.163 0zM272.412 317.907a3.582 3.582 0 1 1-7.163 0 3.582 3.582 0 0 1 7.163 0z" stroke="#68300e" stroke-width="1.1110219000000001" fill="#9d4916"/>
+  </g>
+  <g fill-rule="evenodd" fill="#fff">
+    <g stroke="#000" stroke-width=".667">
+      <path d="M288.203 349.032c-2.355-2.134-3.853-3.503-4.777-5.828l-14.044-1.528c-.063 2.675-.126 5.349-.191 8.024l19.012-.668z" stroke-width="1.1110219000000001"/>
+      <path stroke-linejoin="round" d="M185.313 339.57c8.157 1.507 20.456-.752 24.472 4.518 4.822 5.465-15.093 13.872-12.241 18.6 6.16 6.517 12.5 3.83 19.394.226 1.624-3.523 2.878-9.804 3.766-11.672-2.51-5.773-9.253-8.601-7.53-17.32 11.37-4.249 33.23-3.897 35.583-2.258 1.848 3.623.187 5.273.564 8.16-1.883 3.64-6.728 9.81-6.738 13.074 11.93 4.203 15.074-.648 25.806-.363 12.575.155 20.225 3.531 22.955-1.467-1.87-4.315-13.403-.805-17.78-3.577-2.19-.74-3.604-2.5-5.496-4.44s-7.21-2.04-8.007-6 [...]
+      <path d="M184.732 337.954a3.63 3.63 0 1 1-7.26 0 3.63 3.63 0 0 1 7.26 0zM183.78 355.911a3.63 3.63 0 1 1-7.26 0 3.63 3.63 0 0 1 7.26 0z" stroke-width="1.1110219000000001"/>
+    </g>
+    <g stroke="#000" stroke-width=".667">
+      <path d="M346.253 349.097c2.355-2.134 3.852-3.503 4.777-5.828l14.043-1.528.192 8.024-19.012-.668z" stroke-width="1.1110219000000001"/>
+      <path stroke-linejoin="round" d="M449.143 339.636c-8.157 1.506-20.457-.753-24.473 4.517-4.822 5.465 15.093 13.872 12.242 18.6-6.16 6.517-12.5 3.83-19.394.226-1.624-3.523-2.878-9.804-3.766-11.671 2.51-5.774 9.253-8.602 7.53-17.32-11.371-4.25-33.23-3.898-35.584-2.26-1.847 3.624-.187 5.274-.563 8.161 1.882 3.64 6.728 9.81 6.738 13.074-11.93 4.203-15.075-.648-25.807-.363-12.574.155-20.225 3.531-22.955-1.467 1.87-4.315 13.404-.805 17.781-3.577 2.19-.74 3.603-2.5 5.496-4.44s7.21-2.04 8.0 [...]
+      <path d="M449.723 338.02a3.63 3.63 0 1 0 7.261 0 3.63 3.63 0 0 0-7.26 0zM450.675 355.976a3.63 3.63 0 1 0 7.26 0 3.63 3.63 0 0 0-7.26 0z" stroke-width="1.1110219000000001"/>
+    </g>
+    <path d="M316.986 329.343c-3.231-.606-4.38-.433-6.57-.65-1.715 5.271-3.427 10.541-5.141 15.812 7.938.716 15.29.716 15.29.651-4.816-.976-3.644-15.748-3.579-15.813z"/>
+  </g>
+  <g font-size="9" font-family="Trebuchet MS" font-weight="bold">
+    <text y="344.274" x="448.605" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="344.274" x="448.605">L</tspan>
+    </text>
+    <text y="344.622" x="453.64" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="344.622" x="453.64">I</tspan>
+    </text>
+    <text y="345.056" x="456.678" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="345.056" x="456.678">B</tspan>
+    </text>
+    <text y="345.49" x="462.58" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="345.49" x="462.58">E</tspan>
+    </text>
+    <text y="345.576" x="468.309" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="345.576" x="468.309">R</tspan>
+    </text>
+    <text y="345.403" x="473.952" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="345.403" x="473.952">T</tspan>
+    </text>
+    <text y="344.535" x="479.247" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="344.535" x="479.247">A</tspan>
+    </text>
+    <text y="344.274" x="485.497" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="344.274" x="485.497">S</tspan>
+    </text>
+  </g>
+  <path d="M231.353 318.616c10.047 1.218 24.052.304 30.14-.001M216.128 284.203c8.525 6.698 27.096 10.654 26.791 10.654M253.573 296.696c-2.74-14.004-5.783-17.353-8.219-26.183M201.82 254.67c14.31 6.393 16.44 10.654 25.573 17.047M232.569 257.718c1.219-17.355 3.654-21.922 7.917-25.88M201.82 229.718c5.177 5.785 22.225 23.746 22.225 23.746M217.044 213.877c6.395 4.566 6.395 21.005 6.395 21.005" stroke="#00a400" stroke-linecap="round" stroke-width="2.2203781" fill="none"/>
+</svg>
diff --git a/test/data/vector_tile/compositing/expected/2-1-1b.png b/test/data/vector_tile/compositing/expected/2-1-1b.png
index 0086046..c1039ee 100644
Binary files a/test/data/vector_tile/compositing/expected/2-1-1b.png and b/test/data/vector_tile/compositing/expected/2-1-1b.png differ
diff --git a/test/data/vector_tile/compositing/expected/world-reencode-max-extent.png b/test/data/vector_tile/compositing/expected/world-reencode-max-extent.png
index d474a94..0fa7e80 100644
Binary files a/test/data/vector_tile/compositing/expected/world-reencode-max-extent.png and b/test/data/vector_tile/compositing/expected/world-reencode-max-extent.png differ
diff --git a/test/data/vector_tile/compositing/expected/world-reencode.png b/test/data/vector_tile/compositing/expected/world-reencode.png
index 65c07f0..0e0e8f0 100644
Binary files a/test/data/vector_tile/compositing/expected/world-reencode.png and b/test/data/vector_tile/compositing/expected/world-reencode.png differ
diff --git a/test/data/vector_tile/nz-1.png b/test/data/vector_tile/nz-1.png
index 9f6ca0b..b99d81a 100644
Binary files a/test/data/vector_tile/nz-1.png and b/test/data/vector_tile/nz-1.png differ
diff --git a/test/data/vector_tile/nz-1b.png b/test/data/vector_tile/nz-1b.png
index f44871d..3768e2b 100644
Binary files a/test/data/vector_tile/nz-1b.png and b/test/data/vector_tile/nz-1b.png differ
diff --git a/test/data/vector_tile/tile-raster.expected.jpg b/test/data/vector_tile/tile-raster.expected.jpg
index 20a6cae..3fa2937 100644
Binary files a/test/data/vector_tile/tile-raster.expected.jpg and b/test/data/vector_tile/tile-raster.expected.jpg differ
diff --git a/test/data/vector_tile/tile0-c.expected.png b/test/data/vector_tile/tile0-c.expected.png
index 558d596..01ebc22 100644
Binary files a/test/data/vector_tile/tile0-c.expected.png and b/test/data/vector_tile/tile0-c.expected.png differ
diff --git a/test/data/vector_tile/tile0-simple_and_distance.mvt b/test/data/vector_tile/tile0-simple_and_distance.mvt
index e249918..d31a675 100644
Binary files a/test/data/vector_tile/tile0-simple_and_distance.mvt and b/test/data/vector_tile/tile0-simple_and_distance.mvt differ
diff --git a/test/data/vector_tile/tile0-simplify_distance.mvt b/test/data/vector_tile/tile0-simplify_distance.mvt
index e249918..d31a675 100644
Binary files a/test/data/vector_tile/tile0-simplify_distance.mvt and b/test/data/vector_tile/tile0-simplify_distance.mvt differ
diff --git a/test/datasource.test.js b/test/datasource.test.js
index 15cc16d..710f189 100644
--- a/test/datasource.test.js
+++ b/test/datasource.test.js
@@ -10,7 +10,7 @@ mapnik.register_datasource(path.join(mapnik.settings.paths.input_plugins,'shape.
 mapnik.register_datasource(path.join(mapnik.settings.paths.input_plugins,'gdal.input'));
 
 describe('mapnik.Datasource', function() {
-    
+
     it('should throw with invalid usage', function() {
         assert.throws(function() { mapnik.Datasource('foo'); });
         assert.throws(function() { mapnik.Datasource({ 'foo': 1 }); });
@@ -165,7 +165,7 @@ describe('mapnik.Datasource', function() {
 
         assert.deepEqual(ds.fields(), expected.fields);
     });
-    
+
     it('test invalid use of memory datasource', function() {
         var ds = new mapnik.MemoryDatasource({'extent': '-180,-90,180,90'});
         assert.throws(function() { ds.add(); });
@@ -213,7 +213,10 @@ describe('mapnik.Datasource', function() {
     });
 
     it('test empty geojson datasource due to invalid json file', function() {
-        assert.throws(function() { new mapnik.Datasource({ type:'geojson', file: './test/data/parse.error.json', cache_features: false }); });
+        var ds = new mapnik.Datasource({ type:'geojson', file: './test/data/parse.error.json', cache_features: false });
+        var empty_fs = ds.featureset();
+        assert.equal(typeof(empty_fs),'undefined');
+        assert.equal(empty_fs, null);
     });
 
     it('test valid use of memory datasource', function() {
@@ -221,11 +224,11 @@ describe('mapnik.Datasource', function() {
         assert.equal(true, ds.add({ 'x': 0, 'y': 0 }));
         assert.equal(true, ds.add({ 'x': 0.23432, 'y': 0.234234 }));
         assert.equal(true, ds.add({ 'x': 1, 'y': 1 , 'properties': {'a':'b', 'c':1, 'd':0.23 }}));
-        var expected_describe = { 
+        var expected_describe = {
             type: 'vector',
             encoding: 'utf-8',
             fields: {},
-            geometry_type: 'collection' 
+            geometry_type: 'collection'
         };
         assert.deepEqual(expected_describe, ds.describe());
         // Currently descriptors can not be added to memory datasource so will always be empty object
diff --git a/test/image.svg.test.js b/test/image.svg.test.js
index 2e2ad27..c09fec5 100644
--- a/test/image.svg.test.js
+++ b/test/image.svg.test.js
@@ -25,10 +25,10 @@ describe('mapnik.Image SVG', function() {
         }, /first argument is invalid, must be a Buffer/);
         assert.throws(function() {
           new mapnik.Image.fromSVGBytesSync(new Buffer('asdfasdf'));
-        }, /SVG parse error:\s+Unable to parse 'asdfasdf'/);
+        }, /SVG error: unable to parse "asdfasdf"/);
         assert.throws(function() {
           mapnik.Image.fromSVGSync('./test/data/SVG_DOES_NOT_EXIST.svg');
-        }, /SVG parse error:\s+Unable to open '.\/test\/data\/SVG_DOES_NOT_EXIST.svg'/);
+        }, /SVG error: unable to open "\.\/test\/data\/SVG_DOES_NOT_EXIST\.svg"/);
         assert.throws(function() {
           mapnik.Image.fromSVGSync('./test/data/vector_tile/tile0.expected-svg.svg', 256);
         }, /optional second arg must be an options object/);
@@ -73,7 +73,7 @@ describe('mapnik.Image SVG', function() {
         }, /image created from svg must have a width and height greater then zero/);
         mapnik.Image.fromSVGBytes(new Buffer('a'), { scale: 1 }, function(err, res) {
             assert.ok(err);
-            assert.ok(err.message.match(/Unable to parse 'a'/));
+            assert.ok(err.message.match(/SVG error: unable to parse "a"/));
             var svgdata = "<svg width='1000000000000' height='1000000000000'><g id='a'><ellipse fill='#FFFFFF' stroke='#000000' stroke-width='4' cx='50' cy='50' rx='25' ry='25'/></g></svg>";
             var buffer = new Buffer(svgdata);
             mapnik.Image.fromSVGBytes(buffer, { scale: 1 }, function(err, img) {
@@ -149,7 +149,7 @@ describe('mapnik.Image SVG', function() {
         done();
       });
     });
-    
+
     it('should err with async file w/o width or height as Bytes', function(done) {
         var svgdata = "<svg width='0' height='0'><g id='a'><ellipse fill='#FFFFFF' stroke='#000000' stroke-width='4' cx='50' cy='50' rx='25' ry='25'/></g></svg>";
         var buffer = new Buffer(svgdata);
@@ -164,7 +164,7 @@ describe('mapnik.Image SVG', function() {
     it('should err with async invalid buffer', function(done) {
       mapnik.Image.fromSVGBytes(new Buffer('asdfasdf'), function(err, svg) {
         assert.ok(err);
-        assert.ok(err.message.match(/SVG parse error:\s+Unable to parse 'asdfasdf'/));
+        assert.ok(err.message.match(/SVG error: unable to parse "asdfasdf"/));
         assert.equal(svg, undefined);
         done();
       });
@@ -173,7 +173,7 @@ describe('mapnik.Image SVG', function() {
     it('should err with async non-existent file', function(done) {
       mapnik.Image.fromSVG('./test/data/SVG_DOES_NOT_EXIST.svg', function(err, svg) {
         assert.ok(err);
-        assert.ok(err.message.match(/SVG parse error:\s+Unable to open '.\/test\/data\/SVG_DOES_NOT_EXIST.svg'/));
+        assert.ok(err.message.match(/SVG error: unable to open "\.\/test\/data\/SVG_DOES_NOT_EXIST\.svg"/));
         assert.equal(svg, undefined);
         done();
       });
@@ -196,7 +196,7 @@ describe('mapnik.Image SVG', function() {
         assert.equal(img.height(), 256);
         assert.equal(img.encodeSync('png32').length, 17571);
     });
-    
+
     it('#fromSVGSync load from SVG file - 2', function() {
         var img = mapnik.Image.fromSVG('./test/data/vector_tile/tile0.expected-svg.svg');
         assert.ok(img);
diff --git a/test/vector-tile.test.js b/test/vector-tile.test.js
index 95190d2..e1c0ab1 100644
--- a/test/vector-tile.test.js
+++ b/test/vector-tile.test.js
@@ -906,7 +906,7 @@ describe('mapnik.VectorTile ', function() {
     it('should be able to change tile coordinates and it change the extent', function(done) {
         var vtile = new mapnik.VectorTile(9,112,195);
         var extent = vtile.extent();
-        var expected = [-11271098.44281895, 4696291.017841229, -11192826.925854929, 4774562.534805248];
+        var expected = [-11271098.442818949, 4696291.017841229, -11192826.925854929, 4774562.534805249];
         // typically not different, but rounding can cause different values
         // so we assert each value's difference is nominal
         assert(Math.abs(extent[0] - expected[0]) < 1e-8);
@@ -919,7 +919,7 @@ describe('mapnik.VectorTile ', function() {
         vtile.x = 0;
         assert.equal(vtile.x, 0);
         extent = vtile.extent();
-        var expected_x = [-20037508.342789244, 4696291.017841229, -19959236.825825226, 4774562.534805248];
+        var expected_x = [-20037508.342789244, 4696291.017841229, -19959236.82582522, 4774562.534805249];
         assert(Math.abs(extent[0] - expected_x[0]) < 1e-8);
         assert(Math.abs(extent[1] - expected_x[1]) < 1e-8);
         assert(Math.abs(extent[2] - expected_x[2]) < 1e-8);
@@ -927,7 +927,7 @@ describe('mapnik.VectorTile ', function() {
         vtile.y = 0;
         assert.equal(vtile.y, 0);
         extent = vtile.extent();
-        var expected_y = [-20037508.342789244, 19959236.825825218, -19959236.825825226, 20037508.342789277];
+        var expected_y = [-20037508.342789244, 19959236.82582522, -19959236.82582522, 20037508.342789244];
         assert(Math.abs(extent[0] - expected_y[0]) < 1e-8);
         assert(Math.abs(extent[1] - expected_y[1]) < 1e-8);
         assert(Math.abs(extent[2] - expected_y[2]) < 1e-8);
@@ -935,7 +935,7 @@ describe('mapnik.VectorTile ', function() {
         vtile.z = 0;
         assert.equal(vtile.z, 0);
         extent = vtile.extent();
-        var expected_z = [-20037508.342789244, -20037508.34278924, 20037508.342789244, 20037508.342789277];
+        var expected_z = [-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244];
         assert(Math.abs(extent[0] - expected_z[0]) < 1e-8);
         assert(Math.abs(extent[1] - expected_z[1]) < 1e-8);
         assert(Math.abs(extent[2] - expected_z[2]) < 1e-8);
@@ -2493,7 +2493,7 @@ describe('mapnik.VectorTile ', function() {
                 var simplicityReport = vtile.reportGeometrySimplicity();
                 var validityReport = vtile.reportGeometryValidity();
                 assert.equal(simplicityReport.length, 0);
-                assert.equal(validityReport.length, 1);
+                assert.equal(validityReport.length, 0);
                 assert.equal(vtile.reportGeometryValidity({split_multi_features:true}).length, 0);
             }
             var expected = './test/data/vector_tile/tile0-mpu-true.mvt';

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/node-mapnik.git



More information about the Pkg-javascript-commits mailing list