# Path: habitat/views/utils.py
# def validate_doc(data, schema):
#     """Validate *data* against *schema*, raising descriptive errors"""
#     v = Validator()
#     errors = list(v.iter_errors(data, schema))
#     if errors:
#         errors = ', '.join((str(error) for error in errors))
#         raise ForbiddenError("Validation errors: {0}".format(errors))
#     _validate_formats(data, schema) 
# 
# def read_json_schema(schemaname):
#     mypath = os.path.dirname(inspect.getfile(inspect.currentframe()))
#     path = os.path.join(mypath, "..", "..", "couchdb", "schemas", schemaname)
#     with open(path) as f:
#         schema = json.load(f)
#     return schema
# 
# Path: habitat/views/utils.py
# def only_validates(doc_type):
#     def decorator(func):
#         def wrapped(new, old, userctx, secobj):
#             new_type = new.get("type", None)
#             new_deleted = new.get("_deleted", False)
#             if old:
#                 old_type = old.get("type", None)
#             else:
#                 old_type = None
# 
#             # sanity checks
#             if old_type is None:
#                 assert old == {} or old is None
#             if new_deleted:
#                 assert new_type is None
# 
#             if new_type == doc_type and old_type in [None, doc_type]:
#                 # new doc, or modified doc of correct type. validate:
#                 return func(new, old, userctx, secobj)
# 
#             elif new_deleted and old_type == doc_type:
#                 # deletion is managed by habitat.validate
#                 return
# 
#             elif new_type == doc_type or old_type == doc_type:
#                 # one or the other types match but not both, and not a new or deleted doc.
#                 raise ForbiddenError("You cannot change the type of a doc")
# 
#             else:
#                 # other type: not our business
#                 return
# 
#         # Be a well behaved decorator!
#         wrapped.__name__ = func.__name__
#         wrapped.__doc__ = func.__doc__
#         wrapped.__dict__.update(func.__dict__)
# 
#         return wrapped
#     return decorator


import math
import json
import base64
import hashlib
import datetime
import calendar
from couch_named_python import ForbiddenError, UnauthorizedError, version
from strict_rfc3339 import rfc3339_to_timestamp, now_to_rfc3339_utcoffset
from strict_rfc3339 import timestamp_to_rfc3339_utcoffset
from .utils import validate_doc, read_json_schema
from .utils import only_validates
        if a == b:
            return True

        # relaxed float comparison.
        # Doubles provide 15-17 bits of precision. Converting to decimal and
        # back should not introduce an error larger than 1e-15, really.
        tolerance = max(a, b) * 1e-14
        return abs(a - b) < tolerance

    else:
        # string, int, bool, None, ...
        return a == b

@version(2)
@only_validates("payload_telemetry")
def validate(new, old, userctx, secobj):
    """
    Validate this payload_telemetry document against the schema, then perform
    some specific checks:

    * Admins may perform any further editing
    * If edited
        * Only the parser may add new fields to data
        * The receivers list may only get new receivers
    * If created
        * Must have one receiver
        * Must have _raw and nothing but _raw in data
    """
    global schema
    if not schema:

# Path: habitat/views/utils.py
# def validate_doc(data, schema):
#     """Validate *data* against *schema*, raising descriptive errors"""
#     v = Validator()
#     errors = list(v.iter_errors(data, schema))
#     if errors:
#         errors = ', '.join((str(error) for error in errors))
#         raise ForbiddenError("Validation errors: {0}".format(errors))
#     _validate_formats(data, schema) 
# 
# def read_json_schema(schemaname):
#     mypath = os.path.dirname(inspect.getfile(inspect.currentframe()))
#     path = os.path.join(mypath, "..", "..", "couchdb", "schemas", schemaname)
#     with open(path) as f:
#         schema = json.load(f)
#     return schema
# 
# Path: habitat/views/utils.py
# def only_validates(doc_type):
#     def decorator(func):
#         def wrapped(new, old, userctx, secobj):
#             new_type = new.get("type", None)
#             new_deleted = new.get("_deleted", False)
#             if old:
#                 old_type = old.get("type", None)
#             else:
#                 old_type = None
# 
#             # sanity checks
#             if old_type is None:
#                 assert old == {} or old is None
#             if new_deleted:
#                 assert new_type is None
# 
#             if new_type == doc_type and old_type in [None, doc_type]:
#                 # new doc, or modified doc of correct type. validate:
#                 return func(new, old, userctx, secobj)
# 
#             elif new_deleted and old_type == doc_type:
#                 # deletion is managed by habitat.validate
#                 return
# 
#             elif new_type == doc_type or old_type == doc_type:
#                 # one or the other types match but not both, and not a new or deleted doc.
#                 raise ForbiddenError("You cannot change the type of a doc")
# 
#             else:
#                 # other type: not our business
#                 return
# 
#         # Be a well behaved decorator!
#         wrapped.__name__ = func.__name__
#         wrapped.__doc__ = func.__doc__
#         wrapped.__dict__.update(func.__dict__)
# 
#         return wrapped
#     return decorator


# Path: habitat/views/payload_telemetry.py
import math
import json
import base64
import hashlib
import datetime
import calendar
from couch_named_python import ForbiddenError, UnauthorizedError, version
from strict_rfc3339 import rfc3339_to_timestamp, now_to_rfc3339_utcoffset
from strict_rfc3339 import timestamp_to_rfc3339_utcoffset
from .utils import validate_doc, read_json_schema
from .utils import only_validates

        if a == b:
            return True

        # relaxed float comparison.
        # Doubles provide 15-17 bits of precision. Converting to decimal and
        # back should not introduce an error larger than 1e-15, really.
        tolerance = max(a, b) * 1e-14
        return abs(a - b) < tolerance

    else:
        # string, int, bool, None, ...
        return a == b

@version(2)
@only_validates("payload_telemetry")
def validate(new, old, userctx, secobj):
    """
    Validate this payload_telemetry document against the schema, then perform
    some specific checks:

    * Admins may perform any further editing
    * If edited
        * Only the parser may add new fields to data
        * The receivers list may only get new receivers
    * If created
        * Must have one receiver
        * Must have _raw and nothing but _raw in data
    """
    global schema
    if not schema:

        schema = read_json_schema("payload_telemetry.json")