# Java Templates
Templates:
    # Syntax
    EqualitySyntaxTemplate: &EqualitySyntaxTemplate !!js/function >
        (lhs, op, rhs) => {
            if (op.includes('!')) {
                return `${lhs} != ${rhs}`;
            }
            else {
                return `${lhs} == ${rhs}`;
            }
        }
    EosSyntaxTemplate: &EosSyntaxTemplate null
    EofSyntaxTemplate: &EofSyntaxTemplate null
    # BSON Object Type templates
    CodeTypeTemplate: &CodeTypeTemplate null
    StringTypeTemplate: &StringTypeTemplate !!js/function >
        (str) => {
          let newStr = str;
          if (
            (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
            (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
            newStr = str.substr(1, str.length - 2);
          }
          return `"${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}"`;
        }
    RegexTypeTemplate: &RegexTypeTemplate !!js/function >
        (pattern, flags) => {
            flags = flags === '' ? '' : `(?${flags})`;
            // Double escape characters except for slashes
            const escaped = pattern.replace(/\\/, '\\\\');

            // Double-quote stringify
            const str = escaped + flags;
            let newStr = str;
            if (
                (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
                (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
                    newStr = str.substr(1, str.length - 2);
            }
            return `Pattern.compile("${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}")`;
        }
    BoolTypeTemplate: &BoolTypeTemplate null
    IntegerTypeTemplate: &IntegerTypeTemplate null
    DecimalTypeTemplate: &DecimalTypeTemplate !!js/function >
        (literal, type) => {
            if (type === '_integer' || type === '_long' || type === '_decimal') {
                return `${literal}d`;
            }
            return `(double) ${literal}`;
        }
    LongBasicTypeTemplate: &LongBasicTypeTemplate !!js/function >
        (literal, type) => {
            if (type === '_integer' || type === '_long') {
                return `${literal}L`;
            }
            return `new Long(${literal})`;
        }
    HexTypeTemplate: &HexTypeTemplate null # TODO
    OctalTypeTemplate: &OctalTypeTemplate !!js/function >
        (literal, type) => {
            if ((literal.charAt(0) === '0' && literal.charAt(1) === '0') ||
                (literal.charAt(0) === '0' && (literal.charAt(1) === 'o' || literal.charAt(1) === 'O'))) {
              return `0${literal.substr(2, literal.length - 1)}`;
            }
            return literal;
        }
    NumericTypeTemplate: &NumericTypeTemplate null
    ArrayTypeTemplate: &ArrayTypeTemplate !!js/function >
        (literal, depth) => {
            // TODO: figure out how to best do depth in an array and where to
            // insert and indent
            const indent = '\n' + '    '.repeat(depth);
            // have an indent on every ', new Document' in an array not
            // entirely perfect, but at least makes this more readable/also
            // compiles
            const arr = literal.split(', new').join(`, ${indent}new`)

            return `Arrays.asList(${arr})`;
        }
    ArrayTypeArgsTemplate: &ArrayTypeArgsTemplate null
    NullTypeTemplate: &NullTypeTemplate !!js/function >
        () => {
            return 'new BsonNull()';
        }
    UndefinedTypeTemplate: &UndefinedTypeTemplate !!js/function >
        () => {
            return 'new BsonUndefined()';
        }
    ObjectTypeTemplate: &ObjectTypeTemplate !!js/function >
        (literal, depth) => {

            if (literal === '') {
                return `new Document()`;
            }
            return literal;
        }
    ObjectTypeArgsTemplate: &ObjectTypeArgsTemplate !!js/function >
        (args, depth) => {
            const indent = '\n' + '    '.repeat(depth);
            const doubleStringify = (str) => {
                let newStr = str;
                if (
                  (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
                  (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
                    newStr = str.substr(1, str.length - 2);
                }
                return `"${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}"`;
            }
            const start = `${indent}new Document(${doubleStringify(args[0][0])}, ${args[0][1]})`;

            args = args.slice(1);
            const result = args.reduce((str, pair) => {
                return `${str}${indent}.append(${doubleStringify(pair[0])}, ${pair[1]})`;
            }, start);

            return `${result}`;
        }
    DoubleTypeTemplate: &DoubleTypeTemplate !!js/function >
        (literal, type) => {
            if (type === '_integer' || type === '_long' || type === '_decimal') {
                return `${literal}d`;
            }
            return `(double) ${literal}`;
        }
    DoubleTypeArgsTemplate: &DoubleTypeArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongTypeTemplate: &LongTemplate !!js/function >
        () => {
            return '';
        }
    LongTypeArgsTemplate: &LongSymbolArgsTemplate null
    # BSON Object Method templates
    ObjectIdToStringTemplate: &ObjectIdToStringTemplate !!js/function >
        (lhs) => {
            return `${lhs}.toHexString`;
        }
    ObjectIdToStringArgsTemplate: &ObjectIdToStringArgsTemplate null
    ObjectIdEqualsTemplate: &ObjectIdEqualsTemplate null
    ObjectIdEqualsArgsTemplate: &ObjectIdEqualsArgsTemplate null
    ObjectIdGetTimestampTemplate: &ObjectIdGetTimestampTemplate null
    ObjectIdGetTimestampArgsTemplate: &ObjectIdGetTimestampArgsTemplate null
    CodeCodeTemplate: &CodeCodeTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getCode()`;
        }
    CodeCodeArgsTemplate: &CodeCodeArgsTemplate null
    CodeScopeTemplate: &CodeScopeTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getScope()`;
        }
    CodeScopeArgsTemplate: &CodeScopeArgsTemplate null
    BinaryValueTemplate: &BinaryValueTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getData`;
        }
    BinaryValueArgsTemplate: &BinaryValueArgsTemplate null
    BinaryLengthTemplate: &BinaryLengthTemplate null
    BinaryLengthArgsTemplate: &BinaryLengthArgsTemplate null
    BinaryToStringTemplate: &BinaryToStringTemplate null
    BinaryToStringArgsTemplate: &BinaryToStringArgsTemplate null
    BinarySubtypeTemplate: &BinarySubtypeTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getType()`;
        }
    BinarySubtypeArgsTemplate: &BinarySubtypeArgsTemplate !!js/function >
        () => {
            return '';
        }
    DBRefGetDBTemplate: &DBRefGetDBTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getDatabaseName()`;
        }
    DBRefGetDBArgsTemplate: &DBRefGetDBArgsTemplate !!js/function >
        () => {
            return '';
        }
    DBRefGetCollectionTemplate: &DBRefGetCollectionTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getCollectionName()`;
        }
    DBRefGetCollectionArgsTemplate: &DBRefGetCollectionArgsTemplate !!js/function >
        () => {
            return '';
        }
    DBRefGetIdTemplate: &DBRefGetIdTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getId()`;
        }
    DBRefGetIdArgsTemplate: &DBRefGetIdArgsTemplate !!js/function >
        () => {
            return '';
        }
    DBRefToStringTemplate: &DBRefToStringTemplate null
    DBRefToStringArgsTemplate: &DBRefToStringArgsTemplate null
    DoubleValueOfTemplate: &DoubleValueOfTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    DoubleValueOfArgsTemplate: &DoubleValueOfArgsTemplate !!js/function >
        () => {
            return '';
        }
    Int32ValueOfTemplate: &Int32ValueOfTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    Int32ValueOfArgsTemplate: &Int32ValueOfArgsTemplate !!js/function >
        () => {
            return '';
        }
    Int32ToStringTemplate: &Int32ToStringTemplate !!js/function >
        () => {
            return '';
        }
    Int32ToStringArgsTemplate: &Int32ToStringArgsTemplate !!js/function >
        (lhs) => {
            return `Integer.toString(${lhs})`;
        }
    LongEqualsTemplate: &LongEqualsTemplate !!js/function >
        (lhs) => {
            return `${lhs} ==`;
        }
    LongEqualsArgsTemplate: &LongEqualsArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongToStringTemplate: &LongToStringTemplate !!js/function > # Also has emit method
        (lhs) => {
            return lhs;
        }
    LongToStringArgsTemplate: &LongToStringArgsTemplate null
    LongToIntTemplate: &LongToIntTemplate !!js/function >
        (lhs) => {
            return `(int) ${lhs}`;
        }
    LongToIntArgsTemplate: &LongToIntArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongValueOfTemplate: &LongValueOfTemplate !!js/function >
        (lhs) => {
            return `(int) ${lhs}`;
        }
    LongValueOfArgsTemplate: &LongValueOfArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongToNumberTemplate: &LongToNumberTemplate !!js/function >
        (lhs) => {
            return `(double) ${lhs}`;
        }
    LongToNumberArgsTemplate: &LongToNumberArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongAddTemplate: &LongAddTemplate !!js/function >
        (lhs) => {
            return `${lhs} +`;
        }
    LongAddArgsTemplate: &LongAddArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongSubtractTemplate: &LongSubtractTemplate !!js/function >
        (arg) => {
            return `${arg} -`;
        }
    LongSubtractArgsTemplate: &LongSubtractArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongMultiplyTemplate: &LongMultiplyTemplate !!js/function >
        (arg) => {
            return `${arg} *`;
        }
    LongMultiplyArgsTemplate: &LongMultiplyArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongDivTemplate: &LongDivTemplate !!js/function >
        (lhs) => {
            return `${lhs} /`;
        }
    LongDivArgsTemplate: &LongDivArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongModuloTemplate: &LongModuloTemplate !!js/function >
        (lhs) => {
            return `${lhs} %`;
        }
    LongModuloArgsTemplate: &LongModuloArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongAndTemplate: &LongAndTemplate !!js/function >
        (lhs) => {
            return `${lhs} &`;
        }
    LongAndArgsTemplate: &LongAndArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongOrTemplate: &LongOrTemplate !!js/function >
        (lhs) => {
            return `${lhs} |`;
        }
    LongOrArgsTemplate: &LongOrArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongXorTemplate: &LongXorTemplate !!js/function >
        (lhs) => {
            return `${lhs} ^`;
        }
    LongXorArgsTemplate: &LongXorArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongShiftLeftTemplate: &LongShiftLeftTemplate !!js/function >
        () => {
            return 'Long.rotateLeft';
        }
    LongShiftLeftArgsTemplate: &LongShiftLeftArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${lhs}, ${arg})`;
        }
    LongShiftRightTemplate: &LongShiftRightTemplate !!js/function >
        () => {
            return 'Long.rotateRight';
        }
    LongShiftRightArgsTemplate: &LongShiftRightArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${lhs}, ${arg})`;
        }
    LongCompareTemplate: &LongCompareTemplate !!js/function >
        (lhs) => {
            return `${lhs} -`;
        }
    LongCompareArgsTemplate: &LongCompareArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongIsOddTemplate: &LongIsOddTemplate !!js/function >
        (lhs) => {
            return `(${lhs} % 2) == 1`;
        }
    LongIsOddArgsTemplate: &LongIsOddArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongIsZeroTemplate: &LongIsZeroTemplate !!js/function >
        (lhs) => {
            return `${lhs} == 0`;
        }
    LongIsZeroArgsTemplate: &LongIsZeroArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongIsNegativeTemplate: &LongIsNegativeTemplate !!js/function >
        (lhs) => {
            return `${lhs} < 0`;
        }
    LongIsNegativeArgsTemplate: &LongIsNegativeArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongNegateTemplate: &LongNegateTemplate !!js/function >
        () => {
            return '-';
        }
    LongNegateArgsTemplate: &LongNegateArgsTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    LongNotTemplate: &LongNotTemplate !!js/function >
        () => {
            return '~';
        }
    LongNotArgsTemplate: &LongNotArgsTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    LongNotEqualsTemplate: &LongNotEqualsTemplate !!js/function >
        (lhs) => {
            return `${lhs} !=`;
        }
    LongNotEqualsArgsTemplate: &LongNotEqualsArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongGreaterThanTemplate: &LongGreaterThanTemplate !!js/function >
        (lhs) => {
            return `${lhs} >`;
        }
    LongGreaterThanArgsTemplate: &LongGreaterThanArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongGreaterThanOrEqualTemplate: &LongGreaterThanOrEqualTemplate !!js/function >
        (lhs) => {
            return `${lhs} >=`;
        }
    LongGreaterThanOrEqualArgsTemplate: &LongGreaterThanOrEqualArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongLessThanTemplate: &LongLessThanTemplate !!js/function >
        (lhs) => {
            return `${lhs} <`;
        }
    LongLessThanArgsTemplate: &LongLessThanArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongLessThanOrEqualTemplate: &LongLessThanOrEqualTemplate !!js/function >
        (lhs) => {
            return `${lhs} <=`;
        }
    LongLessThanOrEqualArgsTemplate: &LongLessThanOrEqualArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongFloatApproxTemplate: &LongFloatApproxTemplate !!js/function >
        (lhs) => {
            return `(float) ${lhs}`;
        }
    LongTopTemplate: &LongTopTemplate !!js/function >
        (lhs) => {
            return `${lhs} >> 32`;
        }
    LongBottomTemplate: &LongBottomTemplate !!js/function >
        (lhs) => {
            return `${lhs} & 0x0000ffff`;
        }
    TimestampToStringTemplate: &TimestampToStringTemplate null
    TimestampToStringArgsTemplate: &TimestampToStringArgsTemplate null
    TimestampEqualsTemplate: &TimestampEqualsTemplate null
    TimestampEqualsArgsTemplate: &TimestampEqualsArgsTemplate null
    TimestampGetLowBitsTemplate: &TimestampGetLowBitsTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getTime`;
        }
    TimestampGetLowBitsArgsTemplate: &TimestampGetLowBitsArgsTemplate null
    TimestampGetHighBitsTemplate: &TimestampGetHighBitsTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getInc`;
        }
    TimestampGetHighBitsArgsTemplate: &TimestampGetHighBitsArgsTemplate null
    TimestampTTemplate: &TimestampTTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getTime()`;
        }
    TimestampITemplate: &TimestampITemplate !!js/function >
        (lhs) => {
            return `${lhs}.getInc()`;
        }
    TimestampCompareTemplate: &TimestampCompareTemplate !!js/function >
        (lhs) => {
            return `${lhs}.compareTo`;
        }
    TimestampCompareArgsTemplate: &TimestampCompareArgsTemplate null
    TimestampNotEqualsTemplate: &TimestampNotEqualsTemplate !!js/function >
        (lhs) => {
            return `${lhs}.compareTo`;
        }
    TimestampNotEqualsArgsTemplate: &TimestampNotEqualsArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${arg}) != 0`;
        }
    TimestampGreaterThanTemplate: &TimestampGreaterThanTemplate !!js/function >
        (lhs) => {
            return `${lhs}.compareTo`;
        }
    TimestampGreaterThanArgsTemplate: &TimestampGreaterThanArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${arg}) > 0`;
        }
    TimestampGreaterThanOrEqualTemplate: &TimestampGreaterThanOrEqualTemplate !!js/function >
        (lhs) => {
            return `${lhs}.compareTo`;
        }
    TimestampGreaterThanOrEqualArgsTemplate: &TimestampGreaterThanOrEqualArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${arg}) >= 0`;
        }
    TimestampLessThanTemplate: &TimestampLessThanTemplate !!js/function >
        (lhs) => {
            return `${lhs}.compareTo`;
        }
    TimestampLessThanArgsTemplate: &TimestampLessThanArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${arg}) < 0`;
        }
    TimestampLessThanOrEqualTemplate: &TimestampLessThanOrEqualTemplate !!js/function >
        (lhs) => {
            return `${lhs}.compareTo`;
        }
    TimestampLessThanOrEqualArgsTemplate: &TimestampLessThanOrEqualArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${arg}) <= 0`;
        }
    SymbolValueOfTemplate: &SymbolValueOfTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getSymbol`;
        }
    SymbolValueOfArgsTemplate: &SymbolValueOfArgsTemplate null
    SymbolInspectTemplate: &SymbolInspectTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getSymbol`;
        }
    SymbolInspectArgsTemplate: &SymbolInspectArgsTemplate null
    SymbolToStringTemplate: &SymbolToStringTemplate !!js/function >
        (lhs) => {
            return `${lhs}.toString`;
        }
    SymbolToStringArgsTemplate: &SymbolToStringArgsTemplate null
    # Symbol Templates
    CodeSymbolTemplate: &CodeSymbolTemplate  !!js/function > # Also has process method
        () => {
            return 'Code';
        }
    CodeSymbolArgsTemplate: &CodeSymbolArgsTemplate !!js/function > # Also has process method
        (lhs, code, scope) => {
          // Double quote stringify
          let newStr = code === undefined ? '' : code;
          const str = newStr;
          if (
            (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
            (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
            newStr = str.substr(1, str.length - 2);
          }
          code = `"${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}"`;
          return (scope === undefined) ? `(${code})` : `WithScope(${code}, ${scope})`;
        }
    ObjectIdSymbolTemplate: &ObjectIdSymbolTemplate null
    ObjectIdSymbolArgsTemplate: &ObjectIdSymbolArgsTemplate !!js/function >
        (lhs, str) => {
          let newStr = str;
          if (
            (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
            (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
            newStr = str.substr(1, str.length - 2);
          }
          return `("${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}")`;
        }
    BinarySymbolTemplate: &BinarySymbolTemplate null
    BinarySymbolArgsTemplate: &BinarySymbolArgsTemplate !!js/function >
        (lhs, bytes, type) => {
            const str = bytes;
            let newStr = str;
            if (
              (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
              (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
                newStr = str.substr(1, str.length - 2);
            }
            bytes = `"${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}"`;

            if (type === null) {
                return `(${bytes}.getBytes("UTF-8"))`;
            }
            return `(${type}, ${bytes}.getBytes("UTF-8"))`;
        }
    BinarySymbolSubtypeDefaultTemplate: &BinarySymbolSubtypeDefaultTemplate !!js/function >
        () => {
            return 'BsonBinarySubType.BINARY';
        }
    BinarySymbolSubtypeFunctionTemplate: &BinarySymbolSubtypeFunctionTemplate !!js/function >
        () => {
            return 'BsonBinarySubType.FUNCTION';
        }
    BinarySymbolSubtypeByteArrayTemplate: &BinarySymbolSubtypeByteArrayTemplate !!js/function >
        () => {
            return 'BsonBinarySubType.BINARY';
        }
    BinarySymbolSubtypeUuidOldTemplate: &BinarySymbolSubtypeUuidOldTemplate !!js/function >
        () => {
            return 'BsonBinarySubType.UUID_LEGACY';
        }
    BinarySymbolSubtypeUuidTemplate: &BinarySymbolSubtypeUuidTemplate !!js/function >
        () => {
            return 'BsonBinarySubType.UUID_STANDARD';
        }
    BinarySymbolSubtypeMd5Template: &BinarySymbolSubtypeMd5Template !!js/function >
        () => {
            return 'BsonBinarySubType.MD5';
        }
    BinarySymbolSubtypeUserDefinedTemplate: &BinarySymbolSubtypeUserDefinedTemplate !!js/function >
        () => {
            return 'BsonBinarySubType.USER_DEFINED';
        }
    DBRefSymbolTemplate: &DBRefSymbolTemplate null
    DBRefSymbolArgsTemplate: &DBRefSymbolArgsTemplate !!js/function >
        (lhs, coll, id, db) => {
            const dbstr = db === undefined ? '' : `${db}, `;
            return `(${dbstr}${coll}, ${id})`;
        }
    DoubleSymbolTemplate: &DoubleSymbolTemplate !!js/function >
        () => {
            return '';
        }
    DoubleSymbolArgsTemplate: &DoubleSymbolArgsTemplate !!js/function >
        (lhs, arg, type) => {
            arg = arg === undefined ? 0 : arg;
            if (type === '_string') {
                return `Double.parseDouble(${arg})`;
            }
            if (type === '_integer' || type === '_long' || type === '_double' || type === '_decimal') {
                return `${arg}d`;
            }
            return `(double) ${arg}`;
        }
    Int32SymbolTemplate: &Int32SymbolTemplate !!js/function >
        () => {
            return '';
        }
    Int32SymbolArgsTemplate: &Int32SymbolArgsTemplate !!js/function >
        (lhs, arg, type) => {
            arg = arg === undefined ? 0 : arg;
            if (type === '_string') {
                return `Integer.parseInt(${arg})`;
            }
            if (type === '_integer' || type === '_long') {
                if (arg.includes('L') || arg.includes('d')) {
                    return arg.substr(0, arg.length - 1);
                }
                return arg;
            }
            return `(int) ${arg}`;
        }
    LongSymbolTemplate: &LongSymbolTemplate !!js/function >
        () => {
            return '';
        }
    LongSymbolArgsTemplate: &LongSymbolArgsTemplate !!js/function >
        (lhs, arg, type) => {
            arg = arg === undefined ? 0 : arg;
            if (type === '_string') {
                return `Long.parseLong(${arg})`;
            }
            if (type === '_integer' || type === '_long') {
                if (arg.includes('d') || arg.includes('L')) {
                    return `${arg.substr(0, arg.length - 1)}L`;
                }
                return `${arg}L`;
            }
            return `new Long(${arg})`;
        }
    LongSymbolMaxTemplate: &LongSymbolMaxTemplate !!js/function >
        () => {
            return 'Long.MAX_VALUE';
        }
    LongSymbolMaxArgsTemplate: &LongSymbolMaxArgsTemplate null
    LongSymbolMinTemplate: &LongSymbolMinTemplate !!js/function >
        () => {
            return 'Long.MIN_VALUE';
        }
    LongSymbolMinArgsTemplate: &LongSymbolMinArgsTemplate null
    LongSymbolZeroTemplate: &LongSymbolZeroTemplate !!js/function >
        () => {
            return '0L';
        }
    LongSymbolZeroArgsTemplate: &LongSymbolZeroArgsTemplate null
    LongSymbolOneTemplate: &LongSymbolOneTemplate !!js/function >
        () => {
            return '1L';
        }
    LongSymbolOneArgsTemplate: &LongSymbolOneArgsTemplate null
    LongSymbolNegOneTemplate: &LongSymbolNegOneTemplate !!js/function >
        () => {
            return '-1L';
        }
    LongSymbolNegOneArgsTemplate: &LongSymbolNegOneArgsTemplate null
    LongSymbolFromBitsTemplate: &LongSymbolFromBitsTemplate !!js/function > # Also has process method
        () => {
            return '';
        }
    LongSymbolFromBitsArgsTemplate: &LongSymbolFromBitsArgsTemplate null
    LongSymbolFromIntTemplate: &LongSymbolFromIntTemplate !!js/function >
        () => {
            return '';
        }
    LongSymbolFromIntArgsTemplate: &LongSymbolFromIntArgsTemplate !!js/function >
        (lhs, arg) => {
            return `${arg}L`;
        }
    LongSymbolFromNumberTemplate: &LongSymbolFromNumberTemplate !!js/function >
        () => {
            return '';
        }
    LongSymbolFromNumberArgsTemplate: &LongSymbolFromNumberArgsTemplate !!js/function >
        (lhs, arg) => {
            return `${arg}L`;
        }
    LongSymbolFromStringTemplate: &LongSymbolFromStringTemplate !!js/function >
        (lhs) => {
            return `Long.parseLong`;
        }
    LongSymbolFromStringArgsTemplate: &LongSymbolFromStringArgsTemplate null
    MinKeySymbolTemplate: &MinKeySymbolTemplate null
    MinKeySymbolArgsTemplate: &MinKeySymbolArgsTemplate null
    MaxKeySymbolTemplate: &MaxKeySymbolTemplate null
    MaxKeySymbolArgsTemplate: &MaxKeySymbolArgsTemplate null
    TimestampSymbolTemplate: &TimestampSymbolTemplate !!js/function >
        () => {
            return 'BSONTimestamp';
        }
    TimestampSymbolArgsTemplate: &TimestampSymbolArgsTemplate !!js/function >
        (lhs, arg1, arg2) => {
            return `(${arg1 === undefined ? 0 : arg1}, ${arg2 === undefined ? 0 : arg2})`;
        }
    SymbolSymbolTemplate: &SymbolSymbolTemplate null
    SymbolSymbolArgsTemplate: &SymbolSymbolArgsTemplate null
    BSONRegExpSymbolTemplate: &BSONRegExpSymbolTemplate !!js/function >
        () => {
            return 'BsonRegularExpression';
        }
    BSONRegExpSymbolArgsTemplate: &BSONRegExpSymbolArgsTemplate !!js/function >
        (lhs, pattern, flags) => {
            return `(${pattern}${flags ? ', ' + flags : ''})`;
        }
    Decimal128SymbolTemplate: &Decimal128SymbolTemplate null # Has process method
    Decimal128SymbolArgsTemplate: &Decimal128SymbolArgsTemplate null
    Decimal128SymbolFromStringTemplate: &Decimal128SymbolFromStringTemplate !!js/function >
        (lhs) => {
            return `${lhs}.parse`;
        }
    Decimal128SymbolFromStringArgsTemplate: &Decimal128SymbolFromStringArgsTemplate null
    Decimal128ToStringTemplate: &Decimal128ToStringTemplate null
    Decimal128ToStringArgsTemplate: &Decimal128ToStringArgsTemplate null
    # BSON Util Templates
    ObjectIdCreateFromHexStringTemplate: &ObjectIdCreateFromHexStringTemplate !!js/function >
        () => {
            return 'new ObjectId';
        }
    ObjectIdCreateFromHexStringArgsTemplate: &ObjectIdCreateFromHexStringArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${arg})`;
        }
    ObjectIdCreateFromTimeTemplate: &ObjectIdCreateFromTimeTemplate !!js/function > # Also has emit method
        () => {
            return 'new ObjectId';
        }
    ObjectIdCreateFromTimeArgsTemplate: &ObjectIdCreateFromTimeArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${arg})`;
        }
    ObjectIdIsValidTemplate: &ObjectIdIsValidTemplate null
    ObjectIdIsValidArgsTemplate: &ObjectIdIsValidArgsTemplate null
    # JS Symbol Templates
    ObjectSymbolTemplate: &ObjectSymbolTemplate null
    ObjectSymbolArgsTemplate: &ObjectSymbolArgsTemplate null
    ObjectSymbolCreateTemplate: &ObjectSymbolCreateTemplate !!js/function >
        () => {
            return '';
        }
    ObjectSymbolCreateArgsTemplate: &ObjectSymbolCreateArgsTemplate !!js/function >
        (lhs, arg) => {
            return arg;
        }
    NumberSymbolTemplate: &NumberSymbolTemplate !!js/function >
        () => {
            return '';
        }
    NumberSymbolArgsTemplate: &NumberSymbolArgsTemplate !!js/function >
        (lhs, arg, type) => {
            arg = arg === undefined ? 0 : arg;
            if (type === '_string') {
                return `Double.parseDouble(${arg})`;
            }
            if (type === '_integer' || type === '_long' || type === '_decimal') {
                return `${arg}d`;
            }
            return `(double) ${arg}`;
        }
    DateSymbolTemplate: &DateSymbolTemplate !!js/function > # Also has emit method
        () => {
            return 'java.util.Date';
        }
    DateSymbolArgsTemplate: &DateSymbolArgsTemplate null
    DateSymbolNowTemplate: &DateSymbolNowTemplate !!js/function >
        () => {
            return 'java.util.Date';
        }
    DateSymbolNowArgsTemplate: &DateSymbolNowArgsTemplate null
    RegExpSymbolTemplate: &RegExpSymbolTemplate !!js/function > # Also has emit method
        () => {
            return 'Pattern';
        }
    RegExpSymbolArgsTemplate: &RegExpSymbolArgsTemplate null
    #!!js/function >\n        () => {\n            return '';\n        }
    ImportTemplate: &ImportTemplate null
    0ImportTemplate: &0ImportTemplate null
    1ImportTemplate: &1ImportTemplate null
    2ImportTemplate: &2ImportTemplate null
    3ImportTemplate: &3ImportTemplate null
    4ImportTemplate: &4ImportTemplate null
    5ImportTemplate: &5ImportTemplate null
    6ImportTemplate: &6ImportTemplate null
    7ImportTemplate: &7ImportTemplate null
    8ImportTemplate: &8ImportTemplate !!js/function >
        () => {
            return 'import java.util.regex.Pattern;';
        }
    9ImportTemplate: &9ImportTemplate !!js/function >
        () => {
            return 'import java.util.Arrays;';
        }
    10ImportTemplate: &10ImportTemplate !!js/function >
        () => {
            return 'import org.bson.Document;';
        }
    11ImportTemplate: &11ImportTemplate !!js/function >
        () => {
            return 'import org.bson.BsonNull;';
        }
    12ImportTemplate: &12ImportTemplate !!js/function >
        () => {
            return 'import org.bson.BsonUndefined;';
        }
    100ImportTemplate: &100ImportTemplate !!js/function >
        () => {
            return 'import org.bson.types.Code;';
        }
    113ImportTemplate: &113ImportTemplate !!js/function >
        () => {
            return 'import org.bson.types.CodeWithScope;';
        }
    101ImportTemplate: &101ImportTemplate !!js/function >
        () => {
            return 'import org.bson.types.ObjectId;';
        }
    102ImportTemplate: &102ImportTemplate !!js/function >
        () => {
            return 'import org.bson.types.Binary;';
        }
    103ImportTemplate: &103ImportTemplate !!js/function >
        () => {
            return 'import com.mongodb.DBRef;';
        }
    104ImportTemplate: &104ImportTemplate null
    105ImportTemplate: &105ImportTemplate null
    106ImportTemplate: &106ImportTemplate null
    107ImportTemplate: &107ImportTemplate !!js/function >
        () => {
            return 'import org.bson.types.MinKey;';
        }
    108ImportTemplate: &108ImportTemplate !!js/function >
        () => {
            return 'import org.bson.types.MaxKey;';
        }
    109ImportTemplate: &109ImportTemplate !!js/function >
        () => {
            return 'import org.bson.BsonRegularExpression;';
        }
    110ImportTemplate: &110ImportTemplate !!js/function >
        () => {
            return 'import org.bson.types.BSONTimestamp;';
        }
    111ImportTemplate: &111ImportTemplate !!js/function >
        () => {
            return 'import org.bson.types.Symbol;';
        }
    112ImportTemplate: &112ImportTemplate !!js/function >
        () => {
            return 'import org.bson.types.Decimal128;';
        }
    114ImportTemplate: &114ImportTemplate !!js/function >
        () => {
            return 'import org.bson.BsonBinarySubType;';
        }
    200ImportTemplate: &200ImportTemplate null
    201ImportTemplate: &201ImportTemplate !!js/function >
        () => {
            return 'import java.text.SimpleDateFormat;';
        }
    300ImportTemplate: &300ImportTemplate !!js/function >
        (classes) => {
            return classes
                .filter((f, i) => (classes.indexOf(f) === i && f !== 'options'))
                .sort()
                .map((c) => {
                    return `import static com.mongodb.client.model.Filters.${c};`;
                }).join('\n');
        }
    301ImportTemplate: &301ImportTemplate !!js/function >
        (classes) => {
            return classes
                .filter((f, i) => (classes.indexOf(f) === i))
                .sort()
                .map((c) => {
                    return `import static com.mongodb.client.model.Aggregates.${c};`;
                }).join('\n');
        }
    302ImportTemplate: &302ImportTemplate !!js/function >
        (classes) => {
            return classes
                .filter((f, i) => (classes.indexOf(f) === i))
                .sort()
                .map((c) => {
                    return `import static com.mongodb.client.model.Accumulators.${c};`;
                }).join('\n');
        }
    303ImportTemplate: &303ImportTemplate !!js/function >
        (classes) => {
            return classes
                .filter((f, i) => (classes.indexOf(f) === i))
                .sort()
                .map((c) => {
                    return `import static com.mongodb.client.model.Projections.${c};`;
                }).join('\n');
        }
    304ImportTemplate: &304ImportTemplate !!js/function >
        (classes) => {
            return classes
                .filter((f, i) => (classes.indexOf(f) === i))
                .sort()
                .map((c) => {
                    return `import static com.mongodb.client.model.Sorts.${c};`;
                }).join('\n');
        }
    305ImportTemplate: &305ImportTemplate !!js/function >
        (classes) => {
            return classes
                .filter((f, i) => (classes.indexOf(f) === i))
                .sort()
                .map((c) => {
                    return `import com.mongodb.client.model.geojson.${c};`;
                }).join('\n');
        }
    306ImportTemplate: &306ImportTemplate !!js/function >
        (classes) => {
            return classes
                .filter((f, i) => (classes.indexOf(f) === i))
                .sort()
                .map((c) => {
                    return `import com.mongodb.client.model.${c};`;
                }).join('\n');
        }
