Full Code of chadnickbok/librtcdcpp for AI

master 2fe92c38b48b cached
41 files
457.9 KB
114.9k tokens
259 symbols
1 requests
Download .txt
Showing preview only (476K chars total). Download the full file or copy to clipboard to get everything.
Repository: chadnickbok/librtcdcpp
Branch: master
Commit: 2fe92c38b48b
Files: 41
Total size: 457.9 KB

Directory structure:
gitextract_u2ocm4ci/

├── .clang-format
├── .gitignore
├── CMakeLists.txt
├── LICENSE.md
├── README.md
├── cmake/
│   └── Modules/
│       ├── FindGLIB.cmake
│       ├── FindLibNice.cmake
│       ├── FindSpdlog.cmake
│       └── FindUsrSCTP.cmake
├── examples/
│   ├── README.md
│   ├── site-api.py
│   ├── static/
│   │   ├── adapter.js
│   │   ├── demo.css
│   │   └── index.html
│   └── websocket_client/
│       ├── CMakeLists.txt
│       ├── WebSocketWrapper.cpp
│       ├── WebSocketWrapper.hpp
│       ├── easywsclient.cpp
│       ├── easywsclient.hpp
│       ├── json/
│       │   ├── json-forwards.h
│       │   └── json.h
│       ├── jsoncpp.cpp
│       └── testclient.cpp
├── include/
│   └── rtcdcpp/
│       ├── Chunk.hpp
│       ├── ChunkQueue.hpp
│       ├── DTLSWrapper.hpp
│       ├── DataChannel.hpp
│       ├── Logging.hpp
│       ├── NiceWrapper.hpp
│       ├── PeerConnection.hpp
│       ├── RTCCertificate.hpp
│       ├── SCTPWrapper.hpp
│       └── librtcdcpp.h
└── src/
    ├── DTLSWrapper.cpp
    ├── DataChannel.cpp
    ├── Logging.cpp
    ├── NiceWrapper.cpp
    ├── PeerConnection.cpp
    ├── RTCCertificate.cpp
    ├── SCTPWrapper.cpp
    └── librtcdcpp.c

================================================
FILE CONTENTS
================================================

================================================
FILE: .clang-format
================================================
BasedOnStyle: Google
ColumnLimit: 150
Standard: Cpp11


================================================
FILE: .gitignore
================================================
/.idea/
/BUILD/
/examples/.env/
*.so
spdlog/
CMakeCache.txt
CMakeFiles/
Makefile
cmake_install.cmake
testclient


================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.0)

project(librtcdcpp
        VERSION 1.0.0
        LANGUAGES CXX)

option(DISABLE_SPDLOG "Disable Spdlog")

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_MACOSX_RPATH 1)

# Custom CMake modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules")

# Find packages
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(LibNice REQUIRED)
find_package(UsrSCTP REQUIRED)

set(LIB_HEADERS
        include/rtcdcpp/Chunk.hpp
        include/rtcdcpp/ChunkQueue.hpp
        include/rtcdcpp/DataChannel.hpp
        include/rtcdcpp/DTLSWrapper.hpp
        include/rtcdcpp/Logging.hpp
        include/rtcdcpp/NiceWrapper.hpp
        include/rtcdcpp/PeerConnection.hpp
        include/rtcdcpp/RTCCertificate.hpp
        include/rtcdcpp/SCTPWrapper.hpp)

set(LIB_SOURCES
        src/DataChannel.cpp
        src/DTLSWrapper.cpp
        src/Logging.cpp
        src/NiceWrapper.cpp
        src/PeerConnection.cpp
        src/RTCCertificate.cpp
        src/SCTPWrapper.cpp)

add_library(rtcdcpp SHARED
        ${LIB_HEADERS}
        ${LIB_SOURCES})

if (DISABLE_SPDLOG)
    message(STATUS "Spdlog is disabled. Use stubbed out logging")
    target_compile_definitions(rtcdcpp PUBLIC -DSPDLOG_DISABLED)
else ()
    find_package(Spdlog REQUIRED)
    target_link_libraries(rtcdcpp PUBLIC Gabime::Spdlog)
endif ()

target_include_directories(rtcdcpp
        PUBLIC
        ${PROJECT_SOURCE_DIR}/include)

target_link_libraries(rtcdcpp
        PUBLIC
        LibNice::LibNice
        SctpLab::UsrSCTP
        OpenSSL::SSL
        Threads::Threads)

# Declare a namespaced alias for used in other projects
add_library(LibRtcdcpp::LibRtcdcpp ALIAS rtcdcpp)

# Build examples
add_subdirectory(examples/websocket_client)


================================================
FILE: LICENSE.md
================================================
Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
  * Neither the name of the <organization> nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: README.md
================================================
librtcdcpp - A Simple WebRTC DataChannels Library
=================================================

librtcdcpp is a simple C++ implementation of the WebRTC DataChannels API.

It was originally written by [Andrew Gault](https://github.com/abgault) and [Nick Chadwick](https://github.com/chadnickbok), and was inspired in no small part by [librtcdc](https://github.com/xhs/librtcdc)

Its goal is to be the easiest way to build native WebRTC DataChannels apps across PC/Mac/Linux/iOS/Android.

Why
---

Because building the WebRTC libraries from Chromium can be a real PITA, and slimming it down to just DataChannels can be really tough.


Dependencies
------------

 - libnice - https://github.com/libnice/libnice
 - usrsctp - https://github.com/sctplab/usrsctp
 - openssl - https://www.openssl.org/
 - spdlog  - https://github.com/gabime/spdlog. Header-only. Optional.

Building
--------

On Linux:

**TODO**: deb and rpm packages

  ./configure
  make
  sudo make install

On Mac:

**TODO**: homebrew integration

  brew install ...
  ./configure
  make
  sudo make install


On Windows:

**TODO**: Visual studio integration, or a script like that jsoncpp library does

 - We recommend you just copy-paste the cpp and hpp files into your own project and go from there


Licensing
---------

BSD style - see the accompanying LICENSE file for more information


================================================
FILE: cmake/Modules/FindGLIB.cmake
================================================
# - Try to find Glib and its components (gio, gobject etc)
# Once done, this will define
#
#  GLIB_FOUND - system has Glib
#  GLIB_INCLUDE_DIRS - the Glib include directories
#  GLIB_LIBRARIES - link these to use Glib
#
# Optionally, the COMPONENTS keyword can be passed to find_package()
# and Glib components can be looked for.  Currently, the following
# components can be used, and they define the following variables if
# found:
#
#  gio:             GLIB_GIO_LIBRARIES
#  gobject:         GLIB_GOBJECT_LIBRARIES
#  gmodule:         GLIB_GMODULE_LIBRARIES
#  gthread:         GLIB_GTHREAD_LIBRARIES
#
# Note that the respective _INCLUDE_DIR variables are not set, since
# all headers are in the same directory as GLIB_INCLUDE_DIRS.
#
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

find_package(PkgConfig)
pkg_check_modules(PC_GLIB QUIET glib-2.0)

find_library(GLIB_LIBRARIES
    NAMES glib-2.0
    HINTS ${PC_GLIB_LIBDIR}
          ${PC_GLIB_LIBRARY_DIRS}
)

# Files in glib's main include path may include glibconfig.h, which,
# for some odd reason, is normally in $LIBDIR/glib-2.0/include.
get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH)
find_path(GLIBCONFIG_INCLUDE_DIR
    NAMES glibconfig.h
    HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR}
          ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS}
    PATH_SUFFIXES glib-2.0/include
)

find_path(GLIB_INCLUDE_DIR
    NAMES glib.h
    HINTS ${PC_GLIB_INCLUDEDIR}
          ${PC_GLIB_INCLUDE_DIRS}
    PATH_SUFFIXES glib-2.0
)

set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR})

# Version detection
if (EXISTS "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h")
    file(READ "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h" GLIBCONFIG_H_CONTENTS)
    string(REGEX MATCH "#define GLIB_MAJOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
    set(GLIB_VERSION_MAJOR "${CMAKE_MATCH_1}")
    string(REGEX MATCH "#define GLIB_MINOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
    set(GLIB_VERSION_MINOR "${CMAKE_MATCH_1}")
    string(REGEX MATCH "#define GLIB_MICRO_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
    set(GLIB_VERSION_MICRO "${CMAKE_MATCH_1}")
    set(GLIB_VERSION "${GLIB_VERSION_MAJOR}.${GLIB_VERSION_MINOR}.${GLIB_VERSION_MICRO}")
endif ()

# Additional Glib components.  We only look for libraries, as not all of them
# have corresponding headers and all headers are installed alongside the main
# glib ones.
foreach (_component ${GLIB_FIND_COMPONENTS})
    if (${_component} STREQUAL "gio")
        find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR})
        set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GIO_LIBRARIES)
    elseif (${_component} STREQUAL "gobject")
        find_library(GLIB_GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${_GLIB_LIBRARY_DIR})
        set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GOBJECT_LIBRARIES)
    elseif (${_component} STREQUAL "gmodule")
        find_library(GLIB_GMODULE_LIBRARIES NAMES gmodule-2.0 HINTS ${_GLIB_LIBRARY_DIR})
        set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GMODULE_LIBRARIES)
    elseif (${_component} STREQUAL "gthread")
        find_library(GLIB_GTHREAD_LIBRARIES NAMES gthread-2.0 HINTS ${_GLIB_LIBRARY_DIR})
        set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GTHREAD_LIBRARIES)
    elseif (${_component} STREQUAL "gio-unix")
        # gio-unix is compiled as part of the gio library, but the include paths
        # are separate from the shared glib ones. Since this is currently only used
        # by WebKitGTK+ we don't go to extraordinary measures beyond pkg-config.
        pkg_check_modules(GIO_UNIX QUIET gio-unix-2.0)
    endif ()
endforeach ()

include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLIB REQUIRED_VARS GLIB_INCLUDE_DIRS GLIB_LIBRARIES ${ADDITIONAL_REQUIRED_VARS}
                                       VERSION_VAR   GLIB_VERSION)

mark_as_advanced(
    GLIBCONFIG_INCLUDE_DIR
    GLIB_GIO_LIBRARIES
    GLIB_GIO_UNIX_LIBRARIES
    GLIB_GMODULE_LIBRARIES
    GLIB_GOBJECT_LIBRARIES
    GLIB_GTHREAD_LIBRARIES
    GLIB_INCLUDE_DIR
    GLIB_INCLUDE_DIRS
    GLIB_LIBRARIES
)


================================================
FILE: cmake/Modules/FindLibNice.cmake
================================================
if (NOT TARGET LibNice::LibNice)
    find_package(PkgConfig)
    pkg_check_modules(PC_LIBNICE nice)
    set(LIBNICE_DEFINITIONS ${PC_LIBNICE_CFLAGS_OTHER})

    find_path(LIBNICE_INCLUDE_DIR nice/agent.h
            HINTS ${PC_LIBNICE_INCLUDEDIR} ${PC_LIBNICE_INCLUDE_DIRS}
            PATH_SUFFICES libnice)
    find_library(LIBNICE_LIBRARY NAMES nice libnice
            HINTS ${PC_LIBNICE_LIBDIR} ${PC_LIBNICE_LIBRARY_DIRS})

    include(FindPackageHandleStandardArgs)
    find_package_handle_standard_args(Libnice DEFAULT_MSG
            LIBNICE_LIBRARY LIBNICE_INCLUDE_DIR)
    mark_as_advanced(LIBNICE_INCLUDE_DIR LIBNICE_LIBRARY)

    set(LIBNICE_LIBRARIES ${LIBNICE_LIBRARY})
    set(LIBNICE_INCLUDE_DIRS ${LIBNICE_INCLUDE_DIR})

    find_package(GLIB REQUIRED COMPONENTS gio gobject gmodule gthread)

    list(APPEND LIBNICE_INCLUDE_DIRS ${GLIB_INCLUDE_DIRS})
    list(APPEND LIBNICE_LIBRARIES ${GLIB_GOBJECT_LIBRARIES} ${GLIB_LIBRARIES})

    if (LIBNICE_FOUND)
        add_library(LibNice::LibNice UNKNOWN IMPORTED)
        set_target_properties(LibNice::LibNice PROPERTIES
                IMPORTED_LOCATION "${LIBNICE_LIBRARY}"
                INTERFACE_COMPILE_DEFINITIONS "_REENTRANT"
                INTERFACE_INCLUDE_DIRECTORIES "${LIBNICE_INCLUDE_DIRS}"
                INTERFACE_LINK_LIBRARIES "${LIBNICE_LIBRARIES}"
                IMPORTED_LINK_INTERFACE_LANGUAGES "C")
    endif ()
endif ()


================================================
FILE: cmake/Modules/FindSpdlog.cmake
================================================
if (NOT TARGET Gabime::Spdlog)
    include(FindPackageHandleStandardArgs)
    find_path(SPDLOG_INCLUDE_DIR NAMES spdlog/spdlog.h)
    find_package_handle_standard_args(Spdlog DEFAULT_MSG SPDLOG_INCLUDE_DIR)
    add_library(spdlog INTERFACE)
    target_include_directories(spdlog INTERFACE ${SPDLOG_INCLUDE_DIR})
    add_library(Gabime::Spdlog ALIAS spdlog)
endif ()


================================================
FILE: cmake/Modules/FindUsrSCTP.cmake
================================================
# Simple libnice cmake find

if (NOT TARGET SctpLab::UsrSCTP)
    set(USRSCTP_DEFINITIONS INET INET6)
    find_path(USRSCTP_INCLUDE_DIR usrsctp.h PATH_SUFFICES usrsctp)
    find_library(USRSCTP_LIBRARY NAMES usrsctp libusrsctp)

    include(FindPackageHandleStandardArgs)
    find_package_handle_standard_args(Usrsctp DEFAULT_MSG USRSCTP_LIBRARY USRSCTP_INCLUDE_DIR)

    mark_as_advanced(USRSCTP_INCLUDE_DIR USRSCTP_LIBRARY)

    set(USRSCTP_LIBRARIES ${USRSCTP_LIBRARY})
    set(USRSCTP_INCLUDE_DIRS ${USRSCTP_INCLUDE_DIR})

    if (USRSCTP_FOUND)
        add_library(SctpLab::UsrSCTP UNKNOWN IMPORTED)
        set_target_properties(SctpLab::UsrSCTP PROPERTIES
                IMPORTED_LOCATION "${USRSCTP_LIBRARY}"
                INTERFACE_COMPILE_DEFINITIONS "${USRSCTP_DEFINITIONS}"
                INTERFACE_INCLUDE_DIRECTORIES "${USRSCTP_INCLUDE_DIRS}"
                IMPORTED_LINK_INTERFACE_LANGUAGES "C")
    endif ()
endif ()


================================================
FILE: examples/README.md
================================================


Running the Demo
----------------

To run the demo, first run:

	cd examples
	python site-api.py

This should start a web server on localhost:5000

	Open http://localhost:5000
	Enter channel name "test"
	Click "connect" - This should show up in the python console

Then, run 

	build/examples/websocket_client/testclient - its important that this be started after the web browser has connected to the test channel.

You should then see a whole heap of ICE messages, followed by a "Hello from native code"


================================================
FILE: examples/site-api.py
================================================
#!/usr/bin/env python
# Sets up a basic site that can allow two browsers to connect to each
# other via WebRTC DataChannels, sending connection events via WebSockets.


from flask import Flask, send_from_directory
from flask_sockets import Sockets
import json

app = Flask(__name__)
sockets = Sockets(app)

channels = {}

@sockets.route('/channel/<name>')
def channel_socket(ws, name):
    if name in channels:
        channels[name].append(ws)
    else:
        channels[name] = [ws]

    print("Got new websocket on channel", name)

    ws.send(json.dumps({"type": "hello", "msg": "From the server"}))

    while not ws.closed:
        message = ws.receive()
        print("Got msg:", message)

        if message is None:
            continue

        for other_ws in channels[name]:
            if ws is not other_ws:
                other_ws.send(message)

    channels[name].remove(ws)
    for other_ws in channels[name]:
        other_ws.send(json.dumps({"type": "client_disconnected", "msg": {}}))


@app.route('/static/<path:path>')
def send_static(path):
    return app.send_from_directory('static', path)


@app.route('/')
def serve_site():
    return app.send_static_file("index.html")


if __name__ == "__main__":
    from gevent import pywsgi
    from geventwebsocket.handler import WebSocketHandler
    server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
    server.serve_forever()


================================================
FILE: examples/static/adapter.js
================================================
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
 /* eslint-env node */
'use strict';

// SDP helpers.
var SDPUtils = {};

// Generate an alphanumeric identifier for cname or mids.
// TODO: use UUIDs instead? https://gist.github.com/jed/982883
SDPUtils.generateIdentifier = function() {
  return Math.random().toString(36).substr(2, 10);
};

// The RTCP CNAME used by all peerconnections from the same JS.
SDPUtils.localCName = SDPUtils.generateIdentifier();

// Splits SDP into lines, dealing with both CRLF and LF.
SDPUtils.splitLines = function(blob) {
  return blob.trim().split('\n').map(function(line) {
    return line.trim();
  });
};
// Splits SDP into sessionpart and mediasections. Ensures CRLF.
SDPUtils.splitSections = function(blob) {
  var parts = blob.split('\nm=');
  return parts.map(function(part, index) {
    return (index > 0 ? 'm=' + part : part).trim() + '\r\n';
  });
};

// Returns lines that start with a certain prefix.
SDPUtils.matchPrefix = function(blob, prefix) {
  return SDPUtils.splitLines(blob).filter(function(line) {
    return line.indexOf(prefix) === 0;
  });
};

// Parses an ICE candidate line. Sample input:
// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8
// rport 55996"
SDPUtils.parseCandidate = function(line) {
  var parts;
  // Parse both variants.
  if (line.indexOf('a=candidate:') === 0) {
    parts = line.substring(12).split(' ');
  } else {
    parts = line.substring(10).split(' ');
  }

  var candidate = {
    foundation: parts[0],
    component: parts[1],
    protocol: parts[2].toLowerCase(),
    priority: parseInt(parts[3], 10),
    ip: parts[4],
    port: parseInt(parts[5], 10),
    // skip parts[6] == 'typ'
    type: parts[7]
  };

  for (var i = 8; i < parts.length; i += 2) {
    switch (parts[i]) {
      case 'raddr':
        candidate.relatedAddress = parts[i + 1];
        break;
      case 'rport':
        candidate.relatedPort = parseInt(parts[i + 1], 10);
        break;
      case 'tcptype':
        candidate.tcpType = parts[i + 1];
        break;
      default: // Unknown extensions are silently ignored.
        break;
    }
  }
  return candidate;
};

// Translates a candidate object into SDP candidate attribute.
SDPUtils.writeCandidate = function(candidate) {
  var sdp = [];
  sdp.push(candidate.foundation);
  sdp.push(candidate.component);
  sdp.push(candidate.protocol.toUpperCase());
  sdp.push(candidate.priority);
  sdp.push(candidate.ip);
  sdp.push(candidate.port);

  var type = candidate.type;
  sdp.push('typ');
  sdp.push(type);
  if (type !== 'host' && candidate.relatedAddress &&
      candidate.relatedPort) {
    sdp.push('raddr');
    sdp.push(candidate.relatedAddress); // was: relAddr
    sdp.push('rport');
    sdp.push(candidate.relatedPort); // was: relPort
  }
  if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {
    sdp.push('tcptype');
    sdp.push(candidate.tcpType);
  }
  return 'candidate:' + sdp.join(' ');
};

// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input:
// a=rtpmap:111 opus/48000/2
SDPUtils.parseRtpMap = function(line) {
  var parts = line.substr(9).split(' ');
  var parsed = {
    payloadType: parseInt(parts.shift(), 10) // was: id
  };

  parts = parts[0].split('/');

  parsed.name = parts[0];
  parsed.clockRate = parseInt(parts[1], 10); // was: clockrate
  // was: channels
  parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1;
  return parsed;
};

// Generate an a=rtpmap line from RTCRtpCodecCapability or
// RTCRtpCodecParameters.
SDPUtils.writeRtpMap = function(codec) {
  var pt = codec.payloadType;
  if (codec.preferredPayloadType !== undefined) {
    pt = codec.preferredPayloadType;
  }
  return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +
      (codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n';
};

// Parses an a=extmap line (headerextension from RFC 5285). Sample input:
// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
SDPUtils.parseExtmap = function(line) {
  var parts = line.substr(9).split(' ');
  return {
    id: parseInt(parts[0], 10),
    uri: parts[1]
  };
};

// Generates a=extmap line from RTCRtpHeaderExtensionParameters or
// RTCRtpHeaderExtension.
SDPUtils.writeExtmap = function(headerExtension) {
  return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) +
       ' ' + headerExtension.uri + '\r\n';
};

// Parses an ftmp line, returns dictionary. Sample input:
// a=fmtp:96 vbr=on;cng=on
// Also deals with vbr=on; cng=on
SDPUtils.parseFmtp = function(line) {
  var parsed = {};
  var kv;
  var parts = line.substr(line.indexOf(' ') + 1).split(';');
  for (var j = 0; j < parts.length; j++) {
    kv = parts[j].trim().split('=');
    parsed[kv[0].trim()] = kv[1];
  }
  return parsed;
};

// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters.
SDPUtils.writeFmtp = function(codec) {
  var line = '';
  var pt = codec.payloadType;
  if (codec.preferredPayloadType !== undefined) {
    pt = codec.preferredPayloadType;
  }
  if (codec.parameters && Object.keys(codec.parameters).length) {
    var params = [];
    Object.keys(codec.parameters).forEach(function(param) {
      params.push(param + '=' + codec.parameters[param]);
    });
    line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n';
  }
  return line;
};

// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:
// a=rtcp-fb:98 nack rpsi
SDPUtils.parseRtcpFb = function(line) {
  var parts = line.substr(line.indexOf(' ') + 1).split(' ');
  return {
    type: parts.shift(),
    parameter: parts.join(' ')
  };
};
// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.
SDPUtils.writeRtcpFb = function(codec) {
  var lines = '';
  var pt = codec.payloadType;
  if (codec.preferredPayloadType !== undefined) {
    pt = codec.preferredPayloadType;
  }
  if (codec.rtcpFeedback && codec.rtcpFeedback.length) {
    // FIXME: special handling for trr-int?
    codec.rtcpFeedback.forEach(function(fb) {
      lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + ' ' + fb.parameter +
          '\r\n';
    });
  }
  return lines;
};

// Parses an RFC 5576 ssrc media attribute. Sample input:
// a=ssrc:3735928559 cname:something
SDPUtils.parseSsrcMedia = function(line) {
  var sp = line.indexOf(' ');
  var parts = {
    ssrc: parseInt(line.substr(7, sp - 7), 10)
  };
  var colon = line.indexOf(':', sp);
  if (colon > -1) {
    parts.attribute = line.substr(sp + 1, colon - sp - 1);
    parts.value = line.substr(colon + 1);
  } else {
    parts.attribute = line.substr(sp + 1);
  }
  return parts;
};

// Extracts DTLS parameters from SDP media section or sessionpart.
// FIXME: for consistency with other functions this should only
//   get the fingerprint line as input. See also getIceParameters.
SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {
  var lines = SDPUtils.splitLines(mediaSection);
  // Search in session part, too.
  lines = lines.concat(SDPUtils.splitLines(sessionpart));
  var fpLine = lines.filter(function(line) {
    return line.indexOf('a=fingerprint:') === 0;
  })[0].substr(14);
  // Note: a=setup line is ignored since we use the 'auto' role.
  var dtlsParameters = {
    role: 'auto',
    fingerprints: [{
      algorithm: fpLine.split(' ')[0],
      value: fpLine.split(' ')[1]
    }]
  };
  return dtlsParameters;
};

// Serializes DTLS parameters to SDP.
SDPUtils.writeDtlsParameters = function(params, setupType) {
  var sdp = 'a=setup:' + setupType + '\r\n';
  params.fingerprints.forEach(function(fp) {
    sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n';
  });
  return sdp;
};
// Parses ICE information from SDP media section or sessionpart.
// FIXME: for consistency with other functions this should only
//   get the ice-ufrag and ice-pwd lines as input.
SDPUtils.getIceParameters = function(mediaSection, sessionpart) {
  var lines = SDPUtils.splitLines(mediaSection);
  // Search in session part, too.
  lines = lines.concat(SDPUtils.splitLines(sessionpart));
  var iceParameters = {
    usernameFragment: lines.filter(function(line) {
      return line.indexOf('a=ice-ufrag:') === 0;
    })[0].substr(12),
    password: lines.filter(function(line) {
      return line.indexOf('a=ice-pwd:') === 0;
    })[0].substr(10)
  };
  return iceParameters;
};

// Serializes ICE parameters to SDP.
SDPUtils.writeIceParameters = function(params) {
  return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' +
      'a=ice-pwd:' + params.password + '\r\n';
};

// Parses the SDP media section and returns RTCRtpParameters.
SDPUtils.parseRtpParameters = function(mediaSection) {
  var description = {
    codecs: [],
    headerExtensions: [],
    fecMechanisms: [],
    rtcp: []
  };
  var lines = SDPUtils.splitLines(mediaSection);
  var mline = lines[0].split(' ');
  for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..]
    var pt = mline[i];
    var rtpmapline = SDPUtils.matchPrefix(
        mediaSection, 'a=rtpmap:' + pt + ' ')[0];
    if (rtpmapline) {
      var codec = SDPUtils.parseRtpMap(rtpmapline);
      var fmtps = SDPUtils.matchPrefix(
          mediaSection, 'a=fmtp:' + pt + ' ');
      // Only the first a=fmtp:<pt> is considered.
      codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};
      codec.rtcpFeedback = SDPUtils.matchPrefix(
          mediaSection, 'a=rtcp-fb:' + pt + ' ')
        .map(SDPUtils.parseRtcpFb);
      description.codecs.push(codec);
      // parse FEC mechanisms from rtpmap lines.
      switch (codec.name.toUpperCase()) {
        case 'RED':
        case 'ULPFEC':
          description.fecMechanisms.push(codec.name.toUpperCase());
          break;
        default: // only RED and ULPFEC are recognized as FEC mechanisms.
          break;
      }
    }
  }
  SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) {
    description.headerExtensions.push(SDPUtils.parseExtmap(line));
  });
  // FIXME: parse rtcp.
  return description;
};

// Generates parts of the SDP media section describing the capabilities /
// parameters.
SDPUtils.writeRtpDescription = function(kind, caps) {
  var sdp = '';

  // Build the mline.
  sdp += 'm=' + kind + ' ';
  sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.
  sdp += ' UDP/TLS/RTP/SAVPF ';
  sdp += caps.codecs.map(function(codec) {
    if (codec.preferredPayloadType !== undefined) {
      return codec.preferredPayloadType;
    }
    return codec.payloadType;
  }).join(' ') + '\r\n';

  sdp += 'c=IN IP4 0.0.0.0\r\n';
  sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n';

  // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.
  caps.codecs.forEach(function(codec) {
    sdp += SDPUtils.writeRtpMap(codec);
    sdp += SDPUtils.writeFmtp(codec);
    sdp += SDPUtils.writeRtcpFb(codec);
  });
  // FIXME: add headerExtensions, fecMechanismş and rtcp.
  sdp += 'a=rtcp-mux\r\n';
  return sdp;
};

// Parses the SDP media section and returns an array of
// RTCRtpEncodingParameters.
SDPUtils.parseRtpEncodingParameters = function(mediaSection) {
  var encodingParameters = [];
  var description = SDPUtils.parseRtpParameters(mediaSection);
  var hasRed = description.fecMechanisms.indexOf('RED') !== -1;
  var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;

  // filter a=ssrc:... cname:, ignore PlanB-msid
  var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
  .map(function(line) {
    return SDPUtils.parseSsrcMedia(line);
  })
  .filter(function(parts) {
    return parts.attribute === 'cname';
  });
  var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;
  var secondarySsrc;

  var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')
  .map(function(line) {
    var parts = line.split(' ');
    parts.shift();
    return parts.map(function(part) {
      return parseInt(part, 10);
    });
  });
  if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {
    secondarySsrc = flows[0][1];
  }

  description.codecs.forEach(function(codec) {
    if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {
      var encParam = {
        ssrc: primarySsrc,
        codecPayloadType: parseInt(codec.parameters.apt, 10),
        rtx: {
          payloadType: codec.payloadType,
          ssrc: secondarySsrc
        }
      };
      encodingParameters.push(encParam);
      if (hasRed) {
        encParam = JSON.parse(JSON.stringify(encParam));
        encParam.fec = {
          ssrc: secondarySsrc,
          mechanism: hasUlpfec ? 'red+ulpfec' : 'red'
        };
        encodingParameters.push(encParam);
      }
    }
  });
  if (encodingParameters.length === 0 && primarySsrc) {
    encodingParameters.push({
      ssrc: primarySsrc
    });
  }

  // we support both b=AS and b=TIAS but interpret AS as TIAS.
  var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');
  if (bandwidth.length) {
    if (bandwidth[0].indexOf('b=TIAS:') === 0) {
      bandwidth = parseInt(bandwidth[0].substr(7), 10);
    } else if (bandwidth[0].indexOf('b=AS:') === 0) {
      bandwidth = parseInt(bandwidth[0].substr(5), 10);
    }
    encodingParameters.forEach(function(params) {
      params.maxBitrate = bandwidth;
    });
  }
  return encodingParameters;
};

SDPUtils.writeSessionBoilerplate = function() {
  // FIXME: sess-id should be an NTP timestamp.
  return 'v=0\r\n' +
      'o=thisisadapterortc 8169639915646943137 2 IN IP4 127.0.0.1\r\n' +
      's=-\r\n' +
      't=0 0\r\n';
};

SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) {
  var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps);

  // Map ICE parameters (ufrag, pwd) to SDP.
  sdp += SDPUtils.writeIceParameters(
      transceiver.iceGatherer.getLocalParameters());

  // Map DTLS parameters to SDP.
  sdp += SDPUtils.writeDtlsParameters(
      transceiver.dtlsTransport.getLocalParameters(),
      type === 'offer' ? 'actpass' : 'active');

  sdp += 'a=mid:' + transceiver.mid + '\r\n';

  if (transceiver.rtpSender && transceiver.rtpReceiver) {
    sdp += 'a=sendrecv\r\n';
  } else if (transceiver.rtpSender) {
    sdp += 'a=sendonly\r\n';
  } else if (transceiver.rtpReceiver) {
    sdp += 'a=recvonly\r\n';
  } else {
    sdp += 'a=inactive\r\n';
  }

  // FIXME: for RTX there might be multiple SSRCs. Not implemented in Edge yet.
  if (transceiver.rtpSender) {
    var msid = 'msid:' + stream.id + ' ' +
        transceiver.rtpSender.track.id + '\r\n';
    sdp += 'a=' + msid;
    sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
        ' ' + msid;
  }
  // FIXME: this should be written by writeRtpDescription.
  sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
      ' cname:' + SDPUtils.localCName + '\r\n';
  return sdp;
};

// Gets the direction from the mediaSection or the sessionpart.
SDPUtils.getDirection = function(mediaSection, sessionpart) {
  // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.
  var lines = SDPUtils.splitLines(mediaSection);
  for (var i = 0; i < lines.length; i++) {
    switch (lines[i]) {
      case 'a=sendrecv':
      case 'a=sendonly':
      case 'a=recvonly':
      case 'a=inactive':
        return lines[i].substr(2);
      default:
        // FIXME: What should happen here?
    }
  }
  if (sessionpart) {
    return SDPUtils.getDirection(sessionpart);
  }
  return 'sendrecv';
};

// Expose public methods.
module.exports = SDPUtils;

},{}],2:[function(require,module,exports){
/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */

'use strict';

// Shimming starts here.
(function() {
  // Utils.
  var logging = require('./utils').log;
  var browserDetails = require('./utils').browserDetails;
  // Export to the adapter global object visible in the browser.
  module.exports.browserDetails = browserDetails;
  module.exports.extractVersion = require('./utils').extractVersion;
  module.exports.disableLog = require('./utils').disableLog;

  // Uncomment the line below if you want logging to occur, including logging
  // for the switch statement below. Can also be turned on in the browser via
  // adapter.disableLog(false), but then logging from the switch statement below
  // will not appear.
  // require('./utils').disableLog(false);

  // Browser shims.
  var chromeShim = require('./chrome/chrome_shim') || null;
  var edgeShim = require('./edge/edge_shim') || null;
  var firefoxShim = require('./firefox/firefox_shim') || null;
  var safariShim = require('./safari/safari_shim') || null;

  // Shim browser if found.
  switch (browserDetails.browser) {
    case 'opera': // fallthrough as it uses chrome shims
    case 'chrome':
      if (!chromeShim || !chromeShim.shimPeerConnection) {
        logging('Chrome shim is not included in this adapter release.');
        return;
      }
      logging('adapter.js shimming chrome.');
      // Export to the adapter global object visible in the browser.
      module.exports.browserShim = chromeShim;

      chromeShim.shimGetUserMedia();
      chromeShim.shimMediaStream();
      chromeShim.shimSourceObject();
      chromeShim.shimPeerConnection();
      chromeShim.shimOnTrack();
      break;
    case 'firefox':
      if (!firefoxShim || !firefoxShim.shimPeerConnection) {
        logging('Firefox shim is not included in this adapter release.');
        return;
      }
      logging('adapter.js shimming firefox.');
      // Export to the adapter global object visible in the browser.
      module.exports.browserShim = firefoxShim;

      firefoxShim.shimGetUserMedia();
      firefoxShim.shimSourceObject();
      firefoxShim.shimPeerConnection();
      firefoxShim.shimOnTrack();
      break;
    case 'edge':
      if (!edgeShim || !edgeShim.shimPeerConnection) {
        logging('MS edge shim is not included in this adapter release.');
        return;
      }
      logging('adapter.js shimming edge.');
      // Export to the adapter global object visible in the browser.
      module.exports.browserShim = edgeShim;

      edgeShim.shimGetUserMedia();
      edgeShim.shimPeerConnection();
      break;
    case 'safari':
      if (!safariShim) {
        logging('Safari shim is not included in this adapter release.');
        return;
      }
      logging('adapter.js shimming safari.');
      // Export to the adapter global object visible in the browser.
      module.exports.browserShim = safariShim;

      safariShim.shimGetUserMedia();
      break;
    default:
      logging('Unsupported browser!');
  }
})();

},{"./chrome/chrome_shim":3,"./edge/edge_shim":5,"./firefox/firefox_shim":7,"./safari/safari_shim":9,"./utils":10}],3:[function(require,module,exports){

/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */
'use strict';
var logging = require('../utils.js').log;
var browserDetails = require('../utils.js').browserDetails;

var chromeShim = {
  shimMediaStream: function() {
    window.MediaStream = window.MediaStream || window.webkitMediaStream;
  },

  shimOnTrack: function() {
    if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in
        window.RTCPeerConnection.prototype)) {
      Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
        get: function() {
          return this._ontrack;
        },
        set: function(f) {
          var self = this;
          if (this._ontrack) {
            this.removeEventListener('track', this._ontrack);
            this.removeEventListener('addstream', this._ontrackpoly);
          }
          this.addEventListener('track', this._ontrack = f);
          this.addEventListener('addstream', this._ontrackpoly = function(e) {
            // onaddstream does not fire when a track is added to an existing
            // stream. But stream.onaddtrack is implemented so we use that.
            e.stream.addEventListener('addtrack', function(te) {
              var event = new Event('track');
              event.track = te.track;
              event.receiver = {track: te.track};
              event.streams = [e.stream];
              self.dispatchEvent(event);
            });
            e.stream.getTracks().forEach(function(track) {
              var event = new Event('track');
              event.track = track;
              event.receiver = {track: track};
              event.streams = [e.stream];
              this.dispatchEvent(event);
            }.bind(this));
          }.bind(this));
        }
      });
    }
  },

  shimSourceObject: function() {
    if (typeof window === 'object') {
      if (window.HTMLMediaElement &&
        !('srcObject' in window.HTMLMediaElement.prototype)) {
        // Shim the srcObject property, once, when HTMLMediaElement is found.
        Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
          get: function() {
            return this._srcObject;
          },
          set: function(stream) {
            var self = this;
            // Use _srcObject as a private property for this shim
            this._srcObject = stream;
            if (this.src) {
              URL.revokeObjectURL(this.src);
            }

            if (!stream) {
              this.src = '';
              return;
            }
            this.src = URL.createObjectURL(stream);
            // We need to recreate the blob url when a track is added or
            // removed. Doing it manually since we want to avoid a recursion.
            stream.addEventListener('addtrack', function() {
              if (self.src) {
                URL.revokeObjectURL(self.src);
              }
              self.src = URL.createObjectURL(stream);
            });
            stream.addEventListener('removetrack', function() {
              if (self.src) {
                URL.revokeObjectURL(self.src);
              }
              self.src = URL.createObjectURL(stream);
            });
          }
        });
      }
    }
  },

  shimPeerConnection: function() {
    // The RTCPeerConnection object.
    window.RTCPeerConnection = function(pcConfig, pcConstraints) {
      // Translate iceTransportPolicy to iceTransports,
      // see https://code.google.com/p/webrtc/issues/detail?id=4869
      logging('PeerConnection');
      if (pcConfig && pcConfig.iceTransportPolicy) {
        pcConfig.iceTransports = pcConfig.iceTransportPolicy;
      }

      var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints);
      var origGetStats = pc.getStats.bind(pc);
      pc.getStats = function(selector, successCallback, errorCallback) {
        var self = this;
        var args = arguments;

        // If selector is a function then we are in the old style stats so just
        // pass back the original getStats format to avoid breaking old users.
        if (arguments.length > 0 && typeof selector === 'function') {
          return origGetStats(selector, successCallback);
        }

        var fixChromeStats_ = function(response) {
          var standardReport = {};
          var reports = response.result();
          reports.forEach(function(report) {
            var standardStats = {
              id: report.id,
              timestamp: report.timestamp,
              type: report.type
            };
            report.names().forEach(function(name) {
              standardStats[name] = report.stat(name);
            });
            standardReport[standardStats.id] = standardStats;
          });

          return standardReport;
        };

        // shim getStats with maplike support
        var makeMapStats = function(stats, legacyStats) {
          var map = new Map(Object.keys(stats).map(function(key) {
            return[key, stats[key]];
          }));
          legacyStats = legacyStats || stats;
          Object.keys(legacyStats).forEach(function(key) {
            map[key] = legacyStats[key];
          });
          return map;
        };

        if (arguments.length >= 2) {
          var successCallbackWrapper_ = function(response) {
            args[1](makeMapStats(fixChromeStats_(response)));
          };

          return origGetStats.apply(this, [successCallbackWrapper_,
              arguments[0]]);
        }

        // promise-support
        return new Promise(function(resolve, reject) {
          if (args.length === 1 && typeof selector === 'object') {
            origGetStats.apply(self, [
              function(response) {
                resolve(makeMapStats(fixChromeStats_(response)));
              }, reject]);
          } else {
            // Preserve legacy chrome stats only on legacy access of stats obj
            origGetStats.apply(self, [
              function(response) {
                resolve(makeMapStats(fixChromeStats_(response),
                    response.result()));
              }, reject]);
          }
        }).then(successCallback, errorCallback);
      };

      return pc;
    };
    window.RTCPeerConnection.prototype = webkitRTCPeerConnection.prototype;

    // wrap static methods. Currently just generateCertificate.
    if (webkitRTCPeerConnection.generateCertificate) {
      Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
        get: function() {
          return webkitRTCPeerConnection.generateCertificate;
        }
      });
    }

    ['createOffer', 'createAnswer'].forEach(function(method) {
      var nativeMethod = webkitRTCPeerConnection.prototype[method];
      webkitRTCPeerConnection.prototype[method] = function() {
        var self = this;
        if (arguments.length < 1 || (arguments.length === 1 &&
            typeof arguments[0] === 'object')) {
          var opts = arguments.length === 1 ? arguments[0] : undefined;
          return new Promise(function(resolve, reject) {
            nativeMethod.apply(self, [resolve, reject, opts]);
          });
        }
        return nativeMethod.apply(this, arguments);
      };
    });

    // add promise support -- natively available in Chrome 51
    if (browserDetails.version < 51) {
      ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
          .forEach(function(method) {
            var nativeMethod = webkitRTCPeerConnection.prototype[method];
            webkitRTCPeerConnection.prototype[method] = function() {
              var args = arguments;
              var self = this;
              var promise = new Promise(function(resolve, reject) {
                nativeMethod.apply(self, [args[0], resolve, reject]);
              });
              if (args.length < 2) {
                return promise;
              }
              return promise.then(function() {
                args[1].apply(null, []);
              },
              function(err) {
                if (args.length >= 3) {
                  args[2].apply(null, [err]);
                }
              });
            };
          });
    }

    // support for addIceCandidate(null)
    var nativeAddIceCandidate =
        RTCPeerConnection.prototype.addIceCandidate;
    RTCPeerConnection.prototype.addIceCandidate = function() {
      return arguments[0] === null ? Promise.resolve()
          : nativeAddIceCandidate.apply(this, arguments);
    };

    // shim implicit creation of RTCSessionDescription/RTCIceCandidate
    ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
        .forEach(function(method) {
          var nativeMethod = webkitRTCPeerConnection.prototype[method];
          webkitRTCPeerConnection.prototype[method] = function() {
            arguments[0] = new ((method === 'addIceCandidate') ?
                RTCIceCandidate : RTCSessionDescription)(arguments[0]);
            return nativeMethod.apply(this, arguments);
          };
        });
  },

  // Attach a media stream to an element.
  attachMediaStream: function(element, stream) {
    logging('DEPRECATED, attachMediaStream will soon be removed.');
    if (browserDetails.version >= 43) {
      element.srcObject = stream;
    } else if (typeof element.src !== 'undefined') {
      element.src = URL.createObjectURL(stream);
    } else {
      logging('Error attaching stream to element.');
    }
  },

  reattachMediaStream: function(to, from) {
    logging('DEPRECATED, reattachMediaStream will soon be removed.');
    if (browserDetails.version >= 43) {
      to.srcObject = from.srcObject;
    } else {
      to.src = from.src;
    }
  }
};


// Expose public methods.
module.exports = {
  shimMediaStream: chromeShim.shimMediaStream,
  shimOnTrack: chromeShim.shimOnTrack,
  shimSourceObject: chromeShim.shimSourceObject,
  shimPeerConnection: chromeShim.shimPeerConnection,
  shimGetUserMedia: require('./getusermedia'),
  attachMediaStream: chromeShim.attachMediaStream,
  reattachMediaStream: chromeShim.reattachMediaStream
};

},{"../utils.js":10,"./getusermedia":4}],4:[function(require,module,exports){
/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */
'use strict';
var logging = require('../utils.js').log;

// Expose public methods.
module.exports = function() {
  var constraintsToChrome_ = function(c) {
    if (typeof c !== 'object' || c.mandatory || c.optional) {
      return c;
    }
    var cc = {};
    Object.keys(c).forEach(function(key) {
      if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
        return;
      }
      var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]};
      if (r.exact !== undefined && typeof r.exact === 'number') {
        r.min = r.max = r.exact;
      }
      var oldname_ = function(prefix, name) {
        if (prefix) {
          return prefix + name.charAt(0).toUpperCase() + name.slice(1);
        }
        return (name === 'deviceId') ? 'sourceId' : name;
      };
      if (r.ideal !== undefined) {
        cc.optional = cc.optional || [];
        var oc = {};
        if (typeof r.ideal === 'number') {
          oc[oldname_('min', key)] = r.ideal;
          cc.optional.push(oc);
          oc = {};
          oc[oldname_('max', key)] = r.ideal;
          cc.optional.push(oc);
        } else {
          oc[oldname_('', key)] = r.ideal;
          cc.optional.push(oc);
        }
      }
      if (r.exact !== undefined && typeof r.exact !== 'number') {
        cc.mandatory = cc.mandatory || {};
        cc.mandatory[oldname_('', key)] = r.exact;
      } else {
        ['min', 'max'].forEach(function(mix) {
          if (r[mix] !== undefined) {
            cc.mandatory = cc.mandatory || {};
            cc.mandatory[oldname_(mix, key)] = r[mix];
          }
        });
      }
    });
    if (c.advanced) {
      cc.optional = (cc.optional || []).concat(c.advanced);
    }
    return cc;
  };

  var shimConstraints_ = function(constraints, func) {
    constraints = JSON.parse(JSON.stringify(constraints));
    if (constraints && constraints.audio) {
      constraints.audio = constraintsToChrome_(constraints.audio);
    }
    if (constraints && typeof constraints.video === 'object') {
      // Shim facingMode for mobile, where it defaults to "user".
      var face = constraints.video.facingMode;
      face = face && ((typeof face === 'object') ? face : {ideal: face});

      if ((face && (face.exact === 'user' || face.exact === 'environment' ||
                    face.ideal === 'user' || face.ideal === 'environment')) &&
          !(navigator.mediaDevices.getSupportedConstraints &&
            navigator.mediaDevices.getSupportedConstraints().facingMode)) {
        delete constraints.video.facingMode;
        if (face.exact === 'environment' || face.ideal === 'environment') {
          // Look for "back" in label, or use last cam (typically back cam).
          return navigator.mediaDevices.enumerateDevices()
          .then(function(devices) {
            devices = devices.filter(function(d) {
              return d.kind === 'videoinput';
            });
            var back = devices.find(function(d) {
              return d.label.toLowerCase().indexOf('back') !== -1;
            }) || (devices.length && devices[devices.length - 1]);
            if (back) {
              constraints.video.deviceId = face.exact ? {exact: back.deviceId} :
                                                        {ideal: back.deviceId};
            }
            constraints.video = constraintsToChrome_(constraints.video);
            logging('chrome: ' + JSON.stringify(constraints));
            return func(constraints);
          });
        }
      }
      constraints.video = constraintsToChrome_(constraints.video);
    }
    logging('chrome: ' + JSON.stringify(constraints));
    return func(constraints);
  };

  var shimError_ = function(e) {
    return {
      name: {
        PermissionDeniedError: 'NotAllowedError',
        ConstraintNotSatisfiedError: 'OverconstrainedError'
      }[e.name] || e.name,
      message: e.message,
      constraint: e.constraintName,
      toString: function() {
        return this.name + (this.message && ': ') + this.message;
      }
    };
  };

  var getUserMedia_ = function(constraints, onSuccess, onError) {
    shimConstraints_(constraints, function(c) {
      navigator.webkitGetUserMedia(c, onSuccess, function(e) {
        onError(shimError_(e));
      });
    });
  };

  navigator.getUserMedia = getUserMedia_;

  // Returns the result of getUserMedia as a Promise.
  var getUserMediaPromise_ = function(constraints) {
    return new Promise(function(resolve, reject) {
      navigator.getUserMedia(constraints, resolve, reject);
    });
  };

  if (!navigator.mediaDevices) {
    navigator.mediaDevices = {
      getUserMedia: getUserMediaPromise_,
      enumerateDevices: function() {
        return new Promise(function(resolve) {
          var kinds = {audio: 'audioinput', video: 'videoinput'};
          return MediaStreamTrack.getSources(function(devices) {
            resolve(devices.map(function(device) {
              return {label: device.label,
                      kind: kinds[device.kind],
                      deviceId: device.id,
                      groupId: ''};
            }));
          });
        });
      }
    };
  }

  // A shim for getUserMedia method on the mediaDevices object.
  // TODO(KaptenJansson) remove once implemented in Chrome stable.
  if (!navigator.mediaDevices.getUserMedia) {
    navigator.mediaDevices.getUserMedia = function(constraints) {
      return getUserMediaPromise_(constraints);
    };
  } else {
    // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia
    // function which returns a Promise, it does not accept spec-style
    // constraints.
    var origGetUserMedia = navigator.mediaDevices.getUserMedia.
        bind(navigator.mediaDevices);
    navigator.mediaDevices.getUserMedia = function(cs) {
      return shimConstraints_(cs, function(c) {
        return origGetUserMedia(c).catch(function(e) {
          return Promise.reject(shimError_(e));
        });
      });
    };
  }

  // Dummy devicechange event methods.
  // TODO(KaptenJansson) remove once implemented in Chrome stable.
  if (typeof navigator.mediaDevices.addEventListener === 'undefined') {
    navigator.mediaDevices.addEventListener = function() {
      logging('Dummy mediaDevices.addEventListener called.');
    };
  }
  if (typeof navigator.mediaDevices.removeEventListener === 'undefined') {
    navigator.mediaDevices.removeEventListener = function() {
      logging('Dummy mediaDevices.removeEventListener called.');
    };
  }
};

},{"../utils.js":10}],5:[function(require,module,exports){
/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */
'use strict';

var SDPUtils = require('sdp');
var logging = require('../utils').log;

var edgeShim = {
  shimPeerConnection: function() {
    if (window.RTCIceGatherer) {
      // ORTC defines an RTCIceCandidate object but no constructor.
      // Not implemented in Edge.
      if (!window.RTCIceCandidate) {
        window.RTCIceCandidate = function(args) {
          return args;
        };
      }
      // ORTC does not have a session description object but
      // other browsers (i.e. Chrome) that will support both PC and ORTC
      // in the future might have this defined already.
      if (!window.RTCSessionDescription) {
        window.RTCSessionDescription = function(args) {
          return args;
        };
      }
    }

    window.RTCPeerConnection = function(config) {
      var self = this;

      var _eventTarget = document.createDocumentFragment();
      ['addEventListener', 'removeEventListener', 'dispatchEvent']
          .forEach(function(method) {
            self[method] = _eventTarget[method].bind(_eventTarget);
          });

      this.onicecandidate = null;
      this.onaddstream = null;
      this.ontrack = null;
      this.onremovestream = null;
      this.onsignalingstatechange = null;
      this.oniceconnectionstatechange = null;
      this.onnegotiationneeded = null;
      this.ondatachannel = null;

      this.localStreams = [];
      this.remoteStreams = [];
      this.getLocalStreams = function() {
        return self.localStreams;
      };
      this.getRemoteStreams = function() {
        return self.remoteStreams;
      };

      this.localDescription = new RTCSessionDescription({
        type: '',
        sdp: ''
      });
      this.remoteDescription = new RTCSessionDescription({
        type: '',
        sdp: ''
      });
      this.signalingState = 'stable';
      this.iceConnectionState = 'new';
      this.iceGatheringState = 'new';

      this.iceOptions = {
        gatherPolicy: 'all',
        iceServers: []
      };
      if (config && config.iceTransportPolicy) {
        switch (config.iceTransportPolicy) {
          case 'all':
          case 'relay':
            this.iceOptions.gatherPolicy = config.iceTransportPolicy;
            break;
          case 'none':
            // FIXME: remove once implementation and spec have added this.
            throw new TypeError('iceTransportPolicy "none" not supported');
          default:
            // don't set iceTransportPolicy.
            break;
        }
      }
      this.usingBundle = config && config.bundlePolicy === 'max-bundle';

      if (config && config.iceServers) {
        // Edge does not like
        // 1) stun:
        // 2) turn: that does not have all of turn:host:port?transport=udp
        var iceServers = JSON.parse(JSON.stringify(config.iceServers));
        this.iceOptions.iceServers = iceServers.filter(function(server) {
          if (server && server.urls) {
            var urls = server.urls;
            if (typeof urls === 'string') {
              urls = [urls];
            }
            urls = urls.filter(function(url) {
              return url.indexOf('turn:') === 0 &&
                  url.indexOf('transport=udp') !== -1;
            })[0];
            return !!urls;
          }
          return false;
        });
      }

      // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ...
      // everything that is needed to describe a SDP m-line.
      this.transceivers = [];

      // since the iceGatherer is currently created in createOffer but we
      // must not emit candidates until after setLocalDescription we buffer
      // them in this array.
      this._localIceCandidatesBuffer = [];
    };

    window.RTCPeerConnection.prototype._emitBufferedCandidates = function() {
      var self = this;
      var sections = SDPUtils.splitSections(self.localDescription.sdp);
      // FIXME: need to apply ice candidates in a way which is async but
      // in-order
      this._localIceCandidatesBuffer.forEach(function(event) {
        var end = !event.candidate || Object.keys(event.candidate).length === 0;
        if (end) {
          for (var j = 1; j < sections.length; j++) {
            if (sections[j].indexOf('\r\na=end-of-candidates\r\n') === -1) {
              sections[j] += 'a=end-of-candidates\r\n';
            }
          }
        } else if (event.candidate.candidate.indexOf('typ endOfCandidates')
            === -1) {
          sections[event.candidate.sdpMLineIndex + 1] +=
              'a=' + event.candidate.candidate + '\r\n';
        }
        self.localDescription.sdp = sections.join('');
        self.dispatchEvent(event);
        if (self.onicecandidate !== null) {
          self.onicecandidate(event);
        }
        if (!event.candidate && self.iceGatheringState !== 'complete') {
          var complete = self.transceivers.every(function(transceiver) {
            return transceiver.iceGatherer &&
                transceiver.iceGatherer.state === 'completed';
          });
          if (complete) {
            self.iceGatheringState = 'complete';
          }
        }
      });
      this._localIceCandidatesBuffer = [];
    };

    window.RTCPeerConnection.prototype.addStream = function(stream) {
      // Clone is necessary for local demos mostly, attaching directly
      // to two different senders does not work (build 10547).
      this.localStreams.push(stream.clone());
      this._maybeFireNegotiationNeeded();
    };

    window.RTCPeerConnection.prototype.removeStream = function(stream) {
      var idx = this.localStreams.indexOf(stream);
      if (idx > -1) {
        this.localStreams.splice(idx, 1);
        this._maybeFireNegotiationNeeded();
      }
    };

    window.RTCPeerConnection.prototype.getSenders = function() {
      return this.transceivers.filter(function(transceiver) {
        return !!transceiver.rtpSender;
      })
      .map(function(transceiver) {
        return transceiver.rtpSender;
      });
    };

    window.RTCPeerConnection.prototype.getReceivers = function() {
      return this.transceivers.filter(function(transceiver) {
        return !!transceiver.rtpReceiver;
      })
      .map(function(transceiver) {
        return transceiver.rtpReceiver;
      });
    };

    // Determines the intersection of local and remote capabilities.
    window.RTCPeerConnection.prototype._getCommonCapabilities =
        function(localCapabilities, remoteCapabilities) {
          var commonCapabilities = {
            codecs: [],
            headerExtensions: [],
            fecMechanisms: []
          };
          localCapabilities.codecs.forEach(function(lCodec) {
            for (var i = 0; i < remoteCapabilities.codecs.length; i++) {
              var rCodec = remoteCapabilities.codecs[i];
              if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() &&
                  lCodec.clockRate === rCodec.clockRate &&
                  lCodec.numChannels === rCodec.numChannels) {
                // push rCodec so we reply with offerer payload type
                commonCapabilities.codecs.push(rCodec);

                // FIXME: also need to determine intersection between
                // .rtcpFeedback and .parameters
                break;
              }
            }
          });

          localCapabilities.headerExtensions
              .forEach(function(lHeaderExtension) {
                for (var i = 0; i < remoteCapabilities.headerExtensions.length;
                     i++) {
                  var rHeaderExtension = remoteCapabilities.headerExtensions[i];
                  if (lHeaderExtension.uri === rHeaderExtension.uri) {
                    commonCapabilities.headerExtensions.push(rHeaderExtension);
                    break;
                  }
                }
              });

          // FIXME: fecMechanisms
          return commonCapabilities;
        };

    // Create ICE gatherer, ICE transport and DTLS transport.
    window.RTCPeerConnection.prototype._createIceAndDtlsTransports =
        function(mid, sdpMLineIndex) {
          var self = this;
          var iceGatherer = new RTCIceGatherer(self.iceOptions);
          var iceTransport = new RTCIceTransport(iceGatherer);
          iceGatherer.onlocalcandidate = function(evt) {
            var event = new Event('icecandidate');
            event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex};

            var cand = evt.candidate;
            var end = !cand || Object.keys(cand).length === 0;
            // Edge emits an empty object for RTCIceCandidateComplete‥
            if (end) {
              // polyfill since RTCIceGatherer.state is not implemented in
              // Edge 10547 yet.
              if (iceGatherer.state === undefined) {
                iceGatherer.state = 'completed';
              }

              // Emit a candidate with type endOfCandidates to make the samples
              // work. Edge requires addIceCandidate with this empty candidate
              // to start checking. The real solution is to signal
              // end-of-candidates to the other side when getting the null
              // candidate but some apps (like the samples) don't do that.
              event.candidate.candidate =
                  'candidate:1 1 udp 1 0.0.0.0 9 typ endOfCandidates';
            } else {
              // RTCIceCandidate doesn't have a component, needs to be added
              cand.component = iceTransport.component === 'RTCP' ? 2 : 1;
              event.candidate.candidate = SDPUtils.writeCandidate(cand);
            }

            // update local description.
            var sections = SDPUtils.splitSections(self.localDescription.sdp);
            if (event.candidate.candidate.indexOf('typ endOfCandidates')
                === -1) {
              sections[event.candidate.sdpMLineIndex + 1] +=
                  'a=' + event.candidate.candidate + '\r\n';
            } else {
              sections[event.candidate.sdpMLineIndex + 1] +=
                  'a=end-of-candidates\r\n';
            }
            self.localDescription.sdp = sections.join('');

            var complete = self.transceivers.every(function(transceiver) {
              return transceiver.iceGatherer &&
                  transceiver.iceGatherer.state === 'completed';
            });

            // Emit candidate if localDescription is set.
            // Also emits null candidate when all gatherers are complete.
            switch (self.iceGatheringState) {
              case 'new':
                self._localIceCandidatesBuffer.push(event);
                if (end && complete) {
                  self._localIceCandidatesBuffer.push(
                      new Event('icecandidate'));
                }
                break;
              case 'gathering':
                self._emitBufferedCandidates();
                self.dispatchEvent(event);
                if (self.onicecandidate !== null) {
                  self.onicecandidate(event);
                }
                if (complete) {
                  self.dispatchEvent(new Event('icecandidate'));
                  if (self.onicecandidate !== null) {
                    self.onicecandidate(new Event('icecandidate'));
                  }
                  self.iceGatheringState = 'complete';
                }
                break;
              case 'complete':
                // should not happen... currently!
                break;
              default: // no-op.
                break;
            }
          };
          iceTransport.onicestatechange = function() {
            self._updateConnectionState();
          };

          var dtlsTransport = new RTCDtlsTransport(iceTransport);
          dtlsTransport.ondtlsstatechange = function() {
            self._updateConnectionState();
          };
          dtlsTransport.onerror = function() {
            // onerror does not set state to failed by itself.
            dtlsTransport.state = 'failed';
            self._updateConnectionState();
          };

          return {
            iceGatherer: iceGatherer,
            iceTransport: iceTransport,
            dtlsTransport: dtlsTransport
          };
        };

    // Start the RTP Sender and Receiver for a transceiver.
    window.RTCPeerConnection.prototype._transceive = function(transceiver,
        send, recv) {
      var params = this._getCommonCapabilities(transceiver.localCapabilities,
          transceiver.remoteCapabilities);
      if (send && transceiver.rtpSender) {
        params.encodings = transceiver.sendEncodingParameters;
        params.rtcp = {
          cname: SDPUtils.localCName
        };
        if (transceiver.recvEncodingParameters.length) {
          params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc;
        }
        transceiver.rtpSender.send(params);
      }
      if (recv && transceiver.rtpReceiver) {
        params.encodings = transceiver.recvEncodingParameters;
        params.rtcp = {
          cname: transceiver.cname
        };
        if (transceiver.sendEncodingParameters.length) {
          params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc;
        }
        transceiver.rtpReceiver.receive(params);
      }
    };

    window.RTCPeerConnection.prototype.setLocalDescription =
        function(description) {
          var self = this;
          var sections;
          var sessionpart;
          if (description.type === 'offer') {
            // FIXME: What was the purpose of this empty if statement?
            // if (!this._pendingOffer) {
            // } else {
            if (this._pendingOffer) {
              // VERY limited support for SDP munging. Limited to:
              // * changing the order of codecs
              sections = SDPUtils.splitSections(description.sdp);
              sessionpart = sections.shift();
              sections.forEach(function(mediaSection, sdpMLineIndex) {
                var caps = SDPUtils.parseRtpParameters(mediaSection);
                self._pendingOffer[sdpMLineIndex].localCapabilities = caps;
              });
              this.transceivers = this._pendingOffer;
              delete this._pendingOffer;
            }
          } else if (description.type === 'answer') {
            sections = SDPUtils.splitSections(self.remoteDescription.sdp);
            sessionpart = sections.shift();
            var isIceLite = SDPUtils.matchPrefix(sessionpart,
                'a=ice-lite').length > 0;
            sections.forEach(function(mediaSection, sdpMLineIndex) {
              var transceiver = self.transceivers[sdpMLineIndex];
              var iceGatherer = transceiver.iceGatherer;
              var iceTransport = transceiver.iceTransport;
              var dtlsTransport = transceiver.dtlsTransport;
              var localCapabilities = transceiver.localCapabilities;
              var remoteCapabilities = transceiver.remoteCapabilities;
              var rejected = mediaSection.split('\n', 1)[0]
                  .split(' ', 2)[1] === '0';

              if (!rejected) {
                var remoteIceParameters = SDPUtils.getIceParameters(
                    mediaSection, sessionpart);
                if (isIceLite) {
                  var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:')
                  .map(function(cand) {
                    return SDPUtils.parseCandidate(cand);
                  })
                  .filter(function(cand) {
                    return cand.component === '1';
                  });
                  // ice-lite only includes host candidates in the SDP so we can
                  // use setRemoteCandidates (which implies an
                  // RTCIceCandidateComplete)
                  if (cands.length) {
                    iceTransport.setRemoteCandidates(cands);
                  }
                }
                var remoteDtlsParameters = SDPUtils.getDtlsParameters(
                    mediaSection, sessionpart);
                if (isIceLite) {
                  remoteDtlsParameters.role = 'server';
                }

                if (!self.usingBundle || sdpMLineIndex === 0) {
                  iceTransport.start(iceGatherer, remoteIceParameters,
                      isIceLite ? 'controlling' : 'controlled');
                  dtlsTransport.start(remoteDtlsParameters);
                }

                // Calculate intersection of capabilities.
                var params = self._getCommonCapabilities(localCapabilities,
                    remoteCapabilities);

                // Start the RTCRtpSender. The RTCRtpReceiver for this
                // transceiver has already been started in setRemoteDescription.
                self._transceive(transceiver,
                    params.codecs.length > 0,
                    false);
              }
            });
          }

          this.localDescription = {
            type: description.type,
            sdp: description.sdp
          };
          switch (description.type) {
            case 'offer':
              this._updateSignalingState('have-local-offer');
              break;
            case 'answer':
              this._updateSignalingState('stable');
              break;
            default:
              throw new TypeError('unsupported type "' + description.type +
                  '"');
          }

          // If a success callback was provided, emit ICE candidates after it
          // has been executed. Otherwise, emit callback after the Promise is
          // resolved.
          var hasCallback = arguments.length > 1 &&
            typeof arguments[1] === 'function';
          if (hasCallback) {
            var cb = arguments[1];
            window.setTimeout(function() {
              cb();
              if (self.iceGatheringState === 'new') {
                self.iceGatheringState = 'gathering';
              }
              self._emitBufferedCandidates();
            }, 0);
          }
          var p = Promise.resolve();
          p.then(function() {
            if (!hasCallback) {
              if (self.iceGatheringState === 'new') {
                self.iceGatheringState = 'gathering';
              }
              // Usually candidates will be emitted earlier.
              window.setTimeout(self._emitBufferedCandidates.bind(self), 500);
            }
          });
          return p;
        };

    window.RTCPeerConnection.prototype.setRemoteDescription =
        function(description) {
          var self = this;
          var stream = new MediaStream();
          var receiverList = [];
          var sections = SDPUtils.splitSections(description.sdp);
          var sessionpart = sections.shift();
          var isIceLite = SDPUtils.matchPrefix(sessionpart,
              'a=ice-lite').length > 0;
          this.usingBundle = SDPUtils.matchPrefix(sessionpart,
              'a=group:BUNDLE ').length > 0;
          sections.forEach(function(mediaSection, sdpMLineIndex) {
            var lines = SDPUtils.splitLines(mediaSection);
            var mline = lines[0].substr(2).split(' ');
            var kind = mline[0];
            var rejected = mline[1] === '0';
            var direction = SDPUtils.getDirection(mediaSection, sessionpart);

            var transceiver;
            var iceGatherer;
            var iceTransport;
            var dtlsTransport;
            var rtpSender;
            var rtpReceiver;
            var sendEncodingParameters;
            var recvEncodingParameters;
            var localCapabilities;

            var track;
            // FIXME: ensure the mediaSection has rtcp-mux set.
            var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection);
            var remoteIceParameters;
            var remoteDtlsParameters;
            if (!rejected) {
              remoteIceParameters = SDPUtils.getIceParameters(mediaSection,
                  sessionpart);
              remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection,
                  sessionpart);
              remoteDtlsParameters.role = 'client';
            }
            recvEncodingParameters =
                SDPUtils.parseRtpEncodingParameters(mediaSection);

            var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:');
            if (mid.length) {
              mid = mid[0].substr(6);
            } else {
              mid = SDPUtils.generateIdentifier();
            }

            var cname;
            // Gets the first SSRC. Note that with RTX there might be multiple
            // SSRCs.
            var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
                .map(function(line) {
                  return SDPUtils.parseSsrcMedia(line);
                })
                .filter(function(obj) {
                  return obj.attribute === 'cname';
                })[0];
            if (remoteSsrc) {
              cname = remoteSsrc.value;
            }

            var isComplete = SDPUtils.matchPrefix(mediaSection,
                'a=end-of-candidates').length > 0;
            var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:')
                .map(function(cand) {
                  return SDPUtils.parseCandidate(cand);
                })
                .filter(function(cand) {
                  return cand.component === '1';
                });
            if (description.type === 'offer' && !rejected) {
              var transports = self.usingBundle && sdpMLineIndex > 0 ? {
                iceGatherer: self.transceivers[0].iceGatherer,
                iceTransport: self.transceivers[0].iceTransport,
                dtlsTransport: self.transceivers[0].dtlsTransport
              } : self._createIceAndDtlsTransports(mid, sdpMLineIndex);

              if (isComplete) {
                transports.iceTransport.setRemoteCandidates(cands);
              }

              localCapabilities = RTCRtpReceiver.getCapabilities(kind);
              sendEncodingParameters = [{
                ssrc: (2 * sdpMLineIndex + 2) * 1001
              }];

              rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind);

              track = rtpReceiver.track;
              receiverList.push([track, rtpReceiver]);
              // FIXME: not correct when there are multiple streams but that is
              // not currently supported in this shim.
              stream.addTrack(track);

              // FIXME: look at direction.
              if (self.localStreams.length > 0 &&
                  self.localStreams[0].getTracks().length >= sdpMLineIndex) {
                // FIXME: actually more complicated, needs to match types etc
                var localtrack = self.localStreams[0]
                    .getTracks()[sdpMLineIndex];
                rtpSender = new RTCRtpSender(localtrack,
                    transports.dtlsTransport);
              }

              self.transceivers[sdpMLineIndex] = {
                iceGatherer: transports.iceGatherer,
                iceTransport: transports.iceTransport,
                dtlsTransport: transports.dtlsTransport,
                localCapabilities: localCapabilities,
                remoteCapabilities: remoteCapabilities,
                rtpSender: rtpSender,
                rtpReceiver: rtpReceiver,
                kind: kind,
                mid: mid,
                cname: cname,
                sendEncodingParameters: sendEncodingParameters,
                recvEncodingParameters: recvEncodingParameters
              };
              // Start the RTCRtpReceiver now. The RTPSender is started in
              // setLocalDescription.
              self._transceive(self.transceivers[sdpMLineIndex],
                  false,
                  direction === 'sendrecv' || direction === 'sendonly');
            } else if (description.type === 'answer' && !rejected) {
              transceiver = self.transceivers[sdpMLineIndex];
              iceGatherer = transceiver.iceGatherer;
              iceTransport = transceiver.iceTransport;
              dtlsTransport = transceiver.dtlsTransport;
              rtpSender = transceiver.rtpSender;
              rtpReceiver = transceiver.rtpReceiver;
              sendEncodingParameters = transceiver.sendEncodingParameters;
              localCapabilities = transceiver.localCapabilities;

              self.transceivers[sdpMLineIndex].recvEncodingParameters =
                  recvEncodingParameters;
              self.transceivers[sdpMLineIndex].remoteCapabilities =
                  remoteCapabilities;
              self.transceivers[sdpMLineIndex].cname = cname;

              if ((isIceLite || isComplete) && cands.length) {
                iceTransport.setRemoteCandidates(cands);
              }
              if (!self.usingBundle || sdpMLineIndex === 0) {
                iceTransport.start(iceGatherer, remoteIceParameters,
                    'controlling');
                dtlsTransport.start(remoteDtlsParameters);
              }

              self._transceive(transceiver,
                  direction === 'sendrecv' || direction === 'recvonly',
                  direction === 'sendrecv' || direction === 'sendonly');

              if (rtpReceiver &&
                  (direction === 'sendrecv' || direction === 'sendonly')) {
                track = rtpReceiver.track;
                receiverList.push([track, rtpReceiver]);
                stream.addTrack(track);
              } else {
                // FIXME: actually the receiver should be created later.
                delete transceiver.rtpReceiver;
              }
            }
          });

          this.remoteDescription = {
            type: description.type,
            sdp: description.sdp
          };
          switch (description.type) {
            case 'offer':
              this._updateSignalingState('have-remote-offer');
              break;
            case 'answer':
              this._updateSignalingState('stable');
              break;
            default:
              throw new TypeError('unsupported type "' + description.type +
                  '"');
          }
          if (stream.getTracks().length) {
            self.remoteStreams.push(stream);
            window.setTimeout(function() {
              var event = new Event('addstream');
              event.stream = stream;
              self.dispatchEvent(event);
              if (self.onaddstream !== null) {
                window.setTimeout(function() {
                  self.onaddstream(event);
                }, 0);
              }

              receiverList.forEach(function(item) {
                var track = item[0];
                var receiver = item[1];
                var trackEvent = new Event('track');
                trackEvent.track = track;
                trackEvent.receiver = receiver;
                trackEvent.streams = [stream];
                self.dispatchEvent(event);
                if (self.ontrack !== null) {
                  window.setTimeout(function() {
                    self.ontrack(trackEvent);
                  }, 0);
                }
              });
            }, 0);
          }
          if (arguments.length > 1 && typeof arguments[1] === 'function') {
            window.setTimeout(arguments[1], 0);
          }
          return Promise.resolve();
        };

    window.RTCPeerConnection.prototype.close = function() {
      this.transceivers.forEach(function(transceiver) {
        /* not yet
        if (transceiver.iceGatherer) {
          transceiver.iceGatherer.close();
        }
        */
        if (transceiver.iceTransport) {
          transceiver.iceTransport.stop();
        }
        if (transceiver.dtlsTransport) {
          transceiver.dtlsTransport.stop();
        }
        if (transceiver.rtpSender) {
          transceiver.rtpSender.stop();
        }
        if (transceiver.rtpReceiver) {
          transceiver.rtpReceiver.stop();
        }
      });
      // FIXME: clean up tracks, local streams, remote streams, etc
      this._updateSignalingState('closed');
    };

    // Update the signaling state.
    window.RTCPeerConnection.prototype._updateSignalingState =
        function(newState) {
          this.signalingState = newState;
          var event = new Event('signalingstatechange');
          this.dispatchEvent(event);
          if (this.onsignalingstatechange !== null) {
            this.onsignalingstatechange(event);
          }
        };

    // Determine whether to fire the negotiationneeded event.
    window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded =
        function() {
          // Fire away (for now).
          var event = new Event('negotiationneeded');
          this.dispatchEvent(event);
          if (this.onnegotiationneeded !== null) {
            this.onnegotiationneeded(event);
          }
        };

    // Update the connection state.
    window.RTCPeerConnection.prototype._updateConnectionState = function() {
      var self = this;
      var newState;
      var states = {
        'new': 0,
        closed: 0,
        connecting: 0,
        checking: 0,
        connected: 0,
        completed: 0,
        failed: 0
      };
      this.transceivers.forEach(function(transceiver) {
        states[transceiver.iceTransport.state]++;
        states[transceiver.dtlsTransport.state]++;
      });
      // ICETransport.completed and connected are the same for this purpose.
      states.connected += states.completed;

      newState = 'new';
      if (states.failed > 0) {
        newState = 'failed';
      } else if (states.connecting > 0 || states.checking > 0) {
        newState = 'connecting';
      } else if (states.disconnected > 0) {
        newState = 'disconnected';
      } else if (states.new > 0) {
        newState = 'new';
      } else if (states.connected > 0 || states.completed > 0) {
        newState = 'connected';
      }

      if (newState !== self.iceConnectionState) {
        self.iceConnectionState = newState;
        var event = new Event('iceconnectionstatechange');
        this.dispatchEvent(event);
        if (this.oniceconnectionstatechange !== null) {
          this.oniceconnectionstatechange(event);
        }
      }
    };

    window.RTCPeerConnection.prototype.createOffer = function() {
      var self = this;
      if (this._pendingOffer) {
        throw new Error('createOffer called while there is a pending offer.');
      }
      var offerOptions;
      if (arguments.length === 1 && typeof arguments[0] !== 'function') {
        offerOptions = arguments[0];
      } else if (arguments.length === 3) {
        offerOptions = arguments[2];
      }

      var tracks = [];
      var numAudioTracks = 0;
      var numVideoTracks = 0;
      // Default to sendrecv.
      if (this.localStreams.length) {
        numAudioTracks = this.localStreams[0].getAudioTracks().length;
        numVideoTracks = this.localStreams[0].getVideoTracks().length;
      }
      // Determine number of audio and video tracks we need to send/recv.
      if (offerOptions) {
        // Reject Chrome legacy constraints.
        if (offerOptions.mandatory || offerOptions.optional) {
          throw new TypeError(
              'Legacy mandatory/optional constraints not supported.');
        }
        if (offerOptions.offerToReceiveAudio !== undefined) {
          numAudioTracks = offerOptions.offerToReceiveAudio;
        }
        if (offerOptions.offerToReceiveVideo !== undefined) {
          numVideoTracks = offerOptions.offerToReceiveVideo;
        }
      }
      if (this.localStreams.length) {
        // Push local streams.
        this.localStreams[0].getTracks().forEach(function(track) {
          tracks.push({
            kind: track.kind,
            track: track,
            wantReceive: track.kind === 'audio' ?
                numAudioTracks > 0 : numVideoTracks > 0
          });
          if (track.kind === 'audio') {
            numAudioTracks--;
          } else if (track.kind === 'video') {
            numVideoTracks--;
          }
        });
      }
      // Create M-lines for recvonly streams.
      while (numAudioTracks > 0 || numVideoTracks > 0) {
        if (numAudioTracks > 0) {
          tracks.push({
            kind: 'audio',
            wantReceive: true
          });
          numAudioTracks--;
        }
        if (numVideoTracks > 0) {
          tracks.push({
            kind: 'video',
            wantReceive: true
          });
          numVideoTracks--;
        }
      }

      var sdp = SDPUtils.writeSessionBoilerplate();
      var transceivers = [];
      tracks.forEach(function(mline, sdpMLineIndex) {
        // For each track, create an ice gatherer, ice transport,
        // dtls transport, potentially rtpsender and rtpreceiver.
        var track = mline.track;
        var kind = mline.kind;
        var mid = SDPUtils.generateIdentifier();

        var transports = self.usingBundle && sdpMLineIndex > 0 ? {
          iceGatherer: transceivers[0].iceGatherer,
          iceTransport: transceivers[0].iceTransport,
          dtlsTransport: transceivers[0].dtlsTransport
        } : self._createIceAndDtlsTransports(mid, sdpMLineIndex);

        var localCapabilities = RTCRtpSender.getCapabilities(kind);
        var rtpSender;
        var rtpReceiver;

        // generate an ssrc now, to be used later in rtpSender.send
        var sendEncodingParameters = [{
          ssrc: (2 * sdpMLineIndex + 1) * 1001
        }];
        if (track) {
          rtpSender = new RTCRtpSender(track, transports.dtlsTransport);
        }

        if (mline.wantReceive) {
          rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind);
        }

        transceivers[sdpMLineIndex] = {
          iceGatherer: transports.iceGatherer,
          iceTransport: transports.iceTransport,
          dtlsTransport: transports.dtlsTransport,
          localCapabilities: localCapabilities,
          remoteCapabilities: null,
          rtpSender: rtpSender,
          rtpReceiver: rtpReceiver,
          kind: kind,
          mid: mid,
          sendEncodingParameters: sendEncodingParameters,
          recvEncodingParameters: null
        };
      });
      if (this.usingBundle) {
        sdp += 'a=group:BUNDLE ' + transceivers.map(function(t) {
          return t.mid;
        }).join(' ') + '\r\n';
      }
      tracks.forEach(function(mline, sdpMLineIndex) {
        var transceiver = transceivers[sdpMLineIndex];
        sdp += SDPUtils.writeMediaSection(transceiver,
            transceiver.localCapabilities, 'offer', self.localStreams[0]);
      });

      this._pendingOffer = transceivers;
      var desc = new RTCSessionDescription({
        type: 'offer',
        sdp: sdp
      });
      if (arguments.length && typeof arguments[0] === 'function') {
        window.setTimeout(arguments[0], 0, desc);
      }
      return Promise.resolve(desc);
    };

    window.RTCPeerConnection.prototype.createAnswer = function() {
      var self = this;

      var sdp = SDPUtils.writeSessionBoilerplate();
      if (this.usingBundle) {
        sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) {
          return t.mid;
        }).join(' ') + '\r\n';
      }
      this.transceivers.forEach(function(transceiver) {
        // Calculate intersection of capabilities.
        var commonCapabilities = self._getCommonCapabilities(
            transceiver.localCapabilities,
            transceiver.remoteCapabilities);

        sdp += SDPUtils.writeMediaSection(transceiver, commonCapabilities,
            'answer', self.localStreams[0]);
      });

      var desc = new RTCSessionDescription({
        type: 'answer',
        sdp: sdp
      });
      if (arguments.length && typeof arguments[0] === 'function') {
        window.setTimeout(arguments[0], 0, desc);
      }
      return Promise.resolve(desc);
    };

    window.RTCPeerConnection.prototype.addIceCandidate = function(candidate) {
      if (candidate === null) {
        this.transceivers.forEach(function(transceiver) {
          transceiver.iceTransport.addRemoteCandidate({});
        });
      } else {
        var mLineIndex = candidate.sdpMLineIndex;
        if (candidate.sdpMid) {
          for (var i = 0; i < this.transceivers.length; i++) {
            if (this.transceivers[i].mid === candidate.sdpMid) {
              mLineIndex = i;
              break;
            }
          }
        }
        var transceiver = this.transceivers[mLineIndex];
        if (transceiver) {
          var cand = Object.keys(candidate.candidate).length > 0 ?
              SDPUtils.parseCandidate(candidate.candidate) : {};
          // Ignore Chrome's invalid candidates since Edge does not like them.
          if (cand.protocol === 'tcp' && cand.port === 0) {
            return;
          }
          // Ignore RTCP candidates, we assume RTCP-MUX.
          if (cand.component !== '1') {
            return;
          }
          // A dirty hack to make samples work.
          if (cand.type === 'endOfCandidates') {
            cand = {};
          }
          transceiver.iceTransport.addRemoteCandidate(cand);

          // update the remoteDescription.
          var sections = SDPUtils.splitSections(this.remoteDescription.sdp);
          sections[mLineIndex + 1] += (cand.type ? candidate.candidate.trim()
              : 'a=end-of-candidates') + '\r\n';
          this.remoteDescription.sdp = sections.join('');
        }
      }
      if (arguments.length > 1 && typeof arguments[1] === 'function') {
        window.setTimeout(arguments[1], 0);
      }
      return Promise.resolve();
    };

    window.RTCPeerConnection.prototype.getStats = function() {
      var promises = [];
      this.transceivers.forEach(function(transceiver) {
        ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport',
            'dtlsTransport'].forEach(function(method) {
              if (transceiver[method]) {
                promises.push(transceiver[method].getStats());
              }
            });
      });
      var cb = arguments.length > 1 && typeof arguments[1] === 'function' &&
          arguments[1];
      return new Promise(function(resolve) {
        // shim getStats with maplike support
        var results = new Map();
        Promise.all(promises).then(function(res) {
          res.forEach(function(result) {
            Object.keys(result).forEach(function(id) {
              results.set(id, result[id]);
              results[id] = result[id];
            });
          });
          if (cb) {
            window.setTimeout(cb, 0, results);
          }
          resolve(results);
        });
      });
    };
  },

  // Attach a media stream to an element.
  attachMediaStream: function(element, stream) {
    logging('DEPRECATED, attachMediaStream will soon be removed.');
    element.srcObject = stream;
  },

  reattachMediaStream: function(to, from) {
    logging('DEPRECATED, reattachMediaStream will soon be removed.');
    to.srcObject = from.srcObject;
  }
};

// Expose public methods.
module.exports = {
  shimPeerConnection: edgeShim.shimPeerConnection,
  shimGetUserMedia: require('./getusermedia'),
  attachMediaStream: edgeShim.attachMediaStream,
  reattachMediaStream: edgeShim.reattachMediaStream
};

},{"../utils":10,"./getusermedia":6,"sdp":1}],6:[function(require,module,exports){
/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */
'use strict';

// Expose public methods.
module.exports = function() {
  var shimError_ = function(e) {
    return {
      name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name,
      message: e.message,
      constraint: e.constraint,
      toString: function() {
        return this.name;
      }
    };
  };

  // getUserMedia error shim.
  var origGetUserMedia = navigator.mediaDevices.getUserMedia.
      bind(navigator.mediaDevices);
  navigator.mediaDevices.getUserMedia = function(c) {
    return origGetUserMedia(c).catch(function(e) {
      return Promise.reject(shimError_(e));
    });
  };
};

},{}],7:[function(require,module,exports){
/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */
'use strict';

var logging = require('../utils').log;
var browserDetails = require('../utils').browserDetails;

var firefoxShim = {
  shimOnTrack: function() {
    if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in
        window.RTCPeerConnection.prototype)) {
      Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
        get: function() {
          return this._ontrack;
        },
        set: function(f) {
          if (this._ontrack) {
            this.removeEventListener('track', this._ontrack);
            this.removeEventListener('addstream', this._ontrackpoly);
          }
          this.addEventListener('track', this._ontrack = f);
          this.addEventListener('addstream', this._ontrackpoly = function(e) {
            e.stream.getTracks().forEach(function(track) {
              var event = new Event('track');
              event.track = track;
              event.receiver = {track: track};
              event.streams = [e.stream];
              this.dispatchEvent(event);
            }.bind(this));
          }.bind(this));
        }
      });
    }
  },

  shimSourceObject: function() {
    // Firefox has supported mozSrcObject since FF22, unprefixed in 42.
    if (typeof window === 'object') {
      if (window.HTMLMediaElement &&
        !('srcObject' in window.HTMLMediaElement.prototype)) {
        // Shim the srcObject property, once, when HTMLMediaElement is found.
        Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
          get: function() {
            return this.mozSrcObject;
          },
          set: function(stream) {
            this.mozSrcObject = stream;
          }
        });
      }
    }
  },

  shimPeerConnection: function() {
    if (typeof window !== 'object' || !(window.RTCPeerConnection ||
        window.mozRTCPeerConnection)) {
      return; // probably media.peerconnection.enabled=false in about:config
    }
    // The RTCPeerConnection object.
    if (!window.RTCPeerConnection) {
      window.RTCPeerConnection = function(pcConfig, pcConstraints) {
        if (browserDetails.version < 38) {
          // .urls is not supported in FF < 38.
          // create RTCIceServers with a single url.
          if (pcConfig && pcConfig.iceServers) {
            var newIceServers = [];
            for (var i = 0; i < pcConfig.iceServers.length; i++) {
              var server = pcConfig.iceServers[i];
              if (server.hasOwnProperty('urls')) {
                for (var j = 0; j < server.urls.length; j++) {
                  var newServer = {
                    url: server.urls[j]
                  };
                  if (server.urls[j].indexOf('turn') === 0) {
                    newServer.username = server.username;
                    newServer.credential = server.credential;
                  }
                  newIceServers.push(newServer);
                }
              } else {
                newIceServers.push(pcConfig.iceServers[i]);
              }
            }
            pcConfig.iceServers = newIceServers;
          }
        }
        return new mozRTCPeerConnection(pcConfig, pcConstraints);
      };
      window.RTCPeerConnection.prototype = mozRTCPeerConnection.prototype;

      // wrap static methods. Currently just generateCertificate.
      if (mozRTCPeerConnection.generateCertificate) {
        Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
          get: function() {
            return mozRTCPeerConnection.generateCertificate;
          }
        });
      }

      window.RTCSessionDescription = mozRTCSessionDescription;
      window.RTCIceCandidate = mozRTCIceCandidate;
    }

    // shim away need for obsolete RTCIceCandidate/RTCSessionDescription.
    ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
        .forEach(function(method) {
          var nativeMethod = RTCPeerConnection.prototype[method];
          RTCPeerConnection.prototype[method] = function() {
            arguments[0] = new ((method === 'addIceCandidate') ?
                RTCIceCandidate : RTCSessionDescription)(arguments[0]);
            return nativeMethod.apply(this, arguments);
          };
        });

    // support for addIceCandidate(null)
    var nativeAddIceCandidate =
        RTCPeerConnection.prototype.addIceCandidate;
    RTCPeerConnection.prototype.addIceCandidate = function() {
      return arguments[0] === null ? Promise.resolve()
          : nativeAddIceCandidate.apply(this, arguments);
    };

    // shim getStats with maplike support
    var makeMapStats = function(stats) {
      var map = new Map();
      Object.keys(stats).forEach(function(key) {
        map.set(key, stats[key]);
        map[key] = stats[key];
      });
      return map;
    };

    var nativeGetStats = RTCPeerConnection.prototype.getStats;
    RTCPeerConnection.prototype.getStats = function(selector, onSucc, onErr) {
      return nativeGetStats.apply(this, [selector || null])
        .then(function(stats) {
          return makeMapStats(stats);
        })
        .then(onSucc, onErr);
    };
  },

  // Attach a media stream to an element.
  attachMediaStream: function(element, stream) {
    logging('DEPRECATED, attachMediaStream will soon be removed.');
    element.srcObject = stream;
  },

  reattachMediaStream: function(to, from) {
    logging('DEPRECATED, reattachMediaStream will soon be removed.');
    to.srcObject = from.srcObject;
  }
};

// Expose public methods.
module.exports = {
  shimOnTrack: firefoxShim.shimOnTrack,
  shimSourceObject: firefoxShim.shimSourceObject,
  shimPeerConnection: firefoxShim.shimPeerConnection,
  shimGetUserMedia: require('./getusermedia'),
  attachMediaStream: firefoxShim.attachMediaStream,
  reattachMediaStream: firefoxShim.reattachMediaStream
};

},{"../utils":10,"./getusermedia":8}],8:[function(require,module,exports){
/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */
'use strict';

var logging = require('../utils').log;
var browserDetails = require('../utils').browserDetails;

// Expose public methods.
module.exports = function() {
  var shimError_ = function(e) {
    return {
      name: {
        SecurityError: 'NotAllowedError',
        PermissionDeniedError: 'NotAllowedError'
      }[e.name] || e.name,
      message: {
        'The operation is insecure.': 'The request is not allowed by the ' +
        'user agent or the platform in the current context.'
      }[e.message] || e.message,
      constraint: e.constraint,
      toString: function() {
        return this.name + (this.message && ': ') + this.message;
      }
    };
  };

  // getUserMedia constraints shim.
  var getUserMedia_ = function(constraints, onSuccess, onError) {
    var constraintsToFF37_ = function(c) {
      if (typeof c !== 'object' || c.require) {
        return c;
      }
      var require = [];
      Object.keys(c).forEach(function(key) {
        if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
          return;
        }
        var r = c[key] = (typeof c[key] === 'object') ?
            c[key] : {ideal: c[key]};
        if (r.min !== undefined ||
            r.max !== undefined || r.exact !== undefined) {
          require.push(key);
        }
        if (r.exact !== undefined) {
          if (typeof r.exact === 'number') {
            r. min = r.max = r.exact;
          } else {
            c[key] = r.exact;
          }
          delete r.exact;
        }
        if (r.ideal !== undefined) {
          c.advanced = c.advanced || [];
          var oc = {};
          if (typeof r.ideal === 'number') {
            oc[key] = {min: r.ideal, max: r.ideal};
          } else {
            oc[key] = r.ideal;
          }
          c.advanced.push(oc);
          delete r.ideal;
          if (!Object.keys(r).length) {
            delete c[key];
          }
        }
      });
      if (require.length) {
        c.require = require;
      }
      return c;
    };
    constraints = JSON.parse(JSON.stringify(constraints));
    if (browserDetails.version < 38) {
      logging('spec: ' + JSON.stringify(constraints));
      if (constraints.audio) {
        constraints.audio = constraintsToFF37_(constraints.audio);
      }
      if (constraints.video) {
        constraints.video = constraintsToFF37_(constraints.video);
      }
      logging('ff37: ' + JSON.stringify(constraints));
    }
    return navigator.mozGetUserMedia(constraints, onSuccess, function(e) {
      onError(shimError_(e));
    });
  };

  // Returns the result of getUserMedia as a Promise.
  var getUserMediaPromise_ = function(constraints) {
    return new Promise(function(resolve, reject) {
      getUserMedia_(constraints, resolve, reject);
    });
  };

  // Shim for mediaDevices on older versions.
  if (!navigator.mediaDevices) {
    navigator.mediaDevices = {getUserMedia: getUserMediaPromise_,
      addEventListener: function() { },
      removeEventListener: function() { }
    };
  }
  navigator.mediaDevices.enumerateDevices =
      navigator.mediaDevices.enumerateDevices || function() {
        return new Promise(function(resolve) {
          var infos = [
            {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''},
            {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''}
          ];
          resolve(infos);
        });
      };

  if (browserDetails.version < 41) {
    // Work around http://bugzil.la/1169665
    var orgEnumerateDevices =
        navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices);
    navigator.mediaDevices.enumerateDevices = function() {
      return orgEnumerateDevices().then(undefined, function(e) {
        if (e.name === 'NotFoundError') {
          return [];
        }
        throw e;
      });
    };
  }
  if (browserDetails.version < 49) {
    var origGetUserMedia = navigator.mediaDevices.getUserMedia.
        bind(navigator.mediaDevices);
    navigator.mediaDevices.getUserMedia = function(c) {
      return origGetUserMedia(c).catch(function(e) {
        return Promise.reject(shimError_(e));
      });
    };
  }
  navigator.getUserMedia = function(constraints, onSuccess, onError) {
    if (browserDetails.version < 44) {
      return getUserMedia_(constraints, onSuccess, onError);
    }
    // Replace Firefox 44+'s deprecation warning with unprefixed version.
    console.warn('navigator.getUserMedia has been replaced by ' +
                 'navigator.mediaDevices.getUserMedia');
    navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
  };
};

},{"../utils":10}],9:[function(require,module,exports){
/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
'use strict';
var safariShim = {
  // TODO: DrAlex, should be here, double check against LayoutTests
  // shimOnTrack: function() { },

  // TODO: DrAlex
  // attachMediaStream: function(element, stream) { },
  // reattachMediaStream: function(to, from) { },

  // TODO: once the back-end for the mac port is done, add.
  // TODO: check for webkitGTK+
  // shimPeerConnection: function() { },

  shimGetUserMedia: function() {
    navigator.getUserMedia = navigator.webkitGetUserMedia;
  }
};

// Expose public methods.
module.exports = {
  shimGetUserMedia: safariShim.shimGetUserMedia
  // TODO
  // shimOnTrack: safariShim.shimOnTrack,
  // shimPeerConnection: safariShim.shimPeerConnection,
  // attachMediaStream: safariShim.attachMediaStream,
  // reattachMediaStream: safariShim.reattachMediaStream
};

},{}],10:[function(require,module,exports){
/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */
'use strict';

var logDisabled_ = true;

// Utility methods.
var utils = {
  disableLog: function(bool) {
    if (typeof bool !== 'boolean') {
      return new Error('Argument type: ' + typeof bool +
          '. Please use a boolean.');
    }
    logDisabled_ = bool;
    return (bool) ? 'adapter.js logging disabled' :
        'adapter.js logging enabled';
  },

  log: function() {
    if (typeof window === 'object') {
      if (logDisabled_) {
        return;
      }
      if (typeof console !== 'undefined' && typeof console.log === 'function') {
        console.log.apply(console, arguments);
      }
    }
  },

  /**
   * Extract browser version out of the provided user agent string.
   *
   * @param {!string} uastring userAgent string.
   * @param {!string} expr Regular expression used as match criteria.
   * @param {!number} pos position in the version string to be returned.
   * @return {!number} browser version.
   */
  extractVersion: function(uastring, expr, pos) {
    var match = uastring.match(expr);
    return match && match.length >= pos && parseInt(match[pos], 10);
  },

  /**
   * Browser detector.
   *
   * @return {object} result containing browser, version and minVersion
   *     properties.
   */
  detectBrowser: function() {
    // Returned result object.
    var result = {};
    result.browser = null;
    result.version = null;
    result.minVersion = null;

    // Fail early if it's not a browser
    if (typeof window === 'undefined' || !window.navigator) {
      result.browser = 'Not a browser.';
      return result;
    }

    // Firefox.
    if (navigator.mozGetUserMedia) {
      result.browser = 'firefox';
      result.version = this.extractVersion(navigator.userAgent,
          /Firefox\/([0-9]+)\./, 1);
      result.minVersion = 31;

    // all webkit-based browsers
    } else if (navigator.webkitGetUserMedia) {
      // Chrome, Chromium, Webview, Opera, all use the chrome shim for now
      if (window.webkitRTCPeerConnection) {
        result.browser = 'chrome';
        result.version = this.extractVersion(navigator.userAgent,
          /Chrom(e|ium)\/([0-9]+)\./, 2);
        result.minVersion = 38;

      // Safari or unknown webkit-based
      // for the time being Safari has support for MediaStreams but not webRTC
      } else {
        // Safari UA substrings of interest for reference:
        // - webkit version:           AppleWebKit/602.1.25 (also used in Op,Cr)
        // - safari UI version:        Version/9.0.3 (unique to Safari)
        // - safari UI webkit version: Safari/601.4.4 (also used in Op,Cr)
        //
        // if the webkit version and safari UI webkit versions are equals,
        // ... this is a stable version.
        //
        // only the internal webkit version is important today to know if
        // media streams are supported
        //
        if (navigator.userAgent.match(/Version\/(\d+).(\d+)/)) {
          result.browser = 'safari';
          result.version = this.extractVersion(navigator.userAgent,
            /AppleWebKit\/([0-9]+)\./, 1);
          result.minVersion = 602;

        // unknown webkit-based browser
        } else {
          result.browser = 'Unsupported webkit-based browser ' +
              'with GUM support but no WebRTC support.';
          return result;
        }
      }

    // Edge.
    } else if (navigator.mediaDevices &&
        navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) {
      result.browser = 'edge';
      result.version = this.extractVersion(navigator.userAgent,
          /Edge\/(\d+).(\d+)$/, 2);
      result.minVersion = 10547;

    // Default fallthrough: not supported.
    } else {
      result.browser = 'Not a supported browser.';
      return result;
    }

    // Warn if version is less than minVersion.
    if (result.version < result.minVersion) {
      utils.log('Browser: ' + result.browser + ' Version: ' + result.version +
          ' < minimum supported version: ' + result.minVersion +
          '\n some things might not work!');
    }

    return result;
  }
};

// Export.
module.exports = {
  log: utils.log,
  disableLog: utils.disableLog,
  browserDetails: utils.detectBrowser(),
  extractVersion: utils.extractVersion
};

},{}]},{},[2])(2)
});

================================================
FILE: examples/static/demo.css
================================================

#logs_container {
  display: flex;
  flex-direction: row;
  width: 100%;
}


#reliable_logs {
  flex: 1;
}

#datachannel_logs {
  flex: 1;
}


================================================
FILE: examples/static/index.html
================================================
<!DOCTYPE html>
<html>
<head>
  <title>WebRTC DataChannels Demo Site</title>
  <link rel="stylesheet" type="text/css" href="/static/demo.css">
  <script src="/static/jquery-3.0.0.min.js"></script>
  <script src="/static/adapter.js"></script>
  <script>

  // Global vars
  var dataChannelLabel = "testchannel";
  var reliableSocket = null;
  var peerConnection = null;
  var dataChannel = null;
  var remoteCandidates = [];
  var have_answer = false;

  function reliable_log_msg(msg) {
    console.log(msg);
    $("#reliable_log_list").prepend("<li>" + msg + "</li>");
  }

  function datachannel_log_msg(msg) {
    console.log(msg);
    $("#datachannel_log_list").prepend("<li>" + msg + "</li>");
  }

    $(document).ready(function () {

      var sourceBuffer = null;
      var video = document.querySelector('video');
      var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';

      if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
        var mediaSource = new MediaSource;
        video.src = URL.createObjectURL(mediaSource);
        mediaSource.addEventListener('sourceopen', function () {
          sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
          sourceBuffer.addEventListener('updateend', function () {
            video.play();
          });
        });
      } else {
        console.error("Unsupported MIME type or codec: ", mimeCodec);
      }

      /**
       * Add the various callback handlers to the PeerConnection.
       * Shared between both clients.
       */
      var setupPeerConnection = function () {
        peerConnection = new RTCPeerConnection({
          iceServers: [{
              urls: [
                "stun:stun.l.google.com:19302",
                "stun:stun1.l.google.com:19302",
                "stun:stun2.l.google.com:19302",
                "stun:stun3.l.google.com:19302",
                "stun:stun4.l.google.com:19302"
        ]}]});

        peerConnection.onicecandidate = function (event) {
          if (event.candidate) {
            reliableSocket.sendMessage("candidate", event.candidate);
          } else {
            datachannel_log_msg("All local candidates received");
          }
        };

        peerConnection.ondatachannel = function (event) {
          if (event.channel.label == dataChannelLabel) {
            dataChannel = event.channel;
            datachannel_log_msg("DataChannel received");
            setupDataChannel(event.channel);
          } else {
            datachannel_log_msg("Unknown CataChannel label: " + event.channel.label);
          }
        }
      };

      /**
       * Add the various callback handlers to the DataChannel.
       * Shared between both clients.
       */
      var setupDataChannel = function (dataChannel) {
        dataChannel.onopen = function (e) {
          datachannel_log_msg("DataChannel open and ready to be used");

          $("#send_datachannel_msg").click(function () {
            var msg = $("#datachannel_msg").val();
            datachannel_log_msg("Sending message: " + msg);
            dataChannel.send(msg);
          });
        };

        dataChannel.onclose = function () {
          datachannel_log_msg("DataChannel closed");
        };

        dataChannel.onerror = function (e) {
          datachannel_log_msg("DataChannel error: " + e.message);
          console.log(e);
        };

        dataChannel.onmessage = function (e) {
          datachannel_log_msg("Received message: " + e.data);
          if (sourceBuffer != null) {
            sourceBuffer.appendBuffer(e.data);
          } else {
            console.log("Got data but sourceBuffer is null");
          }
        };
      };

      var createOffer = function () {
        setupPeerConnection();
        dataChannel = peerConnection.createDataChannel("testchannel");
        setupDataChannel(dataChannel);

        peerConnection.createOffer().then(function(offer) {
          return peerConnection.setLocalDescription(offer);
        })
        .then(function() {
          reliableSocket.sendMessage("offer", peerConnection.localDescription);
        })
        .catch(function(reason) {
          // An error occurred, so handle the failure to connect
          console.log("RTC Error", reason);
        });
      };

      var createAnswer = function (msg) {
        setupPeerConnection();

        var desc = new RTCSessionDescription(msg);

        peerConnection.setRemoteDescription(desc)
        .then(function () {
          return peerConnection.createAnswer();
        })
        .then(function(answer) {
          return peerConnection.setLocalDescription(answer);
        })
        .then(function() {
          reliableSocket.sendMessage("answer", peerConnection.localDescription);
        })
        .catch(function () {
          console.log("RTC Error", reason);
        });
      };

      var handleCandidate = function (msg) {
        var candidate = new RTCIceCandidate(msg);
        peerConnection.addIceCandidate(candidate).then(function () {
          datachannel_log_msg("New remote candidate received");
        }).catch(function (e) {
          console.log("Error: Failure during addIceCandidate()", e);
        });
      }

      $("#connect_channel").on('click', function (e) {
        var channel_name = $("#channel_name").val();
        var wsAddress = "ws://" + window.location.host + "/channel/" + channel_name;
        console.log("Attempting WebSocket connection to " + wsAddress);

        reliableSocket = new WebSocket(wsAddress);

        reliableSocket.onopen = function (event) {
          // Socket is now ready to send and receive messages
          console.log("reliableSocket is open and ready to use");
          reliableSocket.sendMessage("client_connected", {});
        };

        reliableSocket.onerror = function (event) {
          // Socket failed to connect
        };

        reliableSocket.onclose = function (event) {
          console.log("ERROR: Reliable socket has closed");
        };

        // Simple helper to send JSON messages with a given type
        reliableSocket.sendMessage = function (type, msg) {
          reliable_log_msg("Sending msg of type: " + type);
          reliableSocket.send(JSON.stringify({"type": type, "msg": msg}));
        }

        reliableSocket.onmessage = function (event) {
          console.log("Got msg", event);
          var msg = JSON.parse(event.data);

          reliable_log_msg("Received msg of type: " + msg.type);
          console.log(msg);

          switch (msg.type) {
            case "client_connected":
              reliable_log_msg("Client connected: starting RTC handshake");
              createOffer();
              break;
            case "client_disconnected":
              reliable_log_msg("Remote client disconnected");
              break;
            case "offer":
              createAnswer(msg.msg);
              break;
            case "answer":
              peerConnection.setRemoteDescription(new RTCSessionDescription(msg.msg))
              .then(function () {
                have_answer = true;
                var i = 0;
                for (i = 0; i < remoteCandidates.length; i++) {
                  handleCandidate(remoteCandidates[i]);
                }
              });
              break;
            case "candidate":
              if (msg.msg.candidate) {
                if (!have_answer) {
                  remoteCandidates.push(msg.msg);
                } else {
                  handleCandidate(msg.msg);
                }
              } else {
                console.log("Remote peer has no more candidates");
              }
              break;
            default:
              console.log("WARNING: Ignoring unknown msg of type '" + msg.type + "'");
              break;
          }
        };


      });

    });

  </script>
</head>
<body>
  <video controls></video>
  <h1>WebRTC DataChannels Demo</h1>

  <div id="channel_select">
    <label for="channel_name">Enter a channel name:</label>
    <input id="channel_name" type="text"></input>
    <button id="connect_channel">Connect</button>
  </div>

  <div id="logs_container">
    <div id="reliable_logs">
      <h2>WebSocket Logs</h2>
      <ul id="reliable_log_list">
      </ul>
    </div>
    <div id="datachannel_logs">
      <h2>DataChannel Logs</h2>
      <label for="datachannel_msg">Send Msg:</label>
      <input id="datachannel_msg" type="text"></input>
      <button id="send_datachannel_msg">Send</button>
      <ul id="datachannel_log_list">
      </ul>
    </div>
  </div>

</body>
</html>


================================================
FILE: examples/websocket_client/CMakeLists.txt
================================================
add_executable(testclient
        json/json.h
        json/json-forwards.h
        easywsclient.cpp
        easywsclient.hpp
        jsoncpp.cpp
        testclient.cpp
        WebSocketWrapper.cpp
        WebSocketWrapper.hpp)

target_link_libraries(testclient rtcdcpp)


================================================
FILE: examples/websocket_client/WebSocketWrapper.cpp
================================================
#include "WebSocketWrapper.hpp"
#include <thread>
#include <iostream>

using namespace rtcdcpp;

WebSocketWrapper::WebSocketWrapper(std::string url) : url(url), send_queue() { ; }

WebSocketWrapper::~WebSocketWrapper() { delete this->ws; }

bool WebSocketWrapper::Initialize() {
  this->ws = WebSocket::from_url(this->url);
  return this->ws ? true : false;
}

void WebSocketWrapper::SetOnMessage(std::function<void(std::string)> onMessage) { this->onMessage = onMessage; }

void WebSocketWrapper::Start() { 
  this->stopping = false;
  this->send_loop = std::thread(&WebSocketWrapper::Loop, this); 
}

void WebSocketWrapper::Loop() {
  while (!this->stopping) {
    this->ws->poll();
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    if (!this->send_queue.empty()) {
      ChunkPtr chunk = this->send_queue.wait_and_pop();
      std::string msg(reinterpret_cast<char const*>(chunk->Data()), chunk->Length());
      this->ws->send(msg);
      this->ws->poll();
    }
    this->ws->dispatch(this->onMessage);
  }
}

void WebSocketWrapper::Send(std::string msg) { this->send_queue.push(std::shared_ptr<Chunk>(new Chunk((const void*)msg.c_str(), msg.length()))); }

void WebSocketWrapper::Close() { this->stopping = true; this->send_loop.join(); }


================================================
FILE: examples/websocket_client/WebSocketWrapper.hpp
================================================
/**
 * Simple libwebsockets C++ wrapper
 */

#include "easywsclient.hpp"

#include <assert.h>
#include <stdio.h>

#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <string>
#include <thread>
#include <vector>

#include <rtcdcpp/ChunkQueue.hpp>

using easywsclient::WebSocket;

class WebSocketWrapper {
 public:
  WebSocketWrapper(std::string url);
  virtual ~WebSocketWrapper();

  bool Initialize();
  void Start();
  void Send(std::string);
  void Close();

  void SetOnMessage(std::function<void(std::string)>);
  void SetOnClose(std::function<void()>);
  void SetOnError(std::function<void(std::string)>);

 private:
  void Loop();
  bool stopping;
  WebSocket::pointer ws;
  std::string url;
  rtcdcpp::ChunkQueue send_queue;
  std::function<void(std::string)> onMessage;
  std::thread send_loop;
};


================================================
FILE: examples/websocket_client/easywsclient.cpp
================================================

#ifdef _WIN32
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS  // _CRT_SECURE_NO_WARNINGS for sscanf errors in MSVC2013 Express
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <fcntl.h>
#pragma comment(lib, "ws2_32")
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#ifndef _SSIZE_T_DEFINED
typedef int ssize_t;
#define _SSIZE_T_DEFINED
#endif
#ifndef _SOCKET_T_DEFINED
typedef SOCKET socket_t;
#define _SOCKET_T_DEFINED
#endif
#ifndef snprintf
#define snprintf _snprintf_s
#endif
#if _MSC_VER >= 1600
// vs2010 or later
#include <stdint.h>
#else
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#endif
#define socketerrno WSAGetLastError()
#define SOCKET_EAGAIN_EINPROGRESS WSAEINPROGRESS
#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
#else
#include <fcntl.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef _SOCKET_T_DEFINED
typedef int socket_t;
#define _SOCKET_T_DEFINED
#endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET (-1)
#endif
#ifndef SOCKET_ERROR
#define SOCKET_ERROR (-1)
#endif
#define closesocket(s) ::close(s)
#include <errno.h>
#define socketerrno errno
#define SOCKET_EAGAIN_EINPROGRESS EAGAIN
#define SOCKET_EWOULDBLOCK EWOULDBLOCK
#endif

#include <string>
#include <vector>

#include "easywsclient.hpp"

using easywsclient::Callback_Imp;
using easywsclient::BytesCallback_Imp;

namespace {  // private module-only namespace

socket_t hostname_connect(const std::string& hostname, int port) {
  struct addrinfo hints;
  struct addrinfo* result;
  struct addrinfo* p;
  int ret;
  socket_t sockfd = INVALID_SOCKET;
  char sport[16];
  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  snprintf(sport, 16, "%d", port);
  if ((ret = getaddrinfo(hostname.c_str(), sport, &hints, &result)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
    return 1;
  }
  for (p = result; p != NULL; p = p->ai_next) {
    sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
    if (sockfd == INVALID_SOCKET) {
      continue;
    }
    if (connect(sockfd, p->ai_addr, p->ai_addrlen) != SOCKET_ERROR) {
      break;
    }
    closesocket(sockfd);
    sockfd = INVALID_SOCKET;
  }
  freeaddrinfo(result);
  return sockfd;
}

class _DummyWebSocket : public easywsclient::WebSocket {
 public:
  void poll(int timeout) {}
  void send(const std::string& message) {}
  void sendBinary(const std::string& message) {}
  void sendBinary(const std::vector<uint8_t>& message) {}
  void sendPing() {}
  void close() {}
  readyStateValues getReadyState() const { return CLOSED; }
  void _dispatch(Callback_Imp& callable) {}
  void _dispatchBinary(BytesCallback_Imp& callable) {}
};

class _RealWebSocket : public easywsclient::WebSocket {
 public:
  // http://tools.ietf.org/html/rfc6455#section-5.2  Base Framing Protocol
  //
  //  0                   1                   2                   3
  //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  // +-+-+-+-+-------+-+-------------+-------------------------------+
  // |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
  // |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
  // |N|V|V|V|       |S|             |   (if payload len==126/127)   |
  // | |1|2|3|       |K|             |                               |
  // +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
  // |     Extended payload length continued, if payload len == 127  |
  // + - - - - - - - - - - - - - - - +-------------------------------+
  // |                               |Masking-key, if MASK set to 1  |
  // +-------------------------------+-------------------------------+
  // | Masking-key (continued)       |          Payload Data         |
  // +-------------------------------- - - - - - - - - - - - - - - - +
  // :                     Payload Data continued ...                :
  // + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
  // |                     Payload Data continued ...                |
  // +---------------------------------------------------------------+
  struct wsheader_type {
    unsigned header_size;
    bool fin;
    bool mask;
    enum opcode_type {
      CONTINUATION = 0x0,
      TEXT_FRAME = 0x1,
      BINARY_FRAME = 0x2,
      CLOSE = 8,
      PING = 9,
      PONG = 0xa,
    } opcode;
    int N0;
    uint64_t N;
    uint8_t masking_key[4];
  };

  std::vector<uint8_t> rxbuf;
  std::vector<uint8_t> txbuf;
  std::vector<uint8_t> receivedData;

  socket_t sockfd;
  readyStateValues readyState;
  bool useMask;

  _RealWebSocket(socket_t sockfd, bool useMask) : sockfd(sockfd), readyState(OPEN), useMask(useMask) {}

  readyStateValues getReadyState() const { return readyState; }

  void poll(int timeout) {  // timeout in milliseconds
    if (readyState == CLOSED) {
      if (timeout > 0) {
        timeval tv = {timeout / 1000, (timeout % 1000) * 1000};
        select(0, NULL, NULL, NULL, &tv);
      }
      return;
    }
    if (timeout != 0) {
      fd_set rfds;
      fd_set wfds;
      timeval tv = {timeout / 1000, (timeout % 1000) * 1000};
      FD_ZERO(&rfds);
      FD_ZERO(&wfds);
      FD_SET(sockfd, &rfds);
      if (txbuf.size()) {
        FD_SET(sockfd, &wfds);
      }
      select(sockfd + 1, &rfds, &wfds, 0, timeout > 0 ? &tv : 0);
    }
    while (true) {
      // FD_ISSET(0, &rfds) will be true
      int N = rxbuf.size();
      ssize_t ret;
      rxbuf.resize(N + 1500);
      ret = recv(sockfd, (char*)&rxbuf[0] + N, 1500, 0);
      if (false) {
      } else if (ret < 0 && (socketerrno == SOCKET_EWOULDBLOCK || socketerrno == SOCKET_EAGAIN_EINPROGRESS)) {
        rxbuf.resize(N);
        break;
      } else if (ret <= 0) {
        rxbuf.resize(N);
        closesocket(sockfd);
        readyState = CLOSED;
        fputs(ret < 0 ? "Connection error!\n" : "Connection closed!\n", stderr);
        break;
      } else {
        rxbuf.resize(N + ret);
      }
    }
    while (txbuf.size()) {
      int ret = ::send(sockfd, (char*)&txbuf[0], txbuf.size(), 0);
      if (false) {
      }  // ??
      else if (ret < 0 && (socketerrno == SOCKET_EWOULDBLOCK || socketerrno == SOCKET_EAGAIN_EINPROGRESS)) {
        break;
      } else if (ret <= 0) {
        closesocket(sockfd);
        readyState = CLOSED;
        fputs(ret < 0 ? "Connection error!\n" : "Connection closed!\n", stderr);
        break;
      } else {
        txbuf.erase(txbuf.begin(), txbuf.begin() + ret);
      }
    }
    if (!txbuf.size() && readyState == CLOSING) {
      closesocket(sockfd);
      readyState = CLOSED;
    }
  }

  // Callable must have signature: void(const std::string & message).
  // Should work with C functions, C++ functors, and C++11 std::function and
  // lambda:
  // template<class Callable>
  // void dispatch(Callable callable)
  virtual void _dispatch(Callback_Imp& callable) {
    struct CallbackAdapter : public BytesCallback_Imp
    // Adapt void(const std::string<uint8_t>&) to void(const std::string&)
    {
      Callback_Imp& callable;
      CallbackAdapter(Callback_Imp& callable) : callable(callable) {}
      void operator()(const std::vector<uint8_t>& message) {
        std::string stringMessage(message.begin(), message.end());
        callable(stringMessage);
      }
    };
    CallbackAdapter bytesCallback(callable);
    _dispatchBinary(bytesCallback);
  }

  virtual void _dispatchBinary(BytesCallback_Imp& callable) {
    // TODO: consider acquiring a lock on rxbuf...
    while (true) {
      wsheader_type ws;
      if (rxbuf.size() < 2) {
        return; /* Need at least 2 */
      }
      const uint8_t* data = (uint8_t*)&rxbuf[0];  // peek, but don't consume
      ws.fin = (data[0] & 0x80) == 0x80;
      ws.opcode = (wsheader_type::opcode_type)(data[0] & 0x0f);
      ws.mask = (data[1] & 0x80) == 0x80;
      ws.N0 = (data[1] & 0x7f);
      ws.header_size = 2 + (ws.N0 == 126 ? 2 : 0) + (ws.N0 == 127 ? 8 : 0) + (ws.mask ? 4 : 0);
      if (rxbuf.size() < ws.header_size) {
        return; /* Need: ws.header_size - rxbuf.size() */
      }
      int i = 0;
      if (ws.N0 < 126) {
        ws.N = ws.N0;
        i = 2;
      } else if (ws.N0 == 126) {
        ws.N = 0;
        ws.N |= ((uint64_t)data[2]) << 8;
        ws.N |= ((uint64_t)data[3]) << 0;
        i = 4;
      } else if (ws.N0 == 127) {
        ws.N = 0;
        ws.N |= ((uint64_t)data[2]) << 56;
        ws.N |= ((uint64_t)data[3]) << 48;
        ws.N |= ((uint64_t)data[4]) << 40;
        ws.N |= ((uint64_t)data[5]) << 32;
        ws.N |= ((uint64_t)data[6]) << 24;
        ws.N |= ((uint64_t)data[7]) << 16;
        ws.N |= ((uint64_t)data[8]) << 8;
        ws.N |= ((uint64_t)data[9]) << 0;
        i = 10;
      }
      if (ws.mask) {
        ws.masking_key[0] = ((uint8_t)data[i + 0]) << 0;
        ws.masking_key[1] = ((uint8_t)data[i + 1]) << 0;
        ws.masking_key[2] = ((uint8_t)data[i + 2]) << 0;
        ws.masking_key[3] = ((uint8_t)data[i + 3]) << 0;
      } else {
        ws.masking_key[0] = 0;
        ws.masking_key[1] = 0;
        ws.masking_key[2] = 0;
        ws.masking_key[3] = 0;
      }
      if (rxbuf.size() < ws.header_size + ws.N) {
        return; /* Need: ws.header_size+ws.N - rxbuf.size() */
      }

      // We got a whole message, now do something with it:
      if (false) {
      } else if (ws.opcode == wsheader_type::TEXT_FRAME || ws.opcode == wsheader_type::BINARY_FRAME || ws.opcode == wsheader_type::CONTINUATION) {
        if (ws.mask) {
          for (size_t i = 0; i != ws.N; ++i) {
            rxbuf[i + ws.header_size] ^= ws.masking_key[i & 0x3];
          }
        }
        receivedData.insert(receivedData.end(), rxbuf.begin() + ws.header_size, rxbuf.begin() + ws.header_size + (size_t)ws.N);  // just feed
        if (ws.fin) {
          callable((const std::vector<uint8_t>)receivedData);
          receivedData.erase(receivedData.begin(), receivedData.end());
          std::vector<uint8_t>().swap(receivedData);  // free memory
        }
      } else if (ws.opcode == wsheader_type::PING) {
        if (ws.mask) {
          for (size_t i = 0; i != ws.N; ++i) {
            rxbuf[i + ws.header_size] ^= ws.masking_key[i & 0x3];
          }
        }
        std::string data(rxbuf.begin() + ws.header_size, rxbuf.begin() + ws.header_size + (size_t)ws.N);
        sendData(wsheader_type::PONG, data.size(), data.begin(), data.end());
      } else if (ws.opcode == wsheader_type::PONG) {
      } else if (ws.opcode == wsheader_type::CLOSE) {
        close();
      } else {
        fprintf(stderr, "ERROR: Got unexpected WebSocket message.\n");
        close();
      }

      rxbuf.erase(rxbuf.begin(), rxbuf.begin() + ws.header_size + (size_t)ws.N);
    }
  }

  void sendPing() {
    std::string empty;
    sendData(wsheader_type::PING, empty.size(), empty.begin(), empty.end());
  }

  void send(const std::string& message) { sendData(wsheader_type::TEXT_FRAME, message.size(), message.begin(), message.end()); }

  void sendBinary(const std::string& message) { sendData(wsheader_type::BINARY_FRAME, message.size(), message.begin(), message.end()); }

  void sendBinary(const std::vector<uint8_t>& message) { sendData(wsheader_type::BINARY_FRAME, message.size(), message.begin(), message.end()); }

  template <class Iterator>
  void sendData(wsheader_type::opcode_type type, uint64_t message_size, Iterator message_begin, Iterator message_end) {
    // TODO:
    // Masking key should (must) be derived from a high quality random
    // number generator, to mitigate attacks on non-WebSocket friendly
    // middleware:
    const uint8_t masking_key[4] = {0x12, 0x34, 0x56, 0x78};
    // TODO: consider acquiring a lock on txbuf...
    if (readyState == CLOSING || readyState == CLOSED) {
      return;
    }
    std::vector<uint8_t> header;
    header.assign(2 + (message_size >= 126 ? 2 : 0) + (message_size >= 65536 ? 6 : 0) + (useMask ? 4 : 0), 0);
    header[0] = 0x80 | type;
    if (false) {
    } else if (message_size < 126) {
      header[1] = (message_size & 0xff) | (useMask ? 0x80 : 0);
      if (useMask) {
        header[2] = masking_key[0];
        header[3] = masking_key[1];
        header[4] = masking_key[2];
        header[5] = masking_key[3];
      }
    } else if (message_size < 65536) {
      header[1] = 126 | (useMask ? 0x80 : 0);
      header[2] = (message_size >> 8) & 0xff;
      header[3] = (message_size >> 0) & 0xff;
      if (useMask) {
        header[4] = masking_key[0];
        header[5] = masking_key[1];
        header[6] = masking_key[2];
        header[7] = masking_key[3];
      }
    } else {  // TODO: run coverage testing here
      header[1] = 127 | (useMask ? 0x80 : 0);
      header[2] = (message_size >> 56) & 0xff;
      header[3] = (message_size >> 48) & 0xff;
      header[4] = (message_size >> 40) & 0xff;
      header[5] = (message_size >> 32) & 0xff;
      header[6] = (message_size >> 24) & 0xff;
      header[7] = (message_size >> 16) & 0xff;
      header[8] = (message_size >> 8) & 0xff;
      header[9] = (message_size >> 0) & 0xff;
      if (useMask) {
        header[10] = masking_key[0];
        header[11] = masking_key[1];
        header[12] = masking_key[2];
        header[13] = masking_key[3];
      }
    }
    // N.B. - txbuf will keep growing until it can be transmitted over the socket:
    txbuf.insert(txbuf.end(), header.begin(), header.end());
    txbuf.insert(txbuf.end(), message_begin, message_end);
    if (useMask) {
      for (size_t i = 0; i != message_size; ++i) {
        *(txbuf.end() - message_size + i) ^= masking_key[i & 0x3];
      }
    }
  }

  void close() {
    if (readyState == CLOSING || readyState == CLOSED) {
      return;
    }
    readyState = CLOSING;
    uint8_t closeFrame[6] = {0x88, 0x80, 0x00, 0x00, 0x00, 0x00};  // last 4 bytes are a masking key
    std::vector<uint8_t> header(closeFrame, closeFrame + 6);
    txbuf.insert(txbuf.end(), header.begin(), header.end());
  }
};

easywsclient::WebSocket::pointer from_url(const std::string& url, bool useMask, const std::string& origin) {
  char host[128];
  int port;
  char path[128];
  if (url.size() >= 128) {
    fprintf(stderr, "ERROR: url size limit exceeded: %s\n", url.c_str());
    return NULL;
  }
  if (origin.size() >= 200) {
    fprintf(stderr, "ERROR: origin size limit exceeded: %s\n", origin.c_str());
    return NULL;
  }
  if (false) {
  } else if (sscanf(url.c_str(), "ws://%[^:/]:%d/%s", host, &port, path) == 3) {
  } else if (sscanf(url.c_str(), "ws://%[^:/]/%s", host, path) == 2) {
    port = 80;
  } else if (sscanf(url.c_str(), "ws://%[^:/]:%d", host, &port) == 2) {
    path[0] = '\0';
  } else if (sscanf(url.c_str(), "ws://%[^:/]", host) == 1) {
    port = 80;
    path[0] = '\0';
  } else {
    fprintf(stderr, "ERROR: Could not parse WebSocket url: %s\n", url.c_str());
    return NULL;
  }
  fprintf(stderr, "easywsclient: connecting: host=%s port=%d path=/%s\n", host, port, path);
  socket_t sockfd = hostname_connect(host, port);
  if (sockfd == INVALID_SOCKET) {
    fprintf(stderr, "Unable to connect to %s:%d\n", host, port);
    return NULL;
  }
  {
    // XXX: this should be done non-blocking,
    char line[256];
    int status;
    int i;
    snprintf(line, 256, "GET /%s HTTP/1.1\r\n", path);
    ::send(sockfd, line, strlen(line), 0);
    if (port == 80) {
      snprintf(line, 256, "Host: %s\r\n", host);
      ::send(sockfd, line, strlen(line), 0);
    } else {
      snprintf(line, 256, "Host: %s:%d\r\n", host, port);
      ::send(sockfd, line, strlen(line), 0);
    }
    snprintf(line, 256, "Upgrade: websocket\r\n");
    ::send(sockfd, line, strlen(line), 0);
    snprintf(line, 256, "Connection: Upgrade\r\n");
    ::send(sockfd, line, strlen(line), 0);
    if (!origin.empty()) {
      snprintf(line, 256, "Origin: %s\r\n", origin.c_str());
      ::send(sockfd, line, strlen(line), 0);
    }
    snprintf(line, 256, "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n");
    ::send(sockfd, line, strlen(line), 0);
    snprintf(line, 256, "Sec-WebSocket-Version: 13\r\n");
    ::send(sockfd, line, strlen(line), 0);
    snprintf(line, 256, "\r\n");
    ::send(sockfd, line, strlen(line), 0);
    for (i = 0; i < 2 || (i < 255 && line[i - 2] != '\r' && line[i - 1] != '\n'); ++i) {
      if (recv(sockfd, line + i, 1, 0) == 0) {
        return NULL;
      }
    }
    line[i] = 0;
    if (i == 255) {
      fprintf(stderr, "ERROR: Got invalid status line connecting to: %s\n", url.c_str());
      return NULL;
    }
    if (sscanf(line, "HTTP/1.1 %d", &status) != 1 || status != 101) {
      fprintf(stderr, "ERROR: Got bad status connecting to %s: %s", url.c_str(), line);
      return NULL;
    }
    // TODO: verify response headers,
    while (true) {
      for (i = 0; i < 2 || (i < 255 && line[i - 2] != '\r' && line[i - 1] != '\n'); ++i) {
        if (recv(sockfd, line + i, 1, 0) == 0) {
          return NULL;
        }
      }
      if (line[0] == '\r' && line[1] == '\n') {
        break;
      }
    }
  }
  int flag = 1;
  setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag));  // Disable Nagle's algorithm
#ifdef _WIN32
  u_long on = 1;
  ioctlsocket(sockfd, FIONBIO, &on);
#else
  fcntl(sockfd, F_SETFL, O_NONBLOCK);
#endif
  fprintf(stderr, "Connected to: %s\n", url.c_str());
  return easywsclient::WebSocket::pointer(new _RealWebSocket(sockfd, useMask));
}

}  // end of module-only namespace

namespace easywsclient {

WebSocket::pointer WebSocket::create_dummy() {
  static pointer dummy = pointer(new _DummyWebSocket);
  return dummy;
}

WebSocket::pointer WebSocket::from_url(const std::string& url, const std::string& origin) { return ::from_url(url, true, origin); }

WebSocket::pointer WebSocket::from_url_no_mask(const std::string& url, const std::string& origin) { return ::from_url(url, false, origin); }

}  // namespace easywsclient


================================================
FILE: examples/websocket_client/easywsclient.hpp
================================================
#ifndef EASYWSCLIENT_HPP_20120819_MIOFVASDTNUASZDQPLFD
#define EASYWSCLIENT_HPP_20120819_MIOFVASDTNUASZDQPLFD

// This code comes from:
// https://github.com/dhbaird/easywsclient
//
// To get the latest version:
// wget https://raw.github.com/dhbaird/easywsclient/master/easywsclient.hpp
// wget https://raw.github.com/dhbaird/easywsclient/master/easywsclient.cpp

#include <string>
#include <vector>

namespace easywsclient {

struct Callback_Imp {
  virtual void operator()(const std::string& message) = 0;
};
struct BytesCallback_Imp {
  virtual void operator()(const std::vector<uint8_t>& message) = 0;
};

class WebSocket {
 public:
  typedef WebSocket* pointer;
  typedef enum readyStateValues { CLOSING, CLOSED, CONNECTING, OPEN } readyStateValues;

  // Factories:
  static pointer create_dummy();
  static pointer from_url(const std::string& url, const std::string& origin = std::string());
  static pointer from_url_no_mask(const std::string& url, const std::string& origin = std::string());

  // Interfaces:
  virtual ~WebSocket() {}
  virtual void poll(int timeout = 0) = 0;  // timeout in milliseconds
  virtual void send(const std::string& message) = 0;
  virtual void sendBinary(const std::string& message) = 0;
  virtual void sendBinary(const std::vector<uint8_t>& message) = 0;
  virtual void sendPing() = 0;
  virtual void close() = 0;
  virtual readyStateValues getReadyState() const = 0;

  template <class Callable>
  void dispatch(Callable callable)
  // For callbacks that accept a string argument.
  {  // N.B. this is compatible with both C++11 lambdas, functors and C function pointers
    struct _Callback : public Callback_Imp {
      Callable& callable;
      _Callback(Callable& callable) : callable(callable) {}
      void operator()(const std::string& message) { callable(message); }
    };
    _Callback callback(callable);
    _dispatch(callback);
  }

  template <class Callable>
  void dispatchBinary(Callable callable)
  // For callbacks that accept a std::vector<uint8_t> argument.
  {  // N.B. this is compatible with both C++11 lambdas, functors and C function pointers
    struct _Callback : public BytesCallback_Imp {
      Callable& callable;
      _Callback(Callable& callable) : callable(callable) {}
      void operator()(const std::vector<uint8_t>& message) { callable(message); }
    };
    _Callback callback(callable);
    _dispatchBinary(callback);
  }

 protected:
  virtual void _dispatch(Callback_Imp& callable) = 0;
  virtual void _dispatchBinary(BytesCallback_Imp& callable) = 0;
};

}  // namespace easywsclient

#endif /* EASYWSCLIENT_HPP_20120819_MIOFVASDTNUASZDQPLFD */


================================================
FILE: examples/websocket_client/json/json-forwards.h
================================================
/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).
/// It is intended to be used with #include "json/json-forwards.h"
/// This header provides forward declaration for all JsonCpp types.

// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: LICENSE
// //////////////////////////////////////////////////////////////////////

/*
The JsonCpp library's source code, including accompanying documentation,
tests and demonstration applications, are licensed under the following
conditions...

The author (Baptiste Lepilleur) explicitly disclaims copyright in all
jurisdictions which recognize such a disclaimer. In such jurisdictions,
this software is released into the Public Domain.

In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
released under the terms of the MIT License (see below).

In jurisdictions which recognize Public Domain property, the user of this
software may choose to accept it either as 1) Public Domain, 2) under the
conditions of the MIT License (see below), or 3) under the terms of dual
Public Domain/MIT License conditions described here, as they choose.

The MIT License is about as close to Public Domain as a license can get, and is
described in clear, concise terms at:

   http://en.wikipedia.org/wiki/MIT_License

The full text of the MIT License follows:

========================================================================
Copyright (c) 2007-2010 Baptiste Lepilleur

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
========================================================================
(END LICENSE TEXT)

The MIT license is compatible with both the GPL and commercial
software, affording one all of the rights of Public Domain with the
minor nuisance of being required to keep the above copyright notice
and license text in the source code. Note also that by accepting the
Public Domain "license" you can re-license your copy using whatever
license you like.

*/

// //////////////////////////////////////////////////////////////////////
// End of content of file: LICENSE
// //////////////////////////////////////////////////////////////////////

#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED
#define JSON_FORWARD_AMALGATED_H_INCLUDED
/// If defined, indicates that the source file is amalgated
/// to prevent private header inclusion.
#define JSON_IS_AMALGAMATION

// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/config.h
// //////////////////////////////////////////////////////////////////////

// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#ifndef JSON_CONFIG_H_INCLUDED
#define JSON_CONFIG_H_INCLUDED
#include <stddef.h>
#include <string>  //typdef String

/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1

/// If defined, indicates that json may leverage CppTL library
//#  define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of
/// std::map
/// as Value container.
//#  define JSON_USE_CPPTL_SMALLMAP 1

// If non-zero, the library uses exceptions to report bad input instead of C
// assertion macros. The default is to use exceptions.
#ifndef JSON_USE_EXCEPTION
#define JSON_USE_EXCEPTION 1
#endif

/// If defined, indicates that the source file is amalgated
/// to prevent private header inclusion.
/// Remarks: it is automatically defined in the generated amalgated header.
// #define JSON_IS_AMALGAMATION

#ifdef JSON_IN_CPPTL
#include <cpptl/config.h>
#ifndef JSON_USE_CPPTL
#define JSON_USE_CPPTL 1
#endif
#endif

#ifdef JSON_IN_CPPTL
#define JSON_API CPPTL_API
#elif defined(JSON_DLL_BUILD)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllexport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif  // if defined(_MSC_VER)
#elif defined(JSON_DLL)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllimport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif  // if defined(_MSC_VER)
#endif  // ifdef JSON_IN_CPPTL
#if !defined(JSON_API)
#define JSON_API
#endif

// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
// integer
// Storages, and 64 bits integer support is disabled.
// #define JSON_NO_INT64 1

#if defined(_MSC_VER)  // MSVC
#if _MSC_VER <= 1200   // MSVC 6
                       // Microsoft Visual Studio 6 only support conversion from __int64 to double
                       // (no conversion from unsigned __int64).
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
// characters in the debug information)
// All projects I've ever seen with VS6 were using this globally (not bothering
// with pragma push/pop).
#pragma warning(disable : 4786)
#endif  // MSVC 6

#if _MSC_VER >= 1500  // MSVC 2008
                      /// Indicates that the following function is deprecated.
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
#endif

#endif  // defined(_MSC_VER)

// In c++11 the override keyword allows you to explicity define that a function
// is intended to override the base-class version.  This makes the code more
// managable and fixes a set of common hard-to-find bugs.
#if __cplusplus >= 201103L
#define JSONCPP_OVERRIDE override
#elif defined(_MSC_VER) && _MSC_VER > 1600
#define JSONCPP_OVERRIDE override
#else
#define JSONCPP_OVERRIDE
#endif

#ifndef JSON_HAS_RVALUE_REFERENCES

#if defined(_MSC_VER) && _MSC_VER >= 1600  // MSVC >= 2010
#define JSON_HAS_RVALUE_REFERENCES 1
#endif  // MSVC >= 2010

#ifdef __clang__
#if __has_feature(cxx_rvalue_references)
#define JSON_HAS_RVALUE_REFERENCES 1
#endif  // has_feature

#elif defined __GNUC__  // not clang (gcc comes later since clang emulates gcc)
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
#define JSON_HAS_RVALUE_REFERENCES 1
#endif  // GXX_EXPERIMENTAL

#endif  // __clang__ || __GNUC__

#endif  // not defined JSON_HAS_RVALUE_REFERENCES

#ifndef JSON_HAS_RVALUE_REFERENCES
#define JSON_HAS_RVALUE_REFERENCES 0
#endif

#ifdef __clang__
#elif defined __GNUC__  // not clang (gcc comes later since clang emulates gcc)
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
#endif  // GNUC version
#endif  // __clang__ || __GNUC__

#if !defined(JSONCPP_DEPRECATED)
#define JSONCPP_DEPRECATED(message)
#endif  // if !defined(JSONCPP_DEPRECATED)

#if __GNUC__ >= 6
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
#endif

#if !defined(JSON_IS_AMALGAMATION)

#include "version.h"

#if JSONCPP_USING_SECURE_MEMORY
#include "allocator.h"  //typedef Allocator
#endif

#endif  // if !defined(JSON_IS_AMALGAMATION)

namespace Json {
typedef int Int;
typedef unsigned int UInt;
#if defined(JSON_NO_INT64)
typedef int LargestInt;
typedef unsigned int LargestUInt;
#undef JSON_HAS_INT64
#else                  // if defined(JSON_NO_INT64)
// For Microsoft Visual use specific types as long long is not supported
#if defined(_MSC_VER)  // Microsoft Visual Studio
typedef __int64 Int64;
typedef unsigned __int64 UInt64;
#else                  // if defined(_MSC_VER) // Other platforms, use long long
typedef long long int Int64;
typedef unsigned long long int UInt64;
#endif                 // if defined(_MSC_VER)
typedef Int64 LargestInt;
typedef UInt64 LargestUInt;
#define JSON_HAS_INT64
#endif  // if defined(JSON_NO_INT64)
#if JSONCPP_USING_SECURE_MEMORY
#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char>>
#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char>>
#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>>
#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char>>
#define JSONCPP_ISTREAM std::istream
#else
#define JSONCPP_STRING std::string
#define JSONCPP_OSTRINGSTREAM std::ostringstream
#define JSONCPP_OSTREAM std::ostream
#define JSONCPP_ISTRINGSTREAM std::istringstream
#define JSONCPP_ISTREAM std::istream
#endif  // if JSONCPP_USING_SECURE_MEMORY
}  // end namespace Json

#endif  // JSON_CONFIG_H_INCLUDED

// //////////////////////////////////////////////////////////////////////
// End of content of file: include/json/config.h
// //////////////////////////////////////////////////////////////////////

// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/forwards.h
// //////////////////////////////////////////////////////////////////////

// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#ifndef JSON_FORWARDS_H_INCLUDED
#define JSON_FORWARDS_H_INCLUDED

#if !defined(JSON_IS_AMALGAMATION)
#include "config.h"
#endif  // if !defined(JSON_IS_AMALGAMATION)

namespace Json {

// writer.h
class FastWriter;
class StyledWriter;

// reader.h
class Reader;

// features.h
class Features;

// value.h
typedef unsigned int ArrayIndex;
class StaticString;
class Path;
class PathArgument;
class Value;
class ValueIteratorBase;
class ValueIterator;
class ValueConstIterator;

}  // namespace Json

#endif  // JSON_FORWARDS_H_INCLUDED

// //////////////////////////////////////////////////////////////////////
// End of content of file: include/json/forwards.h
// //////////////////////////////////////////////////////////////////////

#endif  // ifndef JSON_FORWARD_AMALGATED_H_INCLUDED


================================================
FILE: examples/websocket_client/json/json.h
================================================
/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).
/// It is intended to be used with #include "json/json.h"

// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: LICENSE
// //////////////////////////////////////////////////////////////////////

/*
The JsonCpp library's source code, including accompanying documentation,
tests and demonstration applications, are licensed under the following
conditions...

The author (Baptiste Lepilleur) explicitly disclaims copyright in all
jurisdictions which recognize such a disclaimer. In such jurisdictions,
this software is released into the Public Domain.

In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
released under the terms of the MIT License (see below).

In jurisdictions which recognize Public Domain property, the user of this
software may choose to accept it either as 1) Public Domain, 2) under the
conditions of the MIT License (see below), or 3) under the terms of dual
Public Domain/MIT License conditions described here, as they choose.

The MIT License is about as close to Public Domain as a license can get, and is
described in clear, concise terms at:

   http://en.wikipedia.org/wiki/MIT_License

The full text of the MIT License follows:

========================================================================
Copyright (c) 2007-2010 Baptiste Lepilleur

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
========================================================================
(END LICENSE TEXT)

The MIT license is compatible with both the GPL and commercial
software, affording one all of the rights of Public Domain with the
minor nuisance of being required to keep the above copyright notice
and license text in the source code. Note also that by accepting the
Public Domain "license" you can re-license your copy using whatever
license you like.

*/

// //////////////////////////////////////////////////////////////////////
// End of content of file: LICENSE
// //////////////////////////////////////////////////////////////////////

#ifndef JSON_AMALGATED_H_INCLUDED
#define JSON_AMALGATED_H_INCLUDED
/// If defined, indicates that the source file is amalgated
/// to prevent private header inclusion.
#define JSON_IS_AMALGAMATION

// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/version.h
// //////////////////////////////////////////////////////////////////////

// DO NOT EDIT. This file (and "version") is generated by CMake.
// Run CMake configure step to update it.
#ifndef JSON_VERSION_H_INCLUDED
#define JSON_VERSION_H_INCLUDED

#define JSONCPP_VERSION_STRING "1.7.4"
#define JSONCPP_VERSION_MAJOR 1
#define JSONCPP_VERSION_MINOR 7
#define JSONCPP_VERSION_PATCH 4
#define JSONCPP_VERSION_QUALIFIER
#define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))

#ifdef JSONCPP_USING_SECURE_MEMORY
#undef JSONCPP_USING_SECURE_MEMORY
#endif
#define JSONCPP_USING_SECURE_MEMORY 0
// If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory.

#endif  // JSON_VERSION_H_INCLUDED

// //////////////////////////////////////////////////////////////////////
// End of content of file: include/json/version.h
// //////////////////////////////////////////////////////////////////////

// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/config.h
// //////////////////////////////////////////////////////////////////////

// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#ifndef JSON_CONFIG_H_INCLUDED
#define JSON_CONFIG_H_INCLUDED
#include <stddef.h>
#include <string>  //typdef String

/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1

/// If defined, indicates that json may leverage CppTL library
//#  define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of
/// std::map
/// as Value container.
//#  define JSON_USE_CPPTL_SMALLMAP 1

// If non-zero, the library uses exceptions to report bad input instead of C
// assertion macros. The default is to use exceptions.
#ifndef JSON_USE_EXCEPTION
#define JSON_USE_EXCEPTION 1
#endif

/// If defined, indicates that the source file is amalgated
/// to prevent private header inclusion.
/// Remarks: it is automatically defined in the generated amalgated header.
// #define JSON_IS_AMALGAMATION

#ifdef JSON_IN_CPPTL
#include <cpptl/config.h>
#ifndef JSON_USE_CPPTL
#define JSON_USE_CPPTL 1
#endif
#endif

#ifdef JSON_IN_CPPTL
#define JSON_API CPPTL_API
#elif defined(JSON_DLL_BUILD)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllexport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif  // if defined(_MSC_VER)
#elif defined(JSON_DLL)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllimport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif  // if defined(_MSC_VER)
#endif  // ifdef JSON_IN_CPPTL
#if !defined(JSON_API)
#define JSON_API
#endif

// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
// integer
// Storages, and 64 bits integer support is disabled.
// #define JSON_NO_INT64 1

#if defined(_MSC_VER)  // MSVC
#if _MSC_VER <= 1200   // MSVC 6
                       // Microsoft Visual Studio 6 only support conversion from __int64 to double
                       // (no conversion from unsigned __int64).
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
// characters in the debug information)
// All projects I've ever seen with VS6 were using this globally (not bothering
// with pragma push/pop).
#pragma warning(disable : 4786)
#endif  // MSVC 6

#if _MSC_VER >= 1500  // MSVC 2008
                      /// Indicates that the following function is deprecated.
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
#endif

#endif  // defined(_MSC_VER)

// In c++11 the override keyword allows you to explicity define that a function
// is intended to override the base-class version.  This makes the code more
// managable and fixes a set of common hard-to-find bugs.
#if __cplusplus >= 201103L
#define JSONCPP_OVERRIDE override
#elif defined(_MSC_VER) && _MSC_VER > 1600
#define JSONCPP_OVERRIDE override
#else
#define JSONCPP_OVERRIDE
#endif

#ifndef JSON_HAS_RVALUE_REFERENCES

#if defined(_MSC_VER) && _MSC_VER >= 1600  // MSVC >= 2010
#define JSON_HAS_RVALUE_REFERENCES 1
#endif  // MSVC >= 2010

#ifdef __clang__
#if __has_feature(cxx_rvalue_references)
#define JSON_HAS_RVALUE_REFERENCES 1
#endif  // has_feature

#elif defined __GNUC__  // not clang (gcc comes later since clang emulates gcc)
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
#define JSON_HAS_RVALUE_REFERENCES 1
#endif  // GXX_EXPERIMENTAL

#endif  // __clang__ || __GNUC__

#endif  // not defined JSON_HAS_RVALUE_REFERENCES

#ifndef JSON_HAS_RVALUE_REFERENCES
#define JSON_HAS_RVALUE_REFERENCES 0
#endif

#ifdef __clang__
#elif defined __GNUC__  // not clang (gcc comes later since clang emulates gcc)
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
#endif  // GNUC version
#endif  // __clang__ || __GNUC__

#if !defined(JSONCPP_DEPRECATED)
#define JSONCPP_DEPRECATED(message)
#endif  // if !defined(JSONCPP_DEPRECATED)

#if __GNUC__ >= 6
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
#endif

#if !defined(JSON_IS_AMALGAMATION)

#include "version.h"

#if JSONCPP_USING_SECURE_MEMORY
#include "allocator.h"  //typedef Allocator
#endif

#endif  // if !defined(JSON_IS_AMALGAMATION)

namespace Json {
typedef int Int;
typedef unsigned int UInt;
#if defined(JSON_NO_INT64)
typedef int LargestInt;
typedef unsigned int LargestUInt;
#undef JSON_HAS_INT64
#else                  // if defined(JSON_NO_INT64)
// For Microsoft Visual use specific types as long long is not supported
#if defined(_MSC_VER)  // Microsoft Visual Studio
typedef __int64 Int64;
typedef unsigned __int64 UInt64;
#else                  // if defined(_MSC_VER) // Other platforms, use long long
typedef long long int Int64;
typedef unsigned long long int UInt64;
#endif                 // if defined(_MSC_VER)
typedef Int64 LargestInt;
typedef UInt64 LargestUInt;
#define JSON_HAS_INT64
#endif  // if defined(JSON_NO_INT64)
#if JSONCPP_USING_SECURE_MEMORY
#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char>>
#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char>>
#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>>
#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char>>
#define JSONCPP_ISTREAM std::istream
#else
#define JSONCPP_STRING std::string
#define JSONCPP_OSTRINGSTREAM std::ostringstream
#define JSONCPP_OSTREAM std::ostream
#define JSONCPP_ISTRINGSTREAM std::istringstream
#define JSONCPP_ISTREAM std::istream
#endif  // if JSONCPP_USING_SECURE_MEMORY
}  // end namespace Json

#endif  // JSON_CONFIG_H_INCLUDED

// //////////////////////////////////////////////////////////////////////
// End of content of file: include/json/config.h
// //////////////////////////////////////////////////////////////////////

// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/forwards.h
// //////////////////////////////////////////////////////////////////////

// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#ifndef JSON_FORWARDS_H_INCLUDED
#define JSON_FORWARDS_H_INCLUDED

#if !defined(JSON_IS_AMALGAMATION)
#include "config.h"
#endif  // if !defined(JSON_IS_AMALGAMATION)

namespace Json {

// writer.h
class FastWriter;
class StyledWriter;

// reader.h
class Reader;

// features.h
class Features;

// value.h
typedef unsigned int ArrayIndex;
class StaticString;
class Path;
class PathArgument;
class Value;
class ValueIteratorBase;
class ValueIterator;
class ValueConstIterator;

}  // namespace Json

#endif  // JSON_FORWARDS_H_INCLUDED

// //////////////////////////////////////////////////////////////////////
// End of content of file: include/json/forwards.h
// //////////////////////////////////////////////////////////////////////

// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/features.h
// //////////////////////////////////////////////////////////////////////

// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
#define CPPTL_JSON_FEATURES_H_INCLUDED

#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif  // if !defined(JSON_IS_AMALGAMATION)

namespace Json {

/** \brief Configuration passed to reader and writer.
 * This configuration object can be used to force the Reader or Writer
 * to behave in a standard conforming way.
 */
class JSON_API Features {
 public:
  /** \brief A configuration that allows all features and assumes all strings
   * are UTF-8.
   * - C & C++ comments are allowed
   * - Root object can be any JSON value
   * - Assumes Value strings are encoded in UTF-8
   */
  static Features all();

  /** \brief A configuration that is strictly compatible with the JSON
   * specification.
   * - Comments are forbidden.
   * - Root object must be either an array or an object value.
   * - Assumes Value strings are encoded in UTF-8
   */
  static Features strictMode();

  /** \brief Initialize the configuration like JsonConfig::allFeatures;
   */
  Features();

  /// \c true if comments are allowed. Default: \c true.
  bool allowComments_;

  /// \c true if root must be either an array or an object value. Default: \c
  /// false.
  bool strictRoot_;

  /// \c true if dropped null placeholders are allowed. Default: \c false.
  bool allowDroppedNullPlaceholders_;

  /// \c true if numeric object key are allowed. Default: \c false.
  bool allowNumericKeys_;
};

}  // namespace Json

#endif  // CPPTL_JSON_FEATURES_H_INCLUDED

// //////////////////////////////////////////////////////////////////////
// End of content of file: include/json/features.h
// //////////////////////////////////////////////////////////////////////

// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/value.h
// //////////////////////////////////////////////////////////////////////

// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#ifndef CPPTL_JSON_H_INCLUDED
#define CPPTL_JSON_H_INCLUDED

#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif  // if !defined(JSON_IS_AMALGAMATION)
#include <exception>
#include <string>
#include <vector>

#ifndef JSON_USE_CPPTL_SMALLMAP
#include <map>
#else
#include <cpptl/smallmap.h>
#endif
#ifdef JSON_USE_CPPTL
#include <cpptl/forwards.h>
#endif

// Conditional NORETURN attribute on the throw functions would:
// a) suppress false positives from static code analysis
// b) possibly improve optimization opportunities.
#if !defined(JSONCPP_NORETURN)
#if defined(_MSC_VER)
#define JSONCPP_NORETURN __declspec(noreturn)
#elif defined(__GNUC__)
#define JSONCPP_NORETURN __attribute__((__noreturn__))
#else
#define JSONCPP_NORETURN
#endif
#endif

// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251)
#endif  // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)

/** \brief JSON (JavaScript Object Notation).
 */
namespace Json {

/** Base class for all exceptions we throw.
 *
 * We use nothing but these internally. Of course, STL can throw others.
 */
class JSON_API Exception : public std::exception {
 public:
  Exception(JSONCPP_STRING const& msg);
  ~Exception() throw() JSONCPP_OVERRIDE;
  char const* what() const throw() JSONCPP_OVERRIDE;

 protected:
  JSONCPP_STRING msg_;
};

/** Exceptions which the user cannot easily avoid.
 *
 * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
 *
 * \remark derived from Json::Exception
 */
class JSON_API RuntimeError : public Exception {
 public:
  RuntimeError(JSONCPP_STRING const& msg);
};

/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
 *
 * These are precondition-violations (user bugs) and internal errors (our bugs).
 *
 * \remark derived from Json::Exception
 */
class JSON_API LogicError : public Exception {
 public:
  LogicError(JSONCPP_STRING const& msg);
};

/// used internally
JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg);
/// used internally
JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg);

/** \brief Type of the value held by a Value object.
 */
enum ValueType {
  nullValue = 0,  ///< 'null' value
  intValue,       ///< signed integer value
  uintValue,      ///< unsigned integer value
  realValue,      ///< double value
  stringValue,    ///< UTF-8 string value
  booleanValue,   ///< bool value
  arrayValue,     ///< array value (ordered list)
  objectValue     ///< object value (collection of name/value pairs).
};

enum CommentPlacement {
  commentBefore = 0,       ///< a comment placed on the line before a value
  commentAfterOnSameLine,  ///< a comment just after a value on the same line
  commentAfter,            ///< a comment on the line after a value (only make sense for
  /// root value)
  numberOfCommentPlacement
};

//# ifdef JSON_USE_CPPTL
//   typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
//   typedef CppTL::AnyEnumerator<const Value &> EnumValues;
//# endif

/** \brief Lightweight wrapper to tag static string.
 *
 * Value constructor and objectValue member assignement takes advantage of the
 * StaticString and avoid the cost of string duplication when storing the
 * string or the member name.
 *
 * Example of usage:
 * \code
 * Json::Value aValue( StaticString("some text") );
 * Json::Value object;
 * static const StaticString code("code");
 * object[code] = 1234;
 * \endcode
 */
class JSON_API StaticString {
 public:
  explicit StaticString(const char* czstring) : c_str_(czstring) {}

  operator const char*() const { return c_str_; }

  const char* c_str() const { return c_str_; }

 private:
  const char* c_str_;
};

/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
 *
 * This class is a discriminated union wrapper that can represents a:
 * - signed integer [range: Value::minInt - Value::maxInt]
 * - unsigned integer (range: 0 - Value::maxUInt)
 * - double
 * - UTF-8 string
 * - boolean
 * - 'null'
 * - an ordered list of Value
 * - collection of name/value pairs (javascript object)
 *
 * The type of the held value is represented by a #ValueType and
 * can be obtained using type().
 *
 * Values of an #objectValue or #arrayValue can be accessed using operator[]()
 * methods.
 * Non-const methods will automatically create the a #nullValue element
 * if it does not exist.
 * The sequence of an #arrayValue will be automatically resized and initialized
 * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
 *
 * The get() methods can be used to obtain default value in the case the
 * required element does not exist.
 *
 * It is possible to iterate over the list of a #objectValue values using
 * the getMemberNames() method.
 *
 * \note #Value string-length fit in size_t, but keys must be < 2^30.
 * (The reason is an implementation detail.) A #CharReader will raise an
 * exception if a bound is exceeded to avoid security holes in your app,
 * but the Value API does *not* check bounds. That is the responsibility
 * of the caller.
 */
class JSON_API Value {
  friend class ValueIteratorBase;

 public:
  typedef std::vector<JSONCPP_STRING> Members;
  typedef ValueIterator iterator;
  typedef ValueConstIterator const_iterator;
  typedef Json::UInt UInt;
  typedef Json::Int Int;
#if defined(JSON_HAS_INT64)
  typedef Json::UInt64 UInt64;
  typedef Json::Int64 Int64;
#endif  // defined(JSON_HAS_INT64)
  typedef Json::LargestInt LargestInt;
  typedef Json::LargestUInt LargestUInt;
  typedef Json::ArrayIndex ArrayIndex;

  static const Value& null;             ///< We regret this reference to a global instance; prefer the simpler Value().
  static const Value& nullRef;          ///< just a kludge for binary-compatibility; same as null
  static Value const& nullSingleton();  ///< Prefer this to null or nullRef.

  /// Minimum signed integer value that can be stored in a Json::Value.
  static const LargestInt minLargestInt;
  /// Maximum signed integer value that can be stored in a Json::Value.
  static const LargestInt maxLargestInt;
  /// Maximum unsigned integer value that can be stored in a Json::Value.
  static const LargestUInt maxLargestUInt;

  /// Minimum signed int value that can be stored in a Json::Value.
  static const Int minInt;
  /// Maximum signed int value that can be stored in a Json::Value.
  static const Int maxInt;
  /// Maximum unsigned int value that can be stored in a Json::Value.
  static const UInt maxUInt;

#if defined(JSON_HAS_INT64)
  /// Minimum signed 64 bits int value that can be stored in a Json::Value.
  static const Int64 minInt64;
  /// Maximum signed 64 bits int value that can be stored in a Json::Value.
  static const Int64 maxInt64;
  /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
  static const UInt64 maxUInt64;
#endif  // defined(JSON_HAS_INT64)

 private:
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
  class CZString {
   public:
    enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy };
    CZString(ArrayIndex index);
    CZString(char const* str, unsigned length, DuplicationPolicy allocate);
    CZString(CZString const& other);
#if JSON_HAS_RVALUE_REFERENCES
    CZString(CZString&& other);
#endif
    ~CZString();
    CZString& operator=(CZString other);
    bool operator<(CZString const& other) const;
    bool operator==(CZString const& other) const;
    ArrayIndex index() const;
    // const char* c_str() const; ///< \deprecated
    char const* data() const;
    unsigned length() const;
    bool isStaticString() const;

   private:
    void swap(CZString& other);

    struct StringStorage {
      unsigned policy_ : 2;
      unsigned length_ : 30;  // 1GB max
    };

    char const* cstr_;  // actually, a prefixed string, unless policy is noDup
    union {
      ArrayIndex index_;
      StringStorage storage_;
    };
  };

 public:
#ifndef JSON_USE_CPPTL_SMALLMAP
  typedef std::map<CZString, Value> ObjectValues;
#else
  typedef CppTL::SmallMap<CZString, Value> ObjectValues;
#endif  // ifndef JSON_USE_CPPTL_SMALLMAP
#endif  // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION

 public:
  /** \brief Create a default Value of the given type.

    This is a very useful constructor.
    To create an empty array, pass arrayValue.
    To create an empty object, pass objectValue.
    Another Value can then be set to this one by assignment.
This is useful since clear() and resize() will not alter types.

    Examples:
\code
Json::Value null_value; // null
Json::Value arr_value(Json::arrayValue); // []
Json::Value obj_value(Json::objectValue); // {}
\endcode
  */
  Value(ValueType type = nullValue);
  Value(Int value);
  Value(UInt value);
#if defined(JSON_HAS_INT64)
  Value(Int64 value);
  Value(UInt64 value);
#endif  // if defined(JSON_HAS_INT64)
  Value(double value);
  Value(const char* value);                   ///< Copy til first 0. (NULL causes to seg-fault.)
  Value(const char* begin, const char* end);  ///< Copy all, incl zeroes.
  /** \brief Constructs a value from a static string.

   * Like other value string constructor but do not duplicate the string for
   * internal storage. The given string must remain alive after the call to this
   * constructor.
   * \note This works only for null-terminated strings. (We cannot change the
   *   size of this class, so we have nowhere to store the length,
   *   which might be computed later for various operations.)
   *
   * Example of usage:
   * \code
   * static StaticString foo("some text");
   * Json::Value aValue(foo);
   * \endcode
   */
  Value(const StaticString& value);
  Value(const JSONCPP_STRING& value);  ///< Copy data() til size(). Embedded zeroes too.
#ifdef JSON_USE_CPPTL
  Value(const CppTL::ConstString& value);
#endif
  Value(bool value);
  /// Deep copy.
  Value(const Value& other);
#if JSON_HAS_RVALUE_REFERENCES
  /// Move constructor
  Value(Value&& other);
#endif
  ~Value();

  /// Deep copy, then swap(other).
  /// \note Over-write existing comments. To preserve comments, use #swapPayload().
  Value& operator=(Value other);
  /// Swap everything.
  void swap(Value& other);
  /// Swap values but leave comments and source offsets in place.
  void swapPayload(Value& other);

  ValueType type() const;

  /// Compare payload only, not comments etc.
  bool operator<(const Value& other) const;
  bool operator<=(const Value& other) const;
  bool operator>=(const Value& other) const;
  bool operator>(const Value& other) const;
  bool operator==(const Value& other) const;
  bool operator!=(const Value& other) const;
  int compare(const Value& other) const;

  const char* asCString() const;  ///< Embedded zeroes could cause you trouble!
#if JSONCPP_USING_SECURE_MEMORY
  unsigned getCStringLength() const;  // Allows you to understand the length of the CString
#endif
  JSONCPP_STRING asString() const;  ///< Embedded zeroes are possible.
  /** Get raw char* of string-value.
   *  \return false if !string. (Seg-fault if str or end are NULL.)
   */
  bool getString(char const** begin, char const** end) const;
#ifdef JSON_USE_CPPTL
  CppTL::ConstString asConstString() const;
#endif
  Int asInt() const;
  UInt asUInt() const;
#if defined(JSON_HAS_INT64)
  Int64 asInt64() const;
  UInt64 asUInt64() const;
#endif  // if defined(JSON_HAS_INT64)
  LargestInt asLargestInt() const;
  LargestUInt asLargestUInt() const;
  float asFloat() const;
  double asDouble() const;
  bool asBool() const;

  bool isNull() const;
  bool isBool() const;
  bool isInt() const;
  bool isInt64() const;
  bool isUInt() const;
  bool isUInt64() const;
  bool isIntegral() const;
  bool isDouble() const;
  bool isNumeric() const;
  bool isString() const;
  bool isArray() const;
  bool isObject() const;

  bool isConvertibleTo(ValueType other) const;

  /// Number of values in array or object
  ArrayIndex size() const;

  /// \brief Return true if empty array, empty object, or null;
  /// otherwise, false.
  bool empty() const;

  /// Return isNull()
  bool operator!() const;

  /// Remove all object members and array elements.
  /// \pre type() is arrayValue, objectValue, or nullValue
  /// \post type() is unchanged
  void clear();

  /// Resize the array to size elements.
  /// New elements are initialized to null.
  /// May only be called on nullValue or arrayValue.
  /// \pre type() is arrayValue or nullValue
  /// \post type() is arrayValue
  void resize(ArrayIndex size);

  /// Access an array element (zero based index ).
  /// If the array contains less than index element, then null value are
  /// inserted
  /// in the array so that its size is index+1.
  /// (You may need to say 'value[0u]' to get your compiler to distinguish
  ///  this from the operator[] which takes a string.)
  Value& operator[](ArrayIndex index);

  /// Access an array element (zero based index ).
  /// If the array contains less than index element, then null value are
  /// inserted
  /// in the array so that its size is index+1.
  /// (You may need to say 'value[0u]' to get your compiler to distinguish
  ///  this from the operator[] which takes a string.)
  Value& operator[](int index);

  /// Access an array element (zero based index )
  /// (You may need to say 'value[0u]' to get your compiler to distinguish
  ///  this from the operator[] which takes a string.)
  const Value& operator[](ArrayIndex index) const;

  /// Access an array element (zero based index )
  /// (You may need to say 'value[0u]' to get your compiler to distinguish
  ///  this from the operator[] which takes a string.)
  const Value& operator[](int index) const;

  /// If the array contains at least index+1 elements, returns the element
  /// value,
  /// otherwise returns defaultValue.
  Value get(ArrayIndex index, const Value& defaultValue) const;
  /// Return true if index < size().
  bool isValidIndex(ArrayIndex index) const;
  /// \brief Append value to array at the end.
  ///
  /// Equivalent to jsonvalue[jsonvalue.size()] = value;
  Value& append(const Value& value);

  /// Access an object value by name, create a null member if it does not exist.
  /// \note Because of our implementation, keys are limited to 2^30 -1 chars.
  ///  Exceeding that will cause an exception.
  Value& operator[](const char* key);
  /// Access an object value by name, returns null if there is no member with
  /// that name.
  const Value& operator[](const char* key) const;
  /// Access an object value by name, create a null member if it does not exist.
  /// \param key may contain embedded nulls.
  Value& operator[](const JSONCPP_STRING& key);
  /// Access an object value by name, returns null if there is no member with
  /// that name.
  /// \param key may contain embedded nulls.
  const Value& operator[](const JSONCPP_STRING& key) const;
  /** \brief Access an object value by name, create a null member if it does not
   exist.

   * If the object has no entry for that name, then the member name used to store
   * the new entry is not duplicated.
   * Example of use:
   * \code
   * Json::Value object;
   * static const StaticString code("code");
   * object[code] = 1234;
   * \endcode
   */
  Value& operator[](const StaticString& key);
#ifdef JSON_USE_CPPTL
  /// Access an object value by name, create a null member if it does not exist.
  Value& operator[](const CppTL::ConstString& key);
  /// Access an object value by name, returns null if there is no member with
  /// that name.
  const Value& operator[](const CppTL::ConstString& key) const;
#endif
  /// Return the member named key if it exist, defaultValue otherwise.
  /// \note deep copy
  Value get(const char* key, const Value& defaultValue) const;
  /// Return the member named key if it exist, defaultValue otherwise.
  /// \note deep copy
  /// \note key may contain embedded nulls.
  Value get(const char* begin, const char* end, const Value& defaultValue) const;
  /// Return the member named key if it exist, defaultValue otherwise.
  /// \note deep copy
  /// \param key may contain embedded nulls.
  Value get(const JSONCPP_STRING& key, const Value& defaultValue) const;
#ifdef JSON_USE_CPPTL
  /// Return the member named key if it exist, defaultValue otherwise.
  /// \note deep copy
  Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
#endif
  /// Most general and efficient version of isMember()const, get()const,
  /// and operator[]const
  /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
  Value const* find(char const* begin, char const* end) const;
  /// Most general and efficient version of object-mutators.
  /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
  /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
  Value const* demand(char const* begin, char const* end);
  /// \brief Remove and return the named member.
  ///
  /// Do nothing if it did not exist.
  /// \return the removed Value, or null.
  /// \pre type() is objectValue or nullValue
  /// \post type() is unchanged
  /// \deprecated
  Value removeMember(const char* key);
  /// Same as removeMember(const char*)
  /// \param key may contain embedded nulls.
  /// \deprecated
  Value removeMember(const JSONCPP_STRING& key);
  /// Same as removeMember(const char* begin, const char* end, Value* removed),
  /// but 'key' is null-terminated.
  bool removeMember(const char* key, Value* removed);
  /** \brief Remove the named map member.

      Update 'removed' iff removed.
      \param key may contain embedded nulls.
      \return true iff removed (no exceptions)
  */
  bool removeMember(JSONCPP_STRING const& key, Value* removed);
  /// Same as removeMember(JSONCPP_STRING const& key, Value* removed)
  bool removeMember(const char* begin, const char* end, Value* removed);
  /** \brief Remove the indexed array element.

      O(n) expensive operations.
      Update 'removed' iff removed.
      \return true iff removed (no exceptions)
  */
  bool removeIndex(ArrayIndex i, Value* removed);

  /// Return true if the object has a member named key.
  /// \note 'key' must be null-terminated.
  bool isMember(const char* key) const;
  /// Return true if the object has a member named key.
  /// \param key may contain embedded nulls.
  bool isMember(const JSONCPP_STRING& key) const;
  /// Same as isMember(JSONCPP_STRING const& key)const
  bool isMember(const char* begin, const char* end) const;
#ifdef JSON_USE_CPPTL
  /// Return true if the object has a member named key.
  bool isMember(const CppTL::ConstString& key) const;
#endif

  /// \brief Return a list of the member names.
  ///
  /// If null, return an empty list.
  /// \pre type() is objectValue or nullValue
  /// \post if type() was nullValue, it remains nullValue
  Members getMemberNames() const;

  //# ifdef JSON_USE_CPPTL
  //      EnumMemberNames enumMemberNames() const;
  //      EnumValues enumValues() const;
  //# endif

  /// \deprecated Always pass len.
  JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.")
  void setComment(const char* comment, CommentPlacement placement);
  /// Comments must be //... or /* ... */
  void setComment(const char* comment, size_t len, CommentPlacement placement);
  /// Comments must be //... or /* ... */
  void setComment(const JSONCPP_STRING& comment, CommentPlacement placement);
  bool hasComment(CommentPlacement placement) const;
  /// Include delimiters and embedded newlines.
  JSONCPP_STRING getComment(CommentPlacement placement) const;

  JSONCPP_STRING toStyledString() const;

  const_iterator begin() const;
  const_iterator end() const;

  iterator begin();
  iterator end();

  // Accessors for the [start, limit) range of bytes within the JSON text from
  // which this value was parsed, if any.
  void setOffsetStart(ptrdiff_t start);
  void setOffsetLimit(ptrdiff_t limit);
  ptrdiff_t getOffsetStart() const;
  ptrdiff_t getOffsetLimit() const;

 private:
  void initBasic(ValueType type, bool allocated = false);

  Value& resolveReference(const char* key);
  Value& resolveReference(const char* key, const char* end);

  struct CommentInfo {
    CommentInfo();
    ~CommentInfo();

    void setComment(const char* text, size_t len);

    char* comment_;
  };

  // struct MemberNamesTransform
  //{
  //   typedef const char *result_type;
  //   const char *operator()( const CZString &name ) const
  //   {
  //      return name.c_str();
  //   }
  //};

  union ValueHolder {
    LargestInt int_;
    LargestUInt uint_;
    double real_;
    bool bool_;
    char* string_;  // actually ptr to unsigned, followed by str, unless !allocated_
    ObjectValues* map_;
  } value_;
  ValueType type_ : 8;
  unsigned int allocated_ : 1;  // Notes: if declared as bool, bitfield is useless.
                                // If not allocated_, string_ must be null-terminated.
  CommentInfo* comments_;

  // [start, limit) byte offsets in the source JSON text from which this Value
  // was extracted.
  ptrdiff_t start_;
  ptrdiff_t limit_;
};

/** \brief Experimental and untested: represents an element of the "path" to
 * access a node.
 */
class JSON_API PathArgument {
 public:
  friend class Path;

  PathArgument();
  PathArgument(ArrayIndex index);
  PathArgument(const char* key);
  PathArgument(const JSONCPP_STRING& key);

 private:
  enum Kind { kindNone = 0, kindIndex, kindKey };
  JSONCPP_STRING key_;
  ArrayIndex index_;
  Kind kind_;
};

/** \brief Experimental and untested: represents a "path" to access a node.
 *
 * Syntax:
 * - "." => root node
 * - ".[n]" => elements at index 'n' of root node (an array value)
 * - ".name" => member named 'name' of root node (an object value)
 * - ".name1.name2.name3"
 * - ".[0][1][2].name1[3]"
 * - ".%" => member name is provided as parameter
 * - ".[%]" => index is provied as parameter
 */
class JSON_API Path {
 public:
  Path(const JSONCPP_STRING& path, const PathArgument& a1 = PathArgument(), const PathArgument& a2 = PathArgument(),
       const PathArgument& a3 = PathArgument(), const PathArgument& a4 = PathArgument(), const PathArgument& a5 = PathArgument());

  const Value& resolve(const Value& root) const;
  Value resolve(const Value& root, const Value& defaultValue) const;
  /// Creates the "path" to access the specified node and returns a reference on
  /// the node.
  Value& make(Value& root) const;

 private:
  typedef std::vector<const PathArgument*> InArgs;
  typedef std::vector<PathArgument> Args;

  void makePath(const JSONCPP_STRING& path, const InArgs& in);
  void addPathInArg(const JSONCPP_STRING& path, const InArgs& in, InArgs::const_iterator& itInArg, PathArgument::Kind kind);
  void invalidPath(const JSONCPP_STRING& path, int location);

  Args args_;
};

/** \brief base class for Value iterators.
 *
 */
class JSON_API ValueIteratorBase {
 public:
  typedef std::bidirectional_iterator_tag iterator_category;
  typedef unsigned int size_t;
  typedef int difference_type;
  typedef ValueIteratorBase SelfType;

  bool operator==(const SelfType& other) const { return isEqual(other); }

  bool operator!=(const SelfType& other) const { return !isEqual(other); }

  difference_type operator-(const SelfType& other) const { return other.computeDistance(*this); }

  /// Return either the index or the member name of the referenced value as a
  /// Value.
  Value key() const;

  /// Return the index of the referenced Value, or -1 if it is not an arrayValue.
  UInt index() const;

  /// Return the member name of the referenced Value, or "" if it is not an
  /// objectValue.
  /// \note Avoid `c_str()` on result, as embedded zeroes are possible.
  JSONCPP_STRING name() const;

  /// Return the member name of the referenced Value. "" if it is not an
  /// objectValue.
  /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
  JSONCPP_DEPRECATED("Use `key = name();` instead.")
  char const* memberName() const;
  /// Return the member name of the referenced Value, or NULL if it is not an
  /// objectValue.
  /// \note Better version than memberName(). Allows embedded nulls.
  char const* memberName(char const** end) const;

 protected:
  Value& deref() const;

  void increment();

  void decrement();

  difference_type computeDistance(const SelfType& other) const;

  bool isEqual(const SelfType& other) const;

  void copy(const SelfType& other);

 private:
  Value::ObjectValues::iterator current_;
  // Indicates that iterator is for a null value.
  bool isNull_;

 public:
  // For some reason, BORLAND needs these at the end, rather
  // than earlier. No idea why.
  ValueIteratorBase();
  explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
};

/** \brief const iterator for object and array value.
 *
 */
class JSON_API ValueConstIterator : public ValueIteratorBase {
  friend class Value;

 public:
  typedef const Value value_type;
  // typedef unsigned int size_t;
  // typedef int difference_type;
  typedef const Value& reference;
  typedef const Value* pointer;
  typedef ValueConstIterator SelfType;

  ValueConstIterator();
  ValueConstIterator(ValueIterator const& other);

 private:
  /*! \internal Use by Value to create an iterator.
   */
  explicit ValueConstIterator(const Value::ObjectValues::iterator& current);

 public:
  SelfType& operator=(const ValueIteratorBase& other);

  SelfType operator++(int) {
    SelfType temp(*this);
    ++*this;
    return temp;
  }

  SelfType operator--(int) {
    SelfType temp(*this);
    --*this;
    return temp;
  }

  SelfType& operator--() {
    decrement();
    return *this;
  }

  SelfType& operator++() {
    increment();
    return *this;
  }

  reference operator*() const { return deref(); }

  pointer operator->() const { return &deref(); }
};

/** \brief Iterator for object and array value.
 */
class JSON_API ValueIterator : public ValueIteratorBase {
  friend class Value;

 public:
  typedef Value value_type;
  typedef unsigned int size_t;
  typedef int difference_type;
  typedef Value& reference;
  typedef Value* pointer;
  typedef ValueIterator SelfType;

  ValueIterator();
  explicit ValueIterator(const ValueConstIterator& other);
  ValueIterator(const ValueIterator& other);

 private:
  /*! \internal Use by Value to create an iterator.
   */
  explicit ValueIterator(const Value::ObjectValues::iterator& current);

 public:
  SelfType& operator=(const SelfType& other);

  SelfType operator++(int) {
    SelfType temp(*this);
    ++*this;
    return temp;
  }

  SelfType operator--(int) {
    SelfType temp(*this);
    --*this;
    return temp;
  }

  SelfType& operator--() {
    decrement();
    return *this;
  }

  SelfType& operator++() {
    increment();
    return *this;
  }

  reference operator*() const { return deref(); }

  pointer operator->() const { return &deref(); }
};

}  // namespace Json

namespace std {
/// Specialize std::swap() for Json::Value.
template <>
inline void swap(Json::Value& a, Json::Value& b) {
  a.swap(b);
}
}

#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif  // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)

#endif  // CPPTL_JSON_H_INCLUDED

// //////////////////////////////////////////////////////////////////////
// End of content of file: include/json/value.h
// //////////////////////////////////////////////////////////////////////

// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/reader.h
// //////////////////////////////////////////////////////////////////////

// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#ifndef CPPTL_JSON_READER_H_INCLUDED
#define CPPTL_JSON_READER_H_INCLUDED

#if !defined(JSON_IS_AMALGAMATION)
#include "features.h"
#include "value.h"
#endif  // if !defined(JSON_IS_AMALGAMATION)
#include <deque>
#include <iosfwd>
#include <istream>
#include <stack>
#include <string>

// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251)
#endif  // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)

namespace Json {

/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
 *Value.
 *
 * \deprecated Use CharReader and CharReaderBuilder.
 */
class JSON_API Reader {
 public:
  typedef char Char;
  typedef const Char* Location;

  /** \brief An error tagged with where in the JSON text it was encountered.
   *
   * The offsets give the [start, limit) range of bytes within the text. Note
   * that this is bytes, not codepoints.
   *
   */
  struct StructuredError {
    ptrdiff_t offset_start;
    ptrdiff_t offset_limit;
    JSONCPP_STRING message;
  };

  /** \brief Constructs a Reader allowing all features
   * for parsing.
   */
  Reader();

  /** \brief Constructs a Reader allowing the specified feature set
   * for parsing.
   */
  Reader(const Features& features);

  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
   * document.
   * \param document UTF-8 encoded string containing the document to read.
   * \param root [out] Contains the root value of the document if it was
   *             successfully parsed.
   * \param collectComments \c true to collect comment and allow writing them
   * back during
   *                        serialization, \c false to discard comments.
   *                        This parameter is ignored if
   * Features::allowComments_
   *                        is \c false.
   * \return \c true if the document was successfully parsed, \c false if an
   * error occurred.
   */
  bool parse(const std::string& document, Value& root, bool collectComments = true);

  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
   document.
   * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
   document to read.
   * \param endDoc Pointer on the end of the UTF-8 encoded string of the
   document to read.
   *               Must be >= beginDoc.
   * \param root [out] Contains the root value of the document if it was
   *             successfully parsed.
   * \param collectComments \c true to collect comment and allow writing them
   back during
   *                        serialization, \c false to discard comments.
 
Download .txt
gitextract_u2ocm4ci/

├── .clang-format
├── .gitignore
├── CMakeLists.txt
├── LICENSE.md
├── README.md
├── cmake/
│   └── Modules/
│       ├── FindGLIB.cmake
│       ├── FindLibNice.cmake
│       ├── FindSpdlog.cmake
│       └── FindUsrSCTP.cmake
├── examples/
│   ├── README.md
│   ├── site-api.py
│   ├── static/
│   │   ├── adapter.js
│   │   ├── demo.css
│   │   └── index.html
│   └── websocket_client/
│       ├── CMakeLists.txt
│       ├── WebSocketWrapper.cpp
│       ├── WebSocketWrapper.hpp
│       ├── easywsclient.cpp
│       ├── easywsclient.hpp
│       ├── json/
│       │   ├── json-forwards.h
│       │   └── json.h
│       ├── jsoncpp.cpp
│       └── testclient.cpp
├── include/
│   └── rtcdcpp/
│       ├── Chunk.hpp
│       ├── ChunkQueue.hpp
│       ├── DTLSWrapper.hpp
│       ├── DataChannel.hpp
│       ├── Logging.hpp
│       ├── NiceWrapper.hpp
│       ├── PeerConnection.hpp
│       ├── RTCCertificate.hpp
│       ├── SCTPWrapper.hpp
│       └── librtcdcpp.h
└── src/
    ├── DTLSWrapper.cpp
    ├── DataChannel.cpp
    ├── Logging.cpp
    ├── NiceWrapper.cpp
    ├── PeerConnection.cpp
    ├── RTCCertificate.cpp
    ├── SCTPWrapper.cpp
    └── librtcdcpp.c
Download .txt
SYMBOL INDEX (259 symbols across 25 files)

FILE: examples/site-api.py
  function channel_socket (line 16) | def channel_socket(ws, name):
  function send_static (line 43) | def send_static(path):
  function serve_site (line 48) | def serve_site():

FILE: examples/static/adapter.js
  function s (line 1) | function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&re...

FILE: examples/websocket_client/WebSocketWrapper.hpp
  class WebSocketWrapper (line 22) | class WebSocketWrapper {

FILE: examples/websocket_client/easywsclient.cpp
  function socket_t (line 82) | socket_t hostname_connect(const std::string& hostname, int port) {
  class _DummyWebSocket (line 112) | class _DummyWebSocket : public easywsclient::WebSocket {
    method poll (line 114) | void poll(int timeout) {}
    method send (line 115) | void send(const std::string& message) {}
    method sendBinary (line 116) | void sendBinary(const std::string& message) {}
    method sendBinary (line 117) | void sendBinary(const std::vector<uint8_t>& message) {}
    method sendPing (line 118) | void sendPing() {}
    method close (line 119) | void close() {}
    method readyStateValues (line 120) | readyStateValues getReadyState() const { return CLOSED; }
    method _dispatch (line 121) | void _dispatch(Callback_Imp& callable) {}
    method _dispatchBinary (line 122) | void _dispatchBinary(BytesCallback_Imp& callable) {}
  class _RealWebSocket (line 125) | class _RealWebSocket : public easywsclient::WebSocket {
    type wsheader_type (line 147) | struct wsheader_type {
      type opcode_type (line 151) | enum opcode_type {
    method _RealWebSocket (line 172) | _RealWebSocket(socket_t sockfd, bool useMask) : sockfd(sockfd), readyS...
    method readyStateValues (line 174) | readyStateValues getReadyState() const { return readyState; }
    method poll (line 176) | void poll(int timeout) {  // timeout in milliseconds
    method _dispatch (line 242) | virtual void _dispatch(Callback_Imp& callable) {
    method _dispatchBinary (line 257) | virtual void _dispatchBinary(BytesCallback_Imp& callable) {
    method sendPing (line 343) | void sendPing() {
    method send (line 348) | void send(const std::string& message) { sendData(wsheader_type::TEXT_F...
    method sendBinary (line 350) | void sendBinary(const std::string& message) { sendData(wsheader_type::...
    method sendBinary (line 352) | void sendBinary(const std::vector<uint8_t>& message) { sendData(wshead...
    method sendData (line 355) | void sendData(wsheader_type::opcode_type type, uint64_t message_size, ...
    method close (line 414) | void close() {
  function from_url (line 425) | easywsclient::WebSocket::pointer from_url(const std::string& url, bool u...
  type easywsclient (line 524) | namespace easywsclient {

FILE: examples/websocket_client/easywsclient.hpp
  type easywsclient (line 14) | namespace easywsclient {
    type Callback_Imp (line 16) | struct Callback_Imp {
    type BytesCallback_Imp (line 19) | struct BytesCallback_Imp {
    class WebSocket (line 23) | class WebSocket {
      type readyStateValues (line 26) | enum readyStateValues { CLOSING, CLOSED, CONNECTING, OPEN }
      method dispatch (line 44) | void dispatch(Callable callable)
      method dispatchBinary (line 57) | void dispatchBinary(Callable callable)

FILE: examples/websocket_client/json/json-forwards.h
  function namespace (line 223) | namespace Json {
  function namespace (line 280) | namespace Json {

FILE: examples/websocket_client/json/json.h
  function namespace (line 251) | namespace Json {
  function namespace (line 308) | namespace Json {
  function namespace (line 354) | namespace Json {
  function namespace (line 454) | namespace Json {
  function namespace (line 1248) | namespace std {
  function namespace (line 1295) | namespace Json {
  function namespace (line 1687) | namespace Json {

FILE: examples/websocket_client/jsoncpp.cpp
  type Json (line 95) | namespace Json {
    function JSONCPP_STRING (line 98) | static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
    function isControlCharacter (line 127) | static inline bool isControlCharacter(char ch) { return ch > 0 && ch <...
    function uintToString (line 143) | static inline void uintToString(LargestUInt value, char*& current) {
    function fixNumericLocale (line 156) | static inline void fixNumericLocale(char* begin, char* end) {
    function Features (line 239) | Features Features::all() { return Features(); }
    function Features (line 241) | Features Features::strictMode() {
    function containsNewLine (line 253) | static bool containsNewLine(Reader::Location begin, Reader::Location e...
    function JSONCPP_STRING (line 540) | static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Loc...
    function Value (line 891) | Value& Reader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 918) | JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) con...
    function JSONCPP_STRING (line 927) | JSONCPP_STRING Reader::getFormatedErrorMessages() const { return getFo...
    function JSONCPP_STRING (line 929) | JSONCPP_STRING Reader::getFormattedErrorMessages() const {
    class OurFeatures (line 986) | class OurFeatures {
    function OurFeatures (line 1003) | OurFeatures OurFeatures::all() { return OurFeatures(); }
    class OurReader (line 1009) | class OurReader {
      type StructuredError (line 1013) | struct StructuredError {
      type TokenType (line 1031) | enum TokenType {
      class Token (line 1051) | class Token {
      class ErrorInfo (line 1058) | class ErrorInfo {
    function Value (line 1786) | Value& OurReader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 1813) | JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) ...
    function JSONCPP_STRING (line 1821) | JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
    class OurCharReader (line 1877) | class OurCharReader : public CharReader {
      method OurCharReader (line 1882) | OurCharReader(bool collectComments, OurFeatures const& features) : c...
      method parse (line 1883) | bool parse(char const* beginDoc, char const* endDoc, Value* root, JS...
    function CharReader (line 1894) | CharReader* CharReaderBuilder::newCharReader() const {
    function getValidReaderKeys (line 1908) | static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 1937) | Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { return sett...
    function parseFromStream (line 1971) | bool parseFromStream(CharReader::Factory const& fact, JSONCPP_ISTREAM&...
    function JSONCPP_ISTREAM (line 1982) | JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
    function Value (line 2025) | Value& ValueIteratorBase::deref() const { return current_->second; }
    function Value (line 2069) | Value ValueIteratorBase::key() const {
    function UInt (line 2078) | UInt ValueIteratorBase::index() const {
    function JSONCPP_STRING (line 2084) | JSONCPP_STRING ValueIteratorBase::name() const {
    function ValueConstIterator (line 2121) | ValueConstIterator& ValueConstIterator::operator=(const ValueIteratorB...
    function ValueIterator (line 2144) | ValueIterator& ValueIterator::operator=(const SelfType& other) {
    function Value (line 2198) | Value const& Value::nullSingleton() {
    function InRange (line 2226) | static inline bool InRange(double d, T min, U max) {
    function integerToDouble (line 2233) | static inline double integerToDouble(Json::UInt64 value) {
    function integerToDouble (line 2238) | static inline double integerToDouble(T value) {
    function InRange (line 2243) | static inline bool InRange(double d, T min, U max) {
    function decodePrefixedString (line 2291) | inline static void decodePrefixedString(bool isPrefixed, char const* p...
    function releasePrefixedStringValue (line 2303) | static inline void releasePrefixedStringValue(char* value) {
    function releaseStringValue (line 2311) | static inline void releaseStringValue(char* value, unsigned length) {
    function releasePrefixedStringValue (line 2318) | static inline void releasePrefixedStringValue(char* value) { free(valu...
    function releaseStringValue (line 2319) | static inline void releaseStringValue(char* value, unsigned) { free(va...
    function JSONCPP_NORETURN (line 2343) | JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { t...
    function JSONCPP_NORETURN (line 2344) | JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { thr...
    function ArrayIndex (line 2446) | ArrayIndex Value::CZString::index() const { return index_; }
    function Value (line 2618) | Value& Value::operator=(Value other) {
    function ValueType (line 2640) | ValueType Value::type() const { return type_; }
    function JSONCPP_STRING (line 2773) | JSONCPP_STRING Value::asString() const {
    function LargestInt (line 2891) | LargestInt Value::asLargestInt() const {
    function LargestUInt (line 2899) | LargestUInt Value::asLargestUInt() const {
    function ArrayIndex (line 2996) | ArrayIndex Value::size() const {
    function Value (line 3058) | Value& Value::operator[](ArrayIndex index) {
    function Value (line 3070) | Value& Value::operator[](int index) {
    function Value (line 3075) | const Value& Value::operator[](ArrayIndex index) const {
    function Value (line 3084) | const Value& Value::operator[](int index) const {
    function Value (line 3100) | Value& Value::resolveReference(const char* key) {
    function Value (line 3114) | Value& Value::resolveReference(char const* key, char const* cend) {
    function Value (line 3127) | Value Value::get(ArrayIndex index, const Value& defaultValue) const {
    function Value (line 3134) | Value const* Value::find(char const* key, char const* cend) const {
    function Value (line 3142) | const Value& Value::operator[](const char* key) const {
    function Value (line 3147) | Value const& Value::operator[](JSONCPP_STRING const& key) const {
    function Value (line 3153) | Value& Value::operator[](const char* key) { return resolveReference(ke...
    function Value (line 3155) | Value& Value::operator[](const JSONCPP_STRING& key) { return resolveRe...
    function Value (line 3157) | Value& Value::operator[](const StaticString& key) { return resolveRefe...
    function Value (line 3160) | Value& Value::operator[](const CppTL::ConstString& key) { return resol...
    function Value (line 3161) | Value const& Value::operator[](CppTL::ConstString const& key) const {
    function Value (line 3168) | Value& Value::append(const Value& value) { return (*this)[size()] = va...
    function Value (line 3170) | Value Value::get(char const* key, char const* cend, Value const& defau...
    function Value (line 3174) | Value Value::get(char const* key, Value const& defaultValue) const { r...
    function Value (line 3175) | Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue)...
    function Value (line 3190) | Value Value::removeMember(const char* key) {
    function Value (line 3198) | Value Value::removeMember(const JSONCPP_STRING& key) { return removeMe...
    function Value (line 3224) | Value Value::get(const CppTL::ConstString& key, const Value& defaultVa...
    function IsIntegral (line 3276) | static bool IsIntegral(double d) {
    function JSONCPP_STRING (line 3384) | JSONCPP_STRING Value::getComment(CommentPlacement placement) const {
    function JSONCPP_STRING (line 3397) | JSONCPP_STRING Value::toStyledString() const {
    function Value (line 3517) | const Value& Path::resolve(const Value& root) const {
    function Value (line 3540) | Value Path::resolve(const Value& root, const Value& defaultValue) const {
    function Value (line 3556) | Value& Path::make(Value& root) const {
    function containsControlCharacter (line 3667) | static bool containsControlCharacter(const char* str) {
    function containsControlCharacter0 (line 3674) | static bool containsControlCharacter0(const char* str, unsigned len) {
    function JSONCPP_STRING (line 3683) | JSONCPP_STRING valueToString(LargestInt value) {
    function JSONCPP_STRING (line 3699) | JSONCPP_STRING valueToString(LargestUInt value) {
    function JSONCPP_STRING (line 3709) | JSONCPP_STRING valueToString(Int value) { return valueToString(Largest...
    function JSONCPP_STRING (line 3711) | JSONCPP_STRING valueToString(UInt value) { return valueToString(Larges...
    function JSONCPP_STRING (line 3716) | JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsi...
    function JSONCPP_STRING (line 3747) | JSONCPP_STRING valueToString(double value) { return valueToString(valu...
    function JSONCPP_STRING (line 3749) | JSONCPP_STRING valueToString(bool value) { return value ? "true" : "fa...
    function JSONCPP_STRING (line 3751) | JSONCPP_STRING valueToQuotedString(const char* value) {
    function JSONCPP_STRING (line 3823) | static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned...
    function JSONCPP_STRING (line 3896) | JSONCPP_STRING FastWriter::write(const Value& root) {
    function JSONCPP_STRING (line 3957) | JSONCPP_STRING StyledWriter::write(const Value& root) {
    type CommentStyle (line 4369) | struct CommentStyle {
      type Enum (line 4371) | enum Enum {
    type BuiltStyledStreamWriter (line 4378) | struct BuiltStyledStreamWriter : public StreamWriter {
    function StreamWriter (line 4643) | StreamWriter* StreamWriterBuilder::newStreamWriter() const {
    function getValidWriterKeys (line 4672) | static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 4697) | Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { return se...
    function JSONCPP_STRING (line 4710) | JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value...
    function JSONCPP_OSTREAM (line 4717) | JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
  type Json (line 226) | namespace Json {
    function JSONCPP_STRING (line 98) | static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
    function isControlCharacter (line 127) | static inline bool isControlCharacter(char ch) { return ch > 0 && ch <...
    function uintToString (line 143) | static inline void uintToString(LargestUInt value, char*& current) {
    function fixNumericLocale (line 156) | static inline void fixNumericLocale(char* begin, char* end) {
    function Features (line 239) | Features Features::all() { return Features(); }
    function Features (line 241) | Features Features::strictMode() {
    function containsNewLine (line 253) | static bool containsNewLine(Reader::Location begin, Reader::Location e...
    function JSONCPP_STRING (line 540) | static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Loc...
    function Value (line 891) | Value& Reader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 918) | JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) con...
    function JSONCPP_STRING (line 927) | JSONCPP_STRING Reader::getFormatedErrorMessages() const { return getFo...
    function JSONCPP_STRING (line 929) | JSONCPP_STRING Reader::getFormattedErrorMessages() const {
    class OurFeatures (line 986) | class OurFeatures {
    function OurFeatures (line 1003) | OurFeatures OurFeatures::all() { return OurFeatures(); }
    class OurReader (line 1009) | class OurReader {
      type StructuredError (line 1013) | struct StructuredError {
      type TokenType (line 1031) | enum TokenType {
      class Token (line 1051) | class Token {
      class ErrorInfo (line 1058) | class ErrorInfo {
    function Value (line 1786) | Value& OurReader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 1813) | JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) ...
    function JSONCPP_STRING (line 1821) | JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
    class OurCharReader (line 1877) | class OurCharReader : public CharReader {
      method OurCharReader (line 1882) | OurCharReader(bool collectComments, OurFeatures const& features) : c...
      method parse (line 1883) | bool parse(char const* beginDoc, char const* endDoc, Value* root, JS...
    function CharReader (line 1894) | CharReader* CharReaderBuilder::newCharReader() const {
    function getValidReaderKeys (line 1908) | static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 1937) | Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { return sett...
    function parseFromStream (line 1971) | bool parseFromStream(CharReader::Factory const& fact, JSONCPP_ISTREAM&...
    function JSONCPP_ISTREAM (line 1982) | JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
    function Value (line 2025) | Value& ValueIteratorBase::deref() const { return current_->second; }
    function Value (line 2069) | Value ValueIteratorBase::key() const {
    function UInt (line 2078) | UInt ValueIteratorBase::index() const {
    function JSONCPP_STRING (line 2084) | JSONCPP_STRING ValueIteratorBase::name() const {
    function ValueConstIterator (line 2121) | ValueConstIterator& ValueConstIterator::operator=(const ValueIteratorB...
    function ValueIterator (line 2144) | ValueIterator& ValueIterator::operator=(const SelfType& other) {
    function Value (line 2198) | Value const& Value::nullSingleton() {
    function InRange (line 2226) | static inline bool InRange(double d, T min, U max) {
    function integerToDouble (line 2233) | static inline double integerToDouble(Json::UInt64 value) {
    function integerToDouble (line 2238) | static inline double integerToDouble(T value) {
    function InRange (line 2243) | static inline bool InRange(double d, T min, U max) {
    function decodePrefixedString (line 2291) | inline static void decodePrefixedString(bool isPrefixed, char const* p...
    function releasePrefixedStringValue (line 2303) | static inline void releasePrefixedStringValue(char* value) {
    function releaseStringValue (line 2311) | static inline void releaseStringValue(char* value, unsigned length) {
    function releasePrefixedStringValue (line 2318) | static inline void releasePrefixedStringValue(char* value) { free(valu...
    function releaseStringValue (line 2319) | static inline void releaseStringValue(char* value, unsigned) { free(va...
    function JSONCPP_NORETURN (line 2343) | JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { t...
    function JSONCPP_NORETURN (line 2344) | JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { thr...
    function ArrayIndex (line 2446) | ArrayIndex Value::CZString::index() const { return index_; }
    function Value (line 2618) | Value& Value::operator=(Value other) {
    function ValueType (line 2640) | ValueType Value::type() const { return type_; }
    function JSONCPP_STRING (line 2773) | JSONCPP_STRING Value::asString() const {
    function LargestInt (line 2891) | LargestInt Value::asLargestInt() const {
    function LargestUInt (line 2899) | LargestUInt Value::asLargestUInt() const {
    function ArrayIndex (line 2996) | ArrayIndex Value::size() const {
    function Value (line 3058) | Value& Value::operator[](ArrayIndex index) {
    function Value (line 3070) | Value& Value::operator[](int index) {
    function Value (line 3075) | const Value& Value::operator[](ArrayIndex index) const {
    function Value (line 3084) | const Value& Value::operator[](int index) const {
    function Value (line 3100) | Value& Value::resolveReference(const char* key) {
    function Value (line 3114) | Value& Value::resolveReference(char const* key, char const* cend) {
    function Value (line 3127) | Value Value::get(ArrayIndex index, const Value& defaultValue) const {
    function Value (line 3134) | Value const* Value::find(char const* key, char const* cend) const {
    function Value (line 3142) | const Value& Value::operator[](const char* key) const {
    function Value (line 3147) | Value const& Value::operator[](JSONCPP_STRING const& key) const {
    function Value (line 3153) | Value& Value::operator[](const char* key) { return resolveReference(ke...
    function Value (line 3155) | Value& Value::operator[](const JSONCPP_STRING& key) { return resolveRe...
    function Value (line 3157) | Value& Value::operator[](const StaticString& key) { return resolveRefe...
    function Value (line 3160) | Value& Value::operator[](const CppTL::ConstString& key) { return resol...
    function Value (line 3161) | Value const& Value::operator[](CppTL::ConstString const& key) const {
    function Value (line 3168) | Value& Value::append(const Value& value) { return (*this)[size()] = va...
    function Value (line 3170) | Value Value::get(char const* key, char const* cend, Value const& defau...
    function Value (line 3174) | Value Value::get(char const* key, Value const& defaultValue) const { r...
    function Value (line 3175) | Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue)...
    function Value (line 3190) | Value Value::removeMember(const char* key) {
    function Value (line 3198) | Value Value::removeMember(const JSONCPP_STRING& key) { return removeMe...
    function Value (line 3224) | Value Value::get(const CppTL::ConstString& key, const Value& defaultVa...
    function IsIntegral (line 3276) | static bool IsIntegral(double d) {
    function JSONCPP_STRING (line 3384) | JSONCPP_STRING Value::getComment(CommentPlacement placement) const {
    function JSONCPP_STRING (line 3397) | JSONCPP_STRING Value::toStyledString() const {
    function Value (line 3517) | const Value& Path::resolve(const Value& root) const {
    function Value (line 3540) | Value Path::resolve(const Value& root, const Value& defaultValue) const {
    function Value (line 3556) | Value& Path::make(Value& root) const {
    function containsControlCharacter (line 3667) | static bool containsControlCharacter(const char* str) {
    function containsControlCharacter0 (line 3674) | static bool containsControlCharacter0(const char* str, unsigned len) {
    function JSONCPP_STRING (line 3683) | JSONCPP_STRING valueToString(LargestInt value) {
    function JSONCPP_STRING (line 3699) | JSONCPP_STRING valueToString(LargestUInt value) {
    function JSONCPP_STRING (line 3709) | JSONCPP_STRING valueToString(Int value) { return valueToString(Largest...
    function JSONCPP_STRING (line 3711) | JSONCPP_STRING valueToString(UInt value) { return valueToString(Larges...
    function JSONCPP_STRING (line 3716) | JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsi...
    function JSONCPP_STRING (line 3747) | JSONCPP_STRING valueToString(double value) { return valueToString(valu...
    function JSONCPP_STRING (line 3749) | JSONCPP_STRING valueToString(bool value) { return value ? "true" : "fa...
    function JSONCPP_STRING (line 3751) | JSONCPP_STRING valueToQuotedString(const char* value) {
    function JSONCPP_STRING (line 3823) | static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned...
    function JSONCPP_STRING (line 3896) | JSONCPP_STRING FastWriter::write(const Value& root) {
    function JSONCPP_STRING (line 3957) | JSONCPP_STRING StyledWriter::write(const Value& root) {
    type CommentStyle (line 4369) | struct CommentStyle {
      type Enum (line 4371) | enum Enum {
    type BuiltStyledStreamWriter (line 4378) | struct BuiltStyledStreamWriter : public StreamWriter {
    function StreamWriter (line 4643) | StreamWriter* StreamWriterBuilder::newStreamWriter() const {
    function getValidWriterKeys (line 4672) | static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 4697) | Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { return se...
    function JSONCPP_STRING (line 4710) | JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value...
    function JSONCPP_OSTREAM (line 4717) | JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
  type Json (line 2011) | namespace Json {
    function JSONCPP_STRING (line 98) | static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
    function isControlCharacter (line 127) | static inline bool isControlCharacter(char ch) { return ch > 0 && ch <...
    function uintToString (line 143) | static inline void uintToString(LargestUInt value, char*& current) {
    function fixNumericLocale (line 156) | static inline void fixNumericLocale(char* begin, char* end) {
    function Features (line 239) | Features Features::all() { return Features(); }
    function Features (line 241) | Features Features::strictMode() {
    function containsNewLine (line 253) | static bool containsNewLine(Reader::Location begin, Reader::Location e...
    function JSONCPP_STRING (line 540) | static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Loc...
    function Value (line 891) | Value& Reader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 918) | JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) con...
    function JSONCPP_STRING (line 927) | JSONCPP_STRING Reader::getFormatedErrorMessages() const { return getFo...
    function JSONCPP_STRING (line 929) | JSONCPP_STRING Reader::getFormattedErrorMessages() const {
    class OurFeatures (line 986) | class OurFeatures {
    function OurFeatures (line 1003) | OurFeatures OurFeatures::all() { return OurFeatures(); }
    class OurReader (line 1009) | class OurReader {
      type StructuredError (line 1013) | struct StructuredError {
      type TokenType (line 1031) | enum TokenType {
      class Token (line 1051) | class Token {
      class ErrorInfo (line 1058) | class ErrorInfo {
    function Value (line 1786) | Value& OurReader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 1813) | JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) ...
    function JSONCPP_STRING (line 1821) | JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
    class OurCharReader (line 1877) | class OurCharReader : public CharReader {
      method OurCharReader (line 1882) | OurCharReader(bool collectComments, OurFeatures const& features) : c...
      method parse (line 1883) | bool parse(char const* beginDoc, char const* endDoc, Value* root, JS...
    function CharReader (line 1894) | CharReader* CharReaderBuilder::newCharReader() const {
    function getValidReaderKeys (line 1908) | static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 1937) | Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { return sett...
    function parseFromStream (line 1971) | bool parseFromStream(CharReader::Factory const& fact, JSONCPP_ISTREAM&...
    function JSONCPP_ISTREAM (line 1982) | JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
    function Value (line 2025) | Value& ValueIteratorBase::deref() const { return current_->second; }
    function Value (line 2069) | Value ValueIteratorBase::key() const {
    function UInt (line 2078) | UInt ValueIteratorBase::index() const {
    function JSONCPP_STRING (line 2084) | JSONCPP_STRING ValueIteratorBase::name() const {
    function ValueConstIterator (line 2121) | ValueConstIterator& ValueConstIterator::operator=(const ValueIteratorB...
    function ValueIterator (line 2144) | ValueIterator& ValueIterator::operator=(const SelfType& other) {
    function Value (line 2198) | Value const& Value::nullSingleton() {
    function InRange (line 2226) | static inline bool InRange(double d, T min, U max) {
    function integerToDouble (line 2233) | static inline double integerToDouble(Json::UInt64 value) {
    function integerToDouble (line 2238) | static inline double integerToDouble(T value) {
    function InRange (line 2243) | static inline bool InRange(double d, T min, U max) {
    function decodePrefixedString (line 2291) | inline static void decodePrefixedString(bool isPrefixed, char const* p...
    function releasePrefixedStringValue (line 2303) | static inline void releasePrefixedStringValue(char* value) {
    function releaseStringValue (line 2311) | static inline void releaseStringValue(char* value, unsigned length) {
    function releasePrefixedStringValue (line 2318) | static inline void releasePrefixedStringValue(char* value) { free(valu...
    function releaseStringValue (line 2319) | static inline void releaseStringValue(char* value, unsigned) { free(va...
    function JSONCPP_NORETURN (line 2343) | JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { t...
    function JSONCPP_NORETURN (line 2344) | JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { thr...
    function ArrayIndex (line 2446) | ArrayIndex Value::CZString::index() const { return index_; }
    function Value (line 2618) | Value& Value::operator=(Value other) {
    function ValueType (line 2640) | ValueType Value::type() const { return type_; }
    function JSONCPP_STRING (line 2773) | JSONCPP_STRING Value::asString() const {
    function LargestInt (line 2891) | LargestInt Value::asLargestInt() const {
    function LargestUInt (line 2899) | LargestUInt Value::asLargestUInt() const {
    function ArrayIndex (line 2996) | ArrayIndex Value::size() const {
    function Value (line 3058) | Value& Value::operator[](ArrayIndex index) {
    function Value (line 3070) | Value& Value::operator[](int index) {
    function Value (line 3075) | const Value& Value::operator[](ArrayIndex index) const {
    function Value (line 3084) | const Value& Value::operator[](int index) const {
    function Value (line 3100) | Value& Value::resolveReference(const char* key) {
    function Value (line 3114) | Value& Value::resolveReference(char const* key, char const* cend) {
    function Value (line 3127) | Value Value::get(ArrayIndex index, const Value& defaultValue) const {
    function Value (line 3134) | Value const* Value::find(char const* key, char const* cend) const {
    function Value (line 3142) | const Value& Value::operator[](const char* key) const {
    function Value (line 3147) | Value const& Value::operator[](JSONCPP_STRING const& key) const {
    function Value (line 3153) | Value& Value::operator[](const char* key) { return resolveReference(ke...
    function Value (line 3155) | Value& Value::operator[](const JSONCPP_STRING& key) { return resolveRe...
    function Value (line 3157) | Value& Value::operator[](const StaticString& key) { return resolveRefe...
    function Value (line 3160) | Value& Value::operator[](const CppTL::ConstString& key) { return resol...
    function Value (line 3161) | Value const& Value::operator[](CppTL::ConstString const& key) const {
    function Value (line 3168) | Value& Value::append(const Value& value) { return (*this)[size()] = va...
    function Value (line 3170) | Value Value::get(char const* key, char const* cend, Value const& defau...
    function Value (line 3174) | Value Value::get(char const* key, Value const& defaultValue) const { r...
    function Value (line 3175) | Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue)...
    function Value (line 3190) | Value Value::removeMember(const char* key) {
    function Value (line 3198) | Value Value::removeMember(const JSONCPP_STRING& key) { return removeMe...
    function Value (line 3224) | Value Value::get(const CppTL::ConstString& key, const Value& defaultVa...
    function IsIntegral (line 3276) | static bool IsIntegral(double d) {
    function JSONCPP_STRING (line 3384) | JSONCPP_STRING Value::getComment(CommentPlacement placement) const {
    function JSONCPP_STRING (line 3397) | JSONCPP_STRING Value::toStyledString() const {
    function Value (line 3517) | const Value& Path::resolve(const Value& root) const {
    function Value (line 3540) | Value Path::resolve(const Value& root, const Value& defaultValue) const {
    function Value (line 3556) | Value& Path::make(Value& root) const {
    function containsControlCharacter (line 3667) | static bool containsControlCharacter(const char* str) {
    function containsControlCharacter0 (line 3674) | static bool containsControlCharacter0(const char* str, unsigned len) {
    function JSONCPP_STRING (line 3683) | JSONCPP_STRING valueToString(LargestInt value) {
    function JSONCPP_STRING (line 3699) | JSONCPP_STRING valueToString(LargestUInt value) {
    function JSONCPP_STRING (line 3709) | JSONCPP_STRING valueToString(Int value) { return valueToString(Largest...
    function JSONCPP_STRING (line 3711) | JSONCPP_STRING valueToString(UInt value) { return valueToString(Larges...
    function JSONCPP_STRING (line 3716) | JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsi...
    function JSONCPP_STRING (line 3747) | JSONCPP_STRING valueToString(double value) { return valueToString(valu...
    function JSONCPP_STRING (line 3749) | JSONCPP_STRING valueToString(bool value) { return value ? "true" : "fa...
    function JSONCPP_STRING (line 3751) | JSONCPP_STRING valueToQuotedString(const char* value) {
    function JSONCPP_STRING (line 3823) | static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned...
    function JSONCPP_STRING (line 3896) | JSONCPP_STRING FastWriter::write(const Value& root) {
    function JSONCPP_STRING (line 3957) | JSONCPP_STRING StyledWriter::write(const Value& root) {
    type CommentStyle (line 4369) | struct CommentStyle {
      type Enum (line 4371) | enum Enum {
    type BuiltStyledStreamWriter (line 4378) | struct BuiltStyledStreamWriter : public StreamWriter {
    function StreamWriter (line 4643) | StreamWriter* StreamWriterBuilder::newStreamWriter() const {
    function getValidWriterKeys (line 4672) | static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 4697) | Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { return se...
    function JSONCPP_STRING (line 4710) | JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value...
    function JSONCPP_OSTREAM (line 4717) | JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
  type Json (line 2182) | namespace Json {
    function JSONCPP_STRING (line 98) | static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
    function isControlCharacter (line 127) | static inline bool isControlCharacter(char ch) { return ch > 0 && ch <...
    function uintToString (line 143) | static inline void uintToString(LargestUInt value, char*& current) {
    function fixNumericLocale (line 156) | static inline void fixNumericLocale(char* begin, char* end) {
    function Features (line 239) | Features Features::all() { return Features(); }
    function Features (line 241) | Features Features::strictMode() {
    function containsNewLine (line 253) | static bool containsNewLine(Reader::Location begin, Reader::Location e...
    function JSONCPP_STRING (line 540) | static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Loc...
    function Value (line 891) | Value& Reader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 918) | JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) con...
    function JSONCPP_STRING (line 927) | JSONCPP_STRING Reader::getFormatedErrorMessages() const { return getFo...
    function JSONCPP_STRING (line 929) | JSONCPP_STRING Reader::getFormattedErrorMessages() const {
    class OurFeatures (line 986) | class OurFeatures {
    function OurFeatures (line 1003) | OurFeatures OurFeatures::all() { return OurFeatures(); }
    class OurReader (line 1009) | class OurReader {
      type StructuredError (line 1013) | struct StructuredError {
      type TokenType (line 1031) | enum TokenType {
      class Token (line 1051) | class Token {
      class ErrorInfo (line 1058) | class ErrorInfo {
    function Value (line 1786) | Value& OurReader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 1813) | JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) ...
    function JSONCPP_STRING (line 1821) | JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
    class OurCharReader (line 1877) | class OurCharReader : public CharReader {
      method OurCharReader (line 1882) | OurCharReader(bool collectComments, OurFeatures const& features) : c...
      method parse (line 1883) | bool parse(char const* beginDoc, char const* endDoc, Value* root, JS...
    function CharReader (line 1894) | CharReader* CharReaderBuilder::newCharReader() const {
    function getValidReaderKeys (line 1908) | static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 1937) | Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { return sett...
    function parseFromStream (line 1971) | bool parseFromStream(CharReader::Factory const& fact, JSONCPP_ISTREAM&...
    function JSONCPP_ISTREAM (line 1982) | JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
    function Value (line 2025) | Value& ValueIteratorBase::deref() const { return current_->second; }
    function Value (line 2069) | Value ValueIteratorBase::key() const {
    function UInt (line 2078) | UInt ValueIteratorBase::index() const {
    function JSONCPP_STRING (line 2084) | JSONCPP_STRING ValueIteratorBase::name() const {
    function ValueConstIterator (line 2121) | ValueConstIterator& ValueConstIterator::operator=(const ValueIteratorB...
    function ValueIterator (line 2144) | ValueIterator& ValueIterator::operator=(const SelfType& other) {
    function Value (line 2198) | Value const& Value::nullSingleton() {
    function InRange (line 2226) | static inline bool InRange(double d, T min, U max) {
    function integerToDouble (line 2233) | static inline double integerToDouble(Json::UInt64 value) {
    function integerToDouble (line 2238) | static inline double integerToDouble(T value) {
    function InRange (line 2243) | static inline bool InRange(double d, T min, U max) {
    function decodePrefixedString (line 2291) | inline static void decodePrefixedString(bool isPrefixed, char const* p...
    function releasePrefixedStringValue (line 2303) | static inline void releasePrefixedStringValue(char* value) {
    function releaseStringValue (line 2311) | static inline void releaseStringValue(char* value, unsigned length) {
    function releasePrefixedStringValue (line 2318) | static inline void releasePrefixedStringValue(char* value) { free(valu...
    function releaseStringValue (line 2319) | static inline void releaseStringValue(char* value, unsigned) { free(va...
    function JSONCPP_NORETURN (line 2343) | JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { t...
    function JSONCPP_NORETURN (line 2344) | JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { thr...
    function ArrayIndex (line 2446) | ArrayIndex Value::CZString::index() const { return index_; }
    function Value (line 2618) | Value& Value::operator=(Value other) {
    function ValueType (line 2640) | ValueType Value::type() const { return type_; }
    function JSONCPP_STRING (line 2773) | JSONCPP_STRING Value::asString() const {
    function LargestInt (line 2891) | LargestInt Value::asLargestInt() const {
    function LargestUInt (line 2899) | LargestUInt Value::asLargestUInt() const {
    function ArrayIndex (line 2996) | ArrayIndex Value::size() const {
    function Value (line 3058) | Value& Value::operator[](ArrayIndex index) {
    function Value (line 3070) | Value& Value::operator[](int index) {
    function Value (line 3075) | const Value& Value::operator[](ArrayIndex index) const {
    function Value (line 3084) | const Value& Value::operator[](int index) const {
    function Value (line 3100) | Value& Value::resolveReference(const char* key) {
    function Value (line 3114) | Value& Value::resolveReference(char const* key, char const* cend) {
    function Value (line 3127) | Value Value::get(ArrayIndex index, const Value& defaultValue) const {
    function Value (line 3134) | Value const* Value::find(char const* key, char const* cend) const {
    function Value (line 3142) | const Value& Value::operator[](const char* key) const {
    function Value (line 3147) | Value const& Value::operator[](JSONCPP_STRING const& key) const {
    function Value (line 3153) | Value& Value::operator[](const char* key) { return resolveReference(ke...
    function Value (line 3155) | Value& Value::operator[](const JSONCPP_STRING& key) { return resolveRe...
    function Value (line 3157) | Value& Value::operator[](const StaticString& key) { return resolveRefe...
    function Value (line 3160) | Value& Value::operator[](const CppTL::ConstString& key) { return resol...
    function Value (line 3161) | Value const& Value::operator[](CppTL::ConstString const& key) const {
    function Value (line 3168) | Value& Value::append(const Value& value) { return (*this)[size()] = va...
    function Value (line 3170) | Value Value::get(char const* key, char const* cend, Value const& defau...
    function Value (line 3174) | Value Value::get(char const* key, Value const& defaultValue) const { r...
    function Value (line 3175) | Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue)...
    function Value (line 3190) | Value Value::removeMember(const char* key) {
    function Value (line 3198) | Value Value::removeMember(const JSONCPP_STRING& key) { return removeMe...
    function Value (line 3224) | Value Value::get(const CppTL::ConstString& key, const Value& defaultVa...
    function IsIntegral (line 3276) | static bool IsIntegral(double d) {
    function JSONCPP_STRING (line 3384) | JSONCPP_STRING Value::getComment(CommentPlacement placement) const {
    function JSONCPP_STRING (line 3397) | JSONCPP_STRING Value::toStyledString() const {
    function Value (line 3517) | const Value& Path::resolve(const Value& root) const {
    function Value (line 3540) | Value Path::resolve(const Value& root, const Value& defaultValue) const {
    function Value (line 3556) | Value& Path::make(Value& root) const {
    function containsControlCharacter (line 3667) | static bool containsControlCharacter(const char* str) {
    function containsControlCharacter0 (line 3674) | static bool containsControlCharacter0(const char* str, unsigned len) {
    function JSONCPP_STRING (line 3683) | JSONCPP_STRING valueToString(LargestInt value) {
    function JSONCPP_STRING (line 3699) | JSONCPP_STRING valueToString(LargestUInt value) {
    function JSONCPP_STRING (line 3709) | JSONCPP_STRING valueToString(Int value) { return valueToString(Largest...
    function JSONCPP_STRING (line 3711) | JSONCPP_STRING valueToString(UInt value) { return valueToString(Larges...
    function JSONCPP_STRING (line 3716) | JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsi...
    function JSONCPP_STRING (line 3747) | JSONCPP_STRING valueToString(double value) { return valueToString(valu...
    function JSONCPP_STRING (line 3749) | JSONCPP_STRING valueToString(bool value) { return value ? "true" : "fa...
    function JSONCPP_STRING (line 3751) | JSONCPP_STRING valueToQuotedString(const char* value) {
    function JSONCPP_STRING (line 3823) | static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned...
    function JSONCPP_STRING (line 3896) | JSONCPP_STRING FastWriter::write(const Value& root) {
    function JSONCPP_STRING (line 3957) | JSONCPP_STRING StyledWriter::write(const Value& root) {
    type CommentStyle (line 4369) | struct CommentStyle {
      type Enum (line 4371) | enum Enum {
    type BuiltStyledStreamWriter (line 4378) | struct BuiltStyledStreamWriter : public StreamWriter {
    function StreamWriter (line 4643) | StreamWriter* StreamWriterBuilder::newStreamWriter() const {
    function getValidWriterKeys (line 4672) | static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 4697) | Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { return se...
    function JSONCPP_STRING (line 4710) | JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value...
    function JSONCPP_OSTREAM (line 4717) | JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
  type Json (line 2336) | namespace Json {
    function JSONCPP_STRING (line 98) | static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
    function isControlCharacter (line 127) | static inline bool isControlCharacter(char ch) { return ch > 0 && ch <...
    function uintToString (line 143) | static inline void uintToString(LargestUInt value, char*& current) {
    function fixNumericLocale (line 156) | static inline void fixNumericLocale(char* begin, char* end) {
    function Features (line 239) | Features Features::all() { return Features(); }
    function Features (line 241) | Features Features::strictMode() {
    function containsNewLine (line 253) | static bool containsNewLine(Reader::Location begin, Reader::Location e...
    function JSONCPP_STRING (line 540) | static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Loc...
    function Value (line 891) | Value& Reader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 918) | JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) con...
    function JSONCPP_STRING (line 927) | JSONCPP_STRING Reader::getFormatedErrorMessages() const { return getFo...
    function JSONCPP_STRING (line 929) | JSONCPP_STRING Reader::getFormattedErrorMessages() const {
    class OurFeatures (line 986) | class OurFeatures {
    function OurFeatures (line 1003) | OurFeatures OurFeatures::all() { return OurFeatures(); }
    class OurReader (line 1009) | class OurReader {
      type StructuredError (line 1013) | struct StructuredError {
      type TokenType (line 1031) | enum TokenType {
      class Token (line 1051) | class Token {
      class ErrorInfo (line 1058) | class ErrorInfo {
    function Value (line 1786) | Value& OurReader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 1813) | JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) ...
    function JSONCPP_STRING (line 1821) | JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
    class OurCharReader (line 1877) | class OurCharReader : public CharReader {
      method OurCharReader (line 1882) | OurCharReader(bool collectComments, OurFeatures const& features) : c...
      method parse (line 1883) | bool parse(char const* beginDoc, char const* endDoc, Value* root, JS...
    function CharReader (line 1894) | CharReader* CharReaderBuilder::newCharReader() const {
    function getValidReaderKeys (line 1908) | static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 1937) | Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { return sett...
    function parseFromStream (line 1971) | bool parseFromStream(CharReader::Factory const& fact, JSONCPP_ISTREAM&...
    function JSONCPP_ISTREAM (line 1982) | JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
    function Value (line 2025) | Value& ValueIteratorBase::deref() const { return current_->second; }
    function Value (line 2069) | Value ValueIteratorBase::key() const {
    function UInt (line 2078) | UInt ValueIteratorBase::index() const {
    function JSONCPP_STRING (line 2084) | JSONCPP_STRING ValueIteratorBase::name() const {
    function ValueConstIterator (line 2121) | ValueConstIterator& ValueConstIterator::operator=(const ValueIteratorB...
    function ValueIterator (line 2144) | ValueIterator& ValueIterator::operator=(const SelfType& other) {
    function Value (line 2198) | Value const& Value::nullSingleton() {
    function InRange (line 2226) | static inline bool InRange(double d, T min, U max) {
    function integerToDouble (line 2233) | static inline double integerToDouble(Json::UInt64 value) {
    function integerToDouble (line 2238) | static inline double integerToDouble(T value) {
    function InRange (line 2243) | static inline bool InRange(double d, T min, U max) {
    function decodePrefixedString (line 2291) | inline static void decodePrefixedString(bool isPrefixed, char const* p...
    function releasePrefixedStringValue (line 2303) | static inline void releasePrefixedStringValue(char* value) {
    function releaseStringValue (line 2311) | static inline void releaseStringValue(char* value, unsigned length) {
    function releasePrefixedStringValue (line 2318) | static inline void releasePrefixedStringValue(char* value) { free(valu...
    function releaseStringValue (line 2319) | static inline void releaseStringValue(char* value, unsigned) { free(va...
    function JSONCPP_NORETURN (line 2343) | JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { t...
    function JSONCPP_NORETURN (line 2344) | JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { thr...
    function ArrayIndex (line 2446) | ArrayIndex Value::CZString::index() const { return index_; }
    function Value (line 2618) | Value& Value::operator=(Value other) {
    function ValueType (line 2640) | ValueType Value::type() const { return type_; }
    function JSONCPP_STRING (line 2773) | JSONCPP_STRING Value::asString() const {
    function LargestInt (line 2891) | LargestInt Value::asLargestInt() const {
    function LargestUInt (line 2899) | LargestUInt Value::asLargestUInt() const {
    function ArrayIndex (line 2996) | ArrayIndex Value::size() const {
    function Value (line 3058) | Value& Value::operator[](ArrayIndex index) {
    function Value (line 3070) | Value& Value::operator[](int index) {
    function Value (line 3075) | const Value& Value::operator[](ArrayIndex index) const {
    function Value (line 3084) | const Value& Value::operator[](int index) const {
    function Value (line 3100) | Value& Value::resolveReference(const char* key) {
    function Value (line 3114) | Value& Value::resolveReference(char const* key, char const* cend) {
    function Value (line 3127) | Value Value::get(ArrayIndex index, const Value& defaultValue) const {
    function Value (line 3134) | Value const* Value::find(char const* key, char const* cend) const {
    function Value (line 3142) | const Value& Value::operator[](const char* key) const {
    function Value (line 3147) | Value const& Value::operator[](JSONCPP_STRING const& key) const {
    function Value (line 3153) | Value& Value::operator[](const char* key) { return resolveReference(ke...
    function Value (line 3155) | Value& Value::operator[](const JSONCPP_STRING& key) { return resolveRe...
    function Value (line 3157) | Value& Value::operator[](const StaticString& key) { return resolveRefe...
    function Value (line 3160) | Value& Value::operator[](const CppTL::ConstString& key) { return resol...
    function Value (line 3161) | Value const& Value::operator[](CppTL::ConstString const& key) const {
    function Value (line 3168) | Value& Value::append(const Value& value) { return (*this)[size()] = va...
    function Value (line 3170) | Value Value::get(char const* key, char const* cend, Value const& defau...
    function Value (line 3174) | Value Value::get(char const* key, Value const& defaultValue) const { r...
    function Value (line 3175) | Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue)...
    function Value (line 3190) | Value Value::removeMember(const char* key) {
    function Value (line 3198) | Value Value::removeMember(const JSONCPP_STRING& key) { return removeMe...
    function Value (line 3224) | Value Value::get(const CppTL::ConstString& key, const Value& defaultVa...
    function IsIntegral (line 3276) | static bool IsIntegral(double d) {
    function JSONCPP_STRING (line 3384) | JSONCPP_STRING Value::getComment(CommentPlacement placement) const {
    function JSONCPP_STRING (line 3397) | JSONCPP_STRING Value::toStyledString() const {
    function Value (line 3517) | const Value& Path::resolve(const Value& root) const {
    function Value (line 3540) | Value Path::resolve(const Value& root, const Value& defaultValue) const {
    function Value (line 3556) | Value& Path::make(Value& root) const {
    function containsControlCharacter (line 3667) | static bool containsControlCharacter(const char* str) {
    function containsControlCharacter0 (line 3674) | static bool containsControlCharacter0(const char* str, unsigned len) {
    function JSONCPP_STRING (line 3683) | JSONCPP_STRING valueToString(LargestInt value) {
    function JSONCPP_STRING (line 3699) | JSONCPP_STRING valueToString(LargestUInt value) {
    function JSONCPP_STRING (line 3709) | JSONCPP_STRING valueToString(Int value) { return valueToString(Largest...
    function JSONCPP_STRING (line 3711) | JSONCPP_STRING valueToString(UInt value) { return valueToString(Larges...
    function JSONCPP_STRING (line 3716) | JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsi...
    function JSONCPP_STRING (line 3747) | JSONCPP_STRING valueToString(double value) { return valueToString(valu...
    function JSONCPP_STRING (line 3749) | JSONCPP_STRING valueToString(bool value) { return value ? "true" : "fa...
    function JSONCPP_STRING (line 3751) | JSONCPP_STRING valueToQuotedString(const char* value) {
    function JSONCPP_STRING (line 3823) | static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned...
    function JSONCPP_STRING (line 3896) | JSONCPP_STRING FastWriter::write(const Value& root) {
    function JSONCPP_STRING (line 3957) | JSONCPP_STRING StyledWriter::write(const Value& root) {
    type CommentStyle (line 4369) | struct CommentStyle {
      type Enum (line 4371) | enum Enum {
    type BuiltStyledStreamWriter (line 4378) | struct BuiltStyledStreamWriter : public StreamWriter {
    function StreamWriter (line 4643) | StreamWriter* StreamWriterBuilder::newStreamWriter() const {
    function getValidWriterKeys (line 4672) | static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 4697) | Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { return se...
    function JSONCPP_STRING (line 4710) | JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value...
    function JSONCPP_OSTREAM (line 4717) | JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
  type Json (line 3659) | namespace Json {
    function JSONCPP_STRING (line 98) | static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
    function isControlCharacter (line 127) | static inline bool isControlCharacter(char ch) { return ch > 0 && ch <...
    function uintToString (line 143) | static inline void uintToString(LargestUInt value, char*& current) {
    function fixNumericLocale (line 156) | static inline void fixNumericLocale(char* begin, char* end) {
    function Features (line 239) | Features Features::all() { return Features(); }
    function Features (line 241) | Features Features::strictMode() {
    function containsNewLine (line 253) | static bool containsNewLine(Reader::Location begin, Reader::Location e...
    function JSONCPP_STRING (line 540) | static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Loc...
    function Value (line 891) | Value& Reader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 918) | JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) con...
    function JSONCPP_STRING (line 927) | JSONCPP_STRING Reader::getFormatedErrorMessages() const { return getFo...
    function JSONCPP_STRING (line 929) | JSONCPP_STRING Reader::getFormattedErrorMessages() const {
    class OurFeatures (line 986) | class OurFeatures {
    function OurFeatures (line 1003) | OurFeatures OurFeatures::all() { return OurFeatures(); }
    class OurReader (line 1009) | class OurReader {
      type StructuredError (line 1013) | struct StructuredError {
      type TokenType (line 1031) | enum TokenType {
      class Token (line 1051) | class Token {
      class ErrorInfo (line 1058) | class ErrorInfo {
    function Value (line 1786) | Value& OurReader::currentValue() { return *(nodes_.top()); }
    function JSONCPP_STRING (line 1813) | JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) ...
    function JSONCPP_STRING (line 1821) | JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
    class OurCharReader (line 1877) | class OurCharReader : public CharReader {
      method OurCharReader (line 1882) | OurCharReader(bool collectComments, OurFeatures const& features) : c...
      method parse (line 1883) | bool parse(char const* beginDoc, char const* endDoc, Value* root, JS...
    function CharReader (line 1894) | CharReader* CharReaderBuilder::newCharReader() const {
    function getValidReaderKeys (line 1908) | static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 1937) | Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { return sett...
    function parseFromStream (line 1971) | bool parseFromStream(CharReader::Factory const& fact, JSONCPP_ISTREAM&...
    function JSONCPP_ISTREAM (line 1982) | JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
    function Value (line 2025) | Value& ValueIteratorBase::deref() const { return current_->second; }
    function Value (line 2069) | Value ValueIteratorBase::key() const {
    function UInt (line 2078) | UInt ValueIteratorBase::index() const {
    function JSONCPP_STRING (line 2084) | JSONCPP_STRING ValueIteratorBase::name() const {
    function ValueConstIterator (line 2121) | ValueConstIterator& ValueConstIterator::operator=(const ValueIteratorB...
    function ValueIterator (line 2144) | ValueIterator& ValueIterator::operator=(const SelfType& other) {
    function Value (line 2198) | Value const& Value::nullSingleton() {
    function InRange (line 2226) | static inline bool InRange(double d, T min, U max) {
    function integerToDouble (line 2233) | static inline double integerToDouble(Json::UInt64 value) {
    function integerToDouble (line 2238) | static inline double integerToDouble(T value) {
    function InRange (line 2243) | static inline bool InRange(double d, T min, U max) {
    function decodePrefixedString (line 2291) | inline static void decodePrefixedString(bool isPrefixed, char const* p...
    function releasePrefixedStringValue (line 2303) | static inline void releasePrefixedStringValue(char* value) {
    function releaseStringValue (line 2311) | static inline void releaseStringValue(char* value, unsigned length) {
    function releasePrefixedStringValue (line 2318) | static inline void releasePrefixedStringValue(char* value) { free(valu...
    function releaseStringValue (line 2319) | static inline void releaseStringValue(char* value, unsigned) { free(va...
    function JSONCPP_NORETURN (line 2343) | JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { t...
    function JSONCPP_NORETURN (line 2344) | JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { thr...
    function ArrayIndex (line 2446) | ArrayIndex Value::CZString::index() const { return index_; }
    function Value (line 2618) | Value& Value::operator=(Value other) {
    function ValueType (line 2640) | ValueType Value::type() const { return type_; }
    function JSONCPP_STRING (line 2773) | JSONCPP_STRING Value::asString() const {
    function LargestInt (line 2891) | LargestInt Value::asLargestInt() const {
    function LargestUInt (line 2899) | LargestUInt Value::asLargestUInt() const {
    function ArrayIndex (line 2996) | ArrayIndex Value::size() const {
    function Value (line 3058) | Value& Value::operator[](ArrayIndex index) {
    function Value (line 3070) | Value& Value::operator[](int index) {
    function Value (line 3075) | const Value& Value::operator[](ArrayIndex index) const {
    function Value (line 3084) | const Value& Value::operator[](int index) const {
    function Value (line 3100) | Value& Value::resolveReference(const char* key) {
    function Value (line 3114) | Value& Value::resolveReference(char const* key, char const* cend) {
    function Value (line 3127) | Value Value::get(ArrayIndex index, const Value& defaultValue) const {
    function Value (line 3134) | Value const* Value::find(char const* key, char const* cend) const {
    function Value (line 3142) | const Value& Value::operator[](const char* key) const {
    function Value (line 3147) | Value const& Value::operator[](JSONCPP_STRING const& key) const {
    function Value (line 3153) | Value& Value::operator[](const char* key) { return resolveReference(ke...
    function Value (line 3155) | Value& Value::operator[](const JSONCPP_STRING& key) { return resolveRe...
    function Value (line 3157) | Value& Value::operator[](const StaticString& key) { return resolveRefe...
    function Value (line 3160) | Value& Value::operator[](const CppTL::ConstString& key) { return resol...
    function Value (line 3161) | Value const& Value::operator[](CppTL::ConstString const& key) const {
    function Value (line 3168) | Value& Value::append(const Value& value) { return (*this)[size()] = va...
    function Value (line 3170) | Value Value::get(char const* key, char const* cend, Value const& defau...
    function Value (line 3174) | Value Value::get(char const* key, Value const& defaultValue) const { r...
    function Value (line 3175) | Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue)...
    function Value (line 3190) | Value Value::removeMember(const char* key) {
    function Value (line 3198) | Value Value::removeMember(const JSONCPP_STRING& key) { return removeMe...
    function Value (line 3224) | Value Value::get(const CppTL::ConstString& key, const Value& defaultVa...
    function IsIntegral (line 3276) | static bool IsIntegral(double d) {
    function JSONCPP_STRING (line 3384) | JSONCPP_STRING Value::getComment(CommentPlacement placement) const {
    function JSONCPP_STRING (line 3397) | JSONCPP_STRING Value::toStyledString() const {
    function Value (line 3517) | const Value& Path::resolve(const Value& root) const {
    function Value (line 3540) | Value Path::resolve(const Value& root, const Value& defaultValue) const {
    function Value (line 3556) | Value& Path::make(Value& root) const {
    function containsControlCharacter (line 3667) | static bool containsControlCharacter(const char* str) {
    function containsControlCharacter0 (line 3674) | static bool containsControlCharacter0(const char* str, unsigned len) {
    function JSONCPP_STRING (line 3683) | JSONCPP_STRING valueToString(LargestInt value) {
    function JSONCPP_STRING (line 3699) | JSONCPP_STRING valueToString(LargestUInt value) {
    function JSONCPP_STRING (line 3709) | JSONCPP_STRING valueToString(Int value) { return valueToString(Largest...
    function JSONCPP_STRING (line 3711) | JSONCPP_STRING valueToString(UInt value) { return valueToString(Larges...
    function JSONCPP_STRING (line 3716) | JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsi...
    function JSONCPP_STRING (line 3747) | JSONCPP_STRING valueToString(double value) { return valueToString(valu...
    function JSONCPP_STRING (line 3749) | JSONCPP_STRING valueToString(bool value) { return value ? "true" : "fa...
    function JSONCPP_STRING (line 3751) | JSONCPP_STRING valueToQuotedString(const char* value) {
    function JSONCPP_STRING (line 3823) | static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned...
    function JSONCPP_STRING (line 3896) | JSONCPP_STRING FastWriter::write(const Value& root) {
    function JSONCPP_STRING (line 3957) | JSONCPP_STRING StyledWriter::write(const Value& root) {
    type CommentStyle (line 4369) | struct CommentStyle {
      type Enum (line 4371) | enum Enum {
    type BuiltStyledStreamWriter (line 4378) | struct BuiltStyledStreamWriter : public StreamWriter {
    function StreamWriter (line 4643) | StreamWriter* StreamWriterBuilder::newStreamWriter() const {
    function getValidWriterKeys (line 4672) | static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) {
    function Value (line 4697) | Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { return se...
    function JSONCPP_STRING (line 4710) | JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value...
    function JSONCPP_OSTREAM (line 4717) | JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {

FILE: examples/websocket_client/testclient.cpp
  function send_loop (line 17) | void send_loop(std::shared_ptr<DataChannel> dc) {
  function main (line 35) | int main() {

FILE: include/rtcdcpp/Chunk.hpp
  type rtcdcpp (line 36) | namespace rtcdcpp {
    class Chunk (line 39) | class Chunk {
      method Chunk (line 49) | Chunk(const void *dataToCopy, size_t dataLen) : len(dataLen), data(n...
      method Chunk (line 52) | Chunk(const Chunk &other) : len(other.len), data(new uint8_t[len]) {...
      method Chunk (line 55) | Chunk &operator=(const Chunk &other) {
      method Size (line 68) | size_t Size() const { return len; }
      method Length (line 69) | size_t Length() const { return Size(); }

FILE: include/rtcdcpp/ChunkQueue.hpp
  type rtcdcpp (line 39) | namespace rtcdcpp {
    class ChunkQueue (line 44) | class ChunkQueue {
      method ChunkQueue (line 52) | ChunkQueue() : chunk_queue(), stopping(false) {}
      method Stop (line 54) | void Stop() {
      method push (line 60) | void push(ChunkPtr chunk) {
      method ChunkPtr (line 69) | ChunkPtr wait_and_pop() {
      method empty (line 84) | bool empty() const {

FILE: include/rtcdcpp/DTLSWrapper.hpp
  type rtcdcpp (line 42) | namespace rtcdcpp {
    class DTLSWrapper (line 44) | class DTLSWrapper {
      method RTCCertificate (line 49) | const RTCCertificate *certificate() { return certificate_; }

FILE: include/rtcdcpp/DataChannel.hpp
  type rtcdcpp (line 38) | namespace rtcdcpp {
    class PeerConnection (line 72) | class PeerConnection
    class DataChannel (line 74) | class DataChannel {

FILE: include/rtcdcpp/Logging.hpp
  type rtcdcpp (line 38) | namespace rtcdcpp {
    class Logger (line 46) | class Logger {
      method Logger (line 49) | Logger() = default;
      method Logger (line 51) | Logger(const Logger &) = delete;
      method Logger (line 53) | Logger(Logger &&) = delete;
      method trace (line 57) | void trace(const char *fmt, const Args &... args) {}
      method debug (line 59) | void debug(const char *fmt, const Args &... args) {}
      method info (line 61) | void info(const char *fmt, const Args &... args) {}
      method warn (line 63) | void warn(const char *fmt, const Args &... args) {}
      method error (line 65) | void error(const char *fmt, const Args &... args) {}
      method critical (line 67) | void critical(const char *fmt, const Args &... args) {}
      method trace (line 70) | void trace(const T &) {}
      method debug (line 72) | void debug(const T &) {}
      method info (line 74) | void info(const T &) {}
      method warn (line 76) | void warn(const T &) {}
      method error (line 78) | void error(const T &) {}
      method critical (line 80) | void critical(const T &) {}

FILE: include/rtcdcpp/NiceWrapper.hpp
  type rtcdcpp (line 44) | namespace rtcdcpp {
    class NiceWrapper (line 49) | class NiceWrapper {

FILE: include/rtcdcpp/PeerConnection.hpp
  type rtcdcpp (line 37) | namespace rtcdcpp {
    class NiceWrapper (line 39) | class NiceWrapper
    class DTLSWrapper (line 40) | class DTLSWrapper
    class SCTPWrapper (line 41) | class SCTPWrapper
    type RTCIceServer (line 43) | struct RTCIceServer {
    type RTCConfiguration (line 50) | struct RTCConfiguration {
    class PeerConnection (line 58) | class PeerConnection {
      type IceCandidate (line 60) | struct IceCandidate {
        method IceCandidate (line 61) | IceCandidate(const std::string &candidate, const std::string &sdpM...
      method RTCConfiguration (line 75) | const RTCConfiguration &config() { return config_; }
      type Role (line 134) | enum Role { Client, Server }

FILE: include/rtcdcpp/RTCCertificate.hpp
  type rtcdcpp (line 39) | namespace rtcdcpp {
    class RTCCertificate (line 43) | class RTCCertificate {
      method X509 (line 54) | X509 *x509() const { return x509_.get(); }
      method EVP_PKEY (line 55) | EVP_PKEY *evp_pkey() const { return evp_pkey_.get(); }

FILE: include/rtcdcpp/SCTPWrapper.hpp
  type rtcdcpp (line 41) | namespace rtcdcpp {
    class SCTPWrapper (line 46) | class SCTPWrapper {
      type socket (line 70) | struct socket
      type socket (line 96) | struct socket
      type sctp_rcvinfo (line 96) | struct sctp_rcvinfo
      type socket (line 104) | struct socket
      type sctp_rcvinfo (line 104) | struct sctp_rcvinfo

FILE: src/DTLSWrapper.cpp
  type rtcdcpp (line 41) | namespace rtcdcpp {
    function verify_peer_certificate (line 73) | static int verify_peer_certificate(int ok, X509_STORE_CTX *ctx) {

FILE: src/DataChannel.cpp
  type rtcdcpp (line 37) | namespace rtcdcpp {
    function Close (line 62) | void Close() { ; }

FILE: src/Logging.cpp
  type rtcdcpp (line 30) | namespace rtcdcpp {
    function GetLogger (line 36) | std::shared_ptr<Logger> GetLogger(const std::string &logger_name) {
    function GetLogger (line 48) | std::shared_ptr<Logger> GetLogger(const std::string &logger) {

FILE: src/NiceWrapper.cpp
  function ReplaceAll (line 38) | void ReplaceAll(std::string &s, const std::string &search, const std::st...
  type rtcdcpp (line 46) | namespace rtcdcpp {
    function new_local_candidate (line 58) | void new_local_candidate(NiceAgent *agent, NiceCandidate *candidate, g...
    function candidate_gathering_done (line 71) | void candidate_gathering_done(NiceAgent *agent, guint stream_id, gpoin...
    function component_state_changed (line 84) | void component_state_changed(NiceAgent *agent, guint stream_id, guint ...
    function new_selected_pair (line 119) | void new_selected_pair(NiceAgent *agent, guint stream_id, guint compon...
    function data_received (line 128) | void data_received(NiceAgent *agent, guint stream_id, guint component_...
    function nice_log_handler (line 138) | void nice_log_handler(const gchar *log_domain, GLogLevelFlags log_leve...
    type hostent (line 172) | struct hostent

FILE: src/PeerConnection.cpp
  type rtcdcpp (line 41) | namespace rtcdcpp {
    function random_session_id (line 119) | std::string random_session_id() {

FILE: src/RTCCertificate.cpp
  type rtcdcpp (line 36) | namespace rtcdcpp {
    function GenerateX509 (line 40) | static std::shared_ptr<X509> GenerateX509(std::shared_ptr<EVP_PKEY> ev...
    function GenerateFingerprint (line 91) | static std::string GenerateFingerprint(std::shared_ptr<X509> x509) {
    function RTCCertificate (line 113) | RTCCertificate RTCCertificate::GenerateCertificate(std::string common_...

FILE: src/SCTPWrapper.cpp
  type rtcdcpp (line 36) | namespace rtcdcpp {
    type socket (line 145) | struct socket
    type sctp_rcvinfo (line 145) | struct sctp_rcvinfo
    type socket (line 154) | struct socket
    type sctp_rcvinfo (line 154) | struct sctp_rcvinfo
    type linger (line 191) | struct linger
    type sctp_paddrparams (line 199) | struct sctp_paddrparams
    type sctp_assoc_value (line 208) | struct sctp_assoc_value
    type sctp_event (line 223) | struct sctp_event
    type sctp_initmsg (line 236) | struct sctp_initmsg
    type sockaddr_conn (line 245) | struct sockaddr_conn
    type sockaddr_conn (line 250) | struct sockaddr_conn
    type sockaddr (line 253) | struct sockaddr
    type sctp_sendv_spa (line 300) | struct sctp_sendv_spa
    type sockaddr_conn (line 357) | struct sockaddr_conn
    type sockaddr (line 366) | struct sockaddr
Condensed preview — 41 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (488K chars).
[
  {
    "path": ".clang-format",
    "chars": 54,
    "preview": "BasedOnStyle: Google\nColumnLimit: 150\nStandard: Cpp11\n"
  },
  {
    "path": ".gitignore",
    "chars": 112,
    "preview": "/.idea/\n/BUILD/\n/examples/.env/\n*.so\nspdlog/\nCMakeCache.txt\nCMakeFiles/\nMakefile\ncmake_install.cmake\ntestclient\n"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 1805,
    "preview": "cmake_minimum_required(VERSION 3.0)\n\nproject(librtcdcpp\n        VERSION 1.0.0\n        LANGUAGES CXX)\n\noption(DISABLE_SPD"
  },
  {
    "path": "LICENSE.md",
    "chars": 1538,
    "preview": "Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\nAll rights reserved.\n\nRedistribution and use in sou"
  },
  {
    "path": "README.md",
    "chars": 1359,
    "preview": "librtcdcpp - A Simple WebRTC DataChannels Library\n=================================================\n\nlibrtcdcpp is a sim"
  },
  {
    "path": "cmake/Modules/FindGLIB.cmake",
    "chars": 5513,
    "preview": "# - Try to find Glib and its components (gio, gobject etc)\n# Once done, this will define\n#\n#  GLIB_FOUND - system has Gl"
  },
  {
    "path": "cmake/Modules/FindLibNice.cmake",
    "chars": 1412,
    "preview": "if (NOT TARGET LibNice::LibNice)\n    find_package(PkgConfig)\n    pkg_check_modules(PC_LIBNICE nice)\n    set(LIBNICE_DEFI"
  },
  {
    "path": "cmake/Modules/FindSpdlog.cmake",
    "chars": 366,
    "preview": "if (NOT TARGET Gabime::Spdlog)\n    include(FindPackageHandleStandardArgs)\n    find_path(SPDLOG_INCLUDE_DIR NAMES spdlog/"
  },
  {
    "path": "cmake/Modules/FindUsrSCTP.cmake",
    "chars": 938,
    "preview": "# Simple libnice cmake find\n\nif (NOT TARGET SctpLab::UsrSCTP)\n    set(USRSCTP_DEFINITIONS INET INET6)\n    find_path(USRS"
  },
  {
    "path": "examples/README.md",
    "chars": 507,
    "preview": "\n\nRunning the Demo\n----------------\n\nTo run the demo, first run:\n\n\tcd examples\n\tpython site-api.py\n\nThis should start a "
  },
  {
    "path": "examples/site-api.py",
    "chars": 1421,
    "preview": "#!/usr/bin/env python\n# Sets up a basic site that can allow two browsers to connect to each\n# other via WebRTC DataChann"
  },
  {
    "path": "examples/static/adapter.js",
    "chars": 93880,
    "preview": "(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"func"
  },
  {
    "path": "examples/static/demo.css",
    "chars": 142,
    "preview": "\n#logs_container {\n  display: flex;\n  flex-direction: row;\n  width: 100%;\n}\n\n\n#reliable_logs {\n  flex: 1;\n}\n\n#datachanne"
  },
  {
    "path": "examples/static/index.html",
    "chars": 8592,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <title>WebRTC DataChannels Demo Site</title>\n  <link rel=\"stylesheet\" type=\"text/css\" hr"
  },
  {
    "path": "examples/websocket_client/CMakeLists.txt",
    "chars": 270,
    "preview": "add_executable(testclient\n        json/json.h\n        json/json-forwards.h\n        easywsclient.cpp\n        easywsclient"
  },
  {
    "path": "examples/websocket_client/WebSocketWrapper.cpp",
    "chars": 1263,
    "preview": "#include \"WebSocketWrapper.hpp\"\n#include <thread>\n#include <iostream>\n\nusing namespace rtcdcpp;\n\nWebSocketWrapper::WebSo"
  },
  {
    "path": "examples/websocket_client/WebSocketWrapper.hpp",
    "chars": 839,
    "preview": "/**\n * Simple libwebsockets C++ wrapper\n */\n\n#include \"easywsclient.hpp\"\n\n#include <assert.h>\n#include <stdio.h>\n\n#inclu"
  },
  {
    "path": "examples/websocket_client/easywsclient.cpp",
    "chars": 18272,
    "preview": "\n#ifdef _WIN32\n#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)\n#define _CRT_SECURE_NO_WARNINGS  // _CRT_SECUR"
  },
  {
    "path": "examples/websocket_client/easywsclient.hpp",
    "chars": 2631,
    "preview": "#ifndef EASYWSCLIENT_HPP_20120819_MIOFVASDTNUASZDQPLFD\n#define EASYWSCLIENT_HPP_20120819_MIOFVASDTNUASZDQPLFD\n\n// This c"
  },
  {
    "path": "examples/websocket_client/json/json-forwards.h",
    "chars": 11069,
    "preview": "/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).\n/// It is intended to be used with #include \"js"
  },
  {
    "path": "examples/websocket_client/json/json.h",
    "chars": 69513,
    "preview": "/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).\n/// It is intended to be used with #include \"json/json."
  },
  {
    "path": "examples/websocket_client/jsoncpp.cpp",
    "chars": 152242,
    "preview": "/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).\n/// It is intended to be used with #include \"json/json."
  },
  {
    "path": "examples/websocket_client/testclient.cpp",
    "chars": 3688,
    "preview": "/**\n * Simple WebRTC test client.\n */\n\n#include \"WebSocketWrapper.hpp\"\n#include \"json/json.h\"\n\n#include <rtcdcpp/PeerCon"
  },
  {
    "path": "include/rtcdcpp/Chunk.hpp",
    "chars": 2674,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "include/rtcdcpp/ChunkQueue.hpp",
    "chars": 2699,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "include/rtcdcpp/DTLSWrapper.hpp",
    "chars": 2839,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "include/rtcdcpp/DataChannel.hpp",
    "chars": 5117,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "include/rtcdcpp/Logging.hpp",
    "chars": 3029,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "include/rtcdcpp/NiceWrapper.hpp",
    "chars": 4689,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "include/rtcdcpp/PeerConnection.hpp",
    "chars": 5282,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "include/rtcdcpp/RTCCertificate.hpp",
    "chars": 2409,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "include/rtcdcpp/SCTPWrapper.hpp",
    "chars": 3934,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "include/rtcdcpp/librtcdcpp.h",
    "chars": 1670,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "src/DTLSWrapper.cpp",
    "chars": 8007,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "src/DataChannel.cpp",
    "chars": 4109,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "src/Logging.cpp",
    "chars": 2119,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "src/NiceWrapper.cpp",
    "chars": 12635,
    "preview": "/**\r\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\r\n * All rights reserved.\r\n *\r\n * Redistribu"
  },
  {
    "path": "src/PeerConnection.cpp",
    "chars": 9839,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "src/RTCCertificate.cpp",
    "chars": 5573,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "src/SCTPWrapper.cpp",
    "chars": 13213,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  },
  {
    "path": "src/librtcdcpp.c",
    "chars": 1670,
    "preview": "/**\n * Copyright (c) 2017, Andrew Gault, Nick Chadwick and Guillaume Egles.\n * All rights reserved.\n *\n * Redistribution"
  }
]

About this extraction

This page contains the full source code of the chadnickbok/librtcdcpp GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 41 files (457.9 KB), approximately 114.9k tokens, and a symbol index with 259 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!