<commit_before>/*
Copyright 2011 Timothy J Fontaine <tjfontaine@gmail.com>

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

*/

"use strict";

var LABEL_MASK = 0xC0;

var isLabel = function (len) {
  return len & LABEL_MASK;
}

var unpack = function (buff, pos) {
  var hit_label = false,
    read_size = 0,
    start_pos = pos,
    end,
    offset,
    increaseRead,
    increasePosition,
    readLen,
    parts = [],
    len;

  increaseRead = function (len) {
    if (len === undefined) {
      len = 1;
    }

    if (!hit_label) {
      read_size += 1;
    }
  }

  increasePosition = function (len) {
    if (len === undefined) {
      len = 1;
    }
    increaseRead(len);
    pos += len;
  }

  readLen = function () {
    len = buff.readUInt8(pos);
    increasePosition();
  }

  readLen();

  while (len !== 0) {
    if (isLabel(len)) {
      offset = len - LABEL_MASK;

      if (offset === 0) {
        pos = buff.readUInt8(pos);
        increaseRead();
      } else {
        pos = offset;
      }

      readLen();
      hit_label = true;
    } else {
      end = pos + len;
      parts.push(buff.toString('ascii', pos, end));
      increasePosition(len);
      readLen();
    }
  }

  return {
    read: read_size,
    value: parts.join('.'),
  };
};
exports.unpack = unpack;

var pack = function (str) {
  var a = str.split('.'), b, i,
    buff = new Buffer(str.length + 2),
    pos = 0;

  for (i = 0; i < a.length; i++) {
    b = a[i];
    if (b.length) {
      buff.writeUInt8(b.length, pos);
      pos++;
      buff.write(b, pos, b.length);
      pos += b.length;
    }
  }
  buff.writeUInt8(0, pos);
  return buff;
};
exports.pack = pack;
<commit_msg>small logic error in increaseRead<commit_after>/*
Copyright 2011 Timothy J Fontaine <tjfontaine@gmail.com>

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

*/

"use strict";

var LABEL_MASK = 0xC0;

var isLabel = function (len) {
  return len & LABEL_MASK;
}

var unpack = function (buff, pos) {
  var hit_label = false,
    read_size = 0,
    start_pos = pos,
    end,
    offset,
    increaseRead,
    increasePosition,
    readLen,
    parts = [],
    len;

  increaseRead = function (len) {
    if (len === undefined) {
      len = 1;
    }

    if (!hit_label) {
      read_size += len;
    }
  }

  increasePosition = function (len) {
    if (len === undefined) {
      len = 1;
    }
    increaseRead(len);
    pos += len;
  }

  readLen = function () {
    len = buff.readUInt8(pos);
    increasePosition();
  }

  readLen();

  while (len !== 0) {
    if (isLabel(len)) {
      offset = len - LABEL_MASK;

      if (offset === 0) {
        pos = buff.readUInt8(pos);
        increaseRead();
      } else {
        pos = offset;
      }

      readLen();
      hit_label = true;
    } else {
      end = pos + len;
      parts.push(buff.toString('ascii', pos, end));
      increasePosition(len);
      readLen();
    }
  }

  return {
    read: read_size,
    value: parts.join('.'),
  };
};
exports.unpack = unpack;

var pack = function (str) {
  var a = str.split('.'), b, i,
    buff = new Buffer(str.length + 2),
    pos = 0;

  for (i = 0; i < a.length; i++) {
    b = a[i];
    if (b.length) {
      buff.writeUInt8(b.length, pos);
      pos++;
      buff.write(b, pos, b.length);
      pos += b.length;
    }
  }
  buff.writeUInt8(0, pos);
  return buff;
};
exports.pack = pack;
<|endoftext|>


<commit_before>import React from "react";
import ReactQuill from "react-quill";
import "../quill.core.css";
import "../quill.snow.css";
import "./BodyEditor.css";
import { Container, Row, Col } from "reactstrap";
import ScrollEvent from "react-onscroll";

_quillModules: {
  toolbar: [
    [{ header: [1, 2, false] }],
    ["bold", "italic", "underline", "strike", "blockquote"],
    [
      { list: "ordered" },
      { list: "bullet" },
      { indent: "-1" },
      { indent: "+1" }
    ],
    ["link", "image"],
    ["clean"]
  ];
  /* ... other modules */
}

_quillFormats: [
  "header",
  "bold",
  "italic",
  "underline",
  "strike",
  "blockquote",
  "list",
  "bullet",
  "indent",
  "link",
  "image"
];

class BodyEditor extends React.Component {
  constructor(props) {
    super(props);
    this.state = { fixedBar: false };
    this.handleScroll = this.handleScroll.bind(this);
  }

  handleScroll() {
    let el = this.toolBarContainer;
    let rect = el.getBoundingClientRect();
    console.log("rect", rect);
    if (rect.top <= 0) {
      this.setState({ fixedBar: true });
    } else {
      this.setState({ fixedBar: false });
    }
  }

  render() {
    return (

 this.toolBarContainer = ref}
          className={
            this.state.fixedBar ? "body-editor-box fixed" : "body-editor-box"
          }
        >
          <ScrollEvent handleScrollCallback={this.handleScroll} />
          <ReactQuill
            theme="snow"
            modules={this._quillModules}
            formats={this._quillFormats}
            bounds={"._quill"}
          >

          </ReactQuill>

    );
  }
}

export default BodyEditor;
<commit_msg>Cleanup<commit_after>import React from "react";
import ReactQuill from "react-quill";
import "../quill.core.css";
import "../quill.snow.css";
import "./BodyEditor.css";
import ScrollEvent from "react-onscroll";

const _quillModules = {
  toolbar: [
    [{ header: [1, 2, false] }],
    ["bold", "italic", "underline", "strike", "blockquote"],
    [
      { list: "ordered" },
      { list: "bullet" },
      { indent: "-1" },
      { indent: "+1" }
    ],
    ["link", "image"],
    ["clean"]
  ]
};

const _quillFormats = [
  "header",
  "bold",
  "italic",
  "underline",
  "strike",
  "blockquote",
  "list",
  "bullet",
  "indent",
  "link",
  "image"
];

class BodyEditor extends React.Component {
  constructor(props) {
    super(props);
    this.state = { fixedBar: false };
    this.handleScroll = this.handleScroll.bind(this);
  }

  handleScroll() {
    let el = this.toolBarContainer;
    let rect = el.getBoundingClientRect();
    if (rect.top <= 0) {
      this.setState({ fixedBar: true });
    } else {
      this.setState({ fixedBar: false });
    }
  }

  render() {
    return (

 this.toolBarContainer = ref}
          className={
            this.state.fixedBar ? "body-editor-box fixed" : "body-editor-box"
          }
        >
          <ScrollEvent handleScrollCallback={this.handleScroll} />
          <ReactQuill
            theme="snow"
            modules={_quillModules}
            formats={_quillFormats}
            bounds={"._quill"}
          >

          </ReactQuill>

    );
  }
}

export default BodyEditor;
<|endoftext|>


<commit_before>'use strict';

var util = require('util');
var qs = require('querystring');
var urllib = require('url');
var _ = require('underscore');
var BBPromise = require('bluebird');

var mapnik = require('mapnik');
BBPromise.promisifyAll(mapnik.Map.prototype);
BBPromise.promisifyAll(mapnik.VectorTile.prototype);

var zlib = require('zlib');
BBPromise.promisifyAll(zlib);

module.exports = {
    maxValidZoom: 26,
    maxValidCoordinate: Math.pow(2, 26),
    maxValidIndex: Math.pow(4, 26)
};

var Err = require('./Err');
var core = module.exports;
var _log, _rootDir, _npmResolver;

/**
 * Initializes the core
 * @param logger logger object that implements log(group, message) function
 * @param rootDir Absolute path of the root directory of the main app
 * @param npmResolver function that performs 'require.resolve(moduleName)' in the context of the main app
 *
 * TODO: Any suggestions about how to get rid of this ugly hack are welcome
 *
 * For example, if your main code is in ./routes/nnn.js, you would use this snipet at the top:
 * var core = require('kartotherian-core');
 * core.init(app.logger, require('path').resolve(__dirname, '..'), function (module) { return require.resolve(module); });
 */
module.exports.init = function(logger, rootDir, npmResolver) {
    _log = logger.log.bind(logger);
    _rootDir = rootDir;
    _npmResolver = npmResolver;
};

/**
 * Log info
 */
module.exports.log = function(group, message) {
    if (!_log) {
        console.log.apply(null, arguments);
    } else {
        _log.apply(null, arguments);
    }
};

/**
 * Attempt to convert Error to anything printable (with stacktrace)
 */
module.exports.errToStr = function(err) {
    return (err.body && (err.body.stack || err.body.detail)) || err.stack || err;
};

/**
 * Performs 'require()' in the context of the main app
 */
module.exports.resolveModule = function(moduleName) {
    if (!_npmResolver) throw new Err('core.init() has not been called');
    return _npmResolver(moduleName);
};

/**
 * Returns the root dir of the app, as specified in the init() call
 */
module.exports.getAppRootDir = function() {
    if (!_rootDir) throw new Err('core.init() has not been called');
    return _rootDir;
};

/**
 * Performs 'require()' in the context of the main app
 */
module.exports.resolveModule = function(moduleName) {
    if (!_npmResolver) throw new Err('core.init() has not been called');
    return _npmResolver(moduleName);
};

/**
 * Throw "standard" tile does not exist error.
 * The error message string is often used to check if tile existance, so it has to be exact
 */
module.exports.throwNoTile = function() {
    throw new Error('Tile does not exist');
};

/**
 * Checks if the error indicates the tile does not exist
 */
module.exports.isNoTileError = function(err) {
    return err.message === 'Tile does not exist';
};

/**
 * Parse and normalize URI, ensuring it returns an object with query object field
 * @param uri
 * @returns {*}
 */
module.exports.normalizeUri = function(uri) {
    if (typeof uri === 'string') {
        uri = urllib.parse(uri, true);
    } else if (typeof uri.query === 'string') {
        uri.query = qs.parse(uri.query);
    }
    uri.query = uri.query || {};
    return uri;
};

/**
 * Tests if x or y coordinate is valid for the given zoom
 */
module.exports.isValidCoordinate = function(val, zoom) {
    if (zoom === undefined) {
        return core.isInteger(val) && 0 <= val && val < module.exports.maxValidCoordinate;
    } else {
        return core.isInteger(val) && core.isValidZoom(zoom) && 0 <= val && val < Math.pow(2, zoom);
    }
};

/**
 * Tests if xy index is valid for the given zoom
 */
module.exports.isValidIndex = function(val, zoom) {
    if (zoom === undefined) {
        return core.isInteger(val) && 0 <= val && val < module.exports.maxValidIndex;
    } else {
        return core.isInteger(val) && core.isValidZoom(zoom) && 0 <= val && val < Math.pow(4, zoom);
    }
};

/**
 * Tests if zoom is valid. Zoom may not exceed 26 because the index coordinate we use
 * will exceed the largest JavaScript int of 2^53  (which is 4^26)
 */
module.exports.isValidZoom = function(val) {
    return core.isInteger(val) && 0 <= val && val <= module.exports.maxValidZoom;
};

/**
 * Convert x,y into a single integer with alternating bits
 * @param x
 * @param y
 * @param zoom optional zoom level to validate x,y coordinates
 */
module.exports.xyToIndex = function(x, y, zoom) {
    if (!module.exports.isValidCoordinate(x, zoom) || !module.exports.isValidCoordinate(y, zoom)) {
        throw new Err('Invalid coordinates %s, %s', x, y);
    }
    var mult = 1, result = 0;
    while (x || y) {
        result += (mult * (x % 2));
        x = Math.floor(x / 2);
        mult *= 2;
        result += (mult * (y % 2));
        y = Math.floor(y / 2);
        mult *= 2;
    }
    return result;
};

/**
 * Convert a single integer into the x,y coordinates
 * Given an integer, extract every odd/even bit into two integer values
 */
module.exports.indexToXY = function(index) {
    if (!module.exports.isValidIndex(index)) {
        throw new Err('Invalid index %j', index);
    }
    var x = 0, y = 0, mult = 1;
    while (index) {
        x += mult * (index % 2);
        index = Math.floor(index / 2);
        y += mult * (index % 2);
        index = Math.floor(index / 2);
        mult *= 2;
    }
    return [x, y];
};

module.exports.isInteger = function(value) {
    return typeof value === 'number' && value % 1 === 0;
};

/**
 * Converts value to integer if possible, or returns the original
 */
module.exports.strToInt = function(value) {
    if (typeof value === 'string') {
        var v = parseInt(value);
        if (v.toString() === value) {
            return v;
        }
    }
    return value;
};

/**
 * Converts value to float if possible, or returns the original
 */
module.exports.strToFloat = function(value) {
    if (typeof value === 'string') {
        var v = parseFloat(value);
        if (v.toString() === value) {
            return v;
        }
    }
    return value;
};

module.exports.uncompressAsync = function(data) {
    return BBPromise.try(function () {
        if (data && data.length) {
            if (data[0] == 0x1F && data[1] == 0x8B) {
                return zlib.gunzipAsync(data);
            } else if (data[0] == 0x78 && data[1] == 0x9C) {
                return zlib.inflateAsync(data);
            }
        }
        return data;
    });
};

/**
 * Extract portion of a higher zoom tile as a new tile
 * @param baseTileRawPbf uncompressed vector tile pbf
 * @param z desired zoom of the subtile
 * @param x subtile's x
 * @param y subtile's y
 * @param bz source tile's zoom
 * @param bx source tile's x
 * @param by source tile's y
 * @returns {string|*}
 */
module.exports.extractSubTileAsync = function(baseTileRawPbf, z, x, y, bz, bx, by) {
    return BBPromise
        .try(function () {
            if (bz >= z) {
                throw new Err('Base tile zoom is not less than z');
            }
            var baseTile = new mapnik.VectorTile(bz, bx, by);
            // TODO: setData has an async version - we might want to use it instead
            baseTile.setData(baseTileRawPbf);
            var subTile = new mapnik.VectorTile(+z, +x, +y);
            // TODO: should we do a ".return(subTile)" after compositeAsync()?
            return subTile.compositeAsync([baseTile]);
        }).then(function (vtile) {
            return vtile.getData();
        });
};

module.exports.compressPbfAsync2 = function(data, headers) {
    return zlib
        .gzipAsync(data)
        .then(function (pbfz) {
            headers['Content-Encoding'] = 'gzip';
            return [pbfz, headers];
        });
};

module.exports.getStaticOpts = function(conf) {
    var staticOpts = {};
    staticOpts.setHeaders = function (res) {
        if (conf.cache) {
            res.header('Cache-Control', conf.cache);
        }
        if (res.req.originalUrl.endsWith('.pbf')) {
            res.header('Content-Encoding', 'gzip');
        }
    };
    return staticOpts;
};

/**
 * Wrapper around the backwards-style getTile() call, where extra args are passed by attaching them to the callback
 */
module.exports.getTitleWithParamsAsync = function(source, z, x, y, opts) {
    return new BBPromise(function (resolve, reject) {
        try {
            var callback = function (err, data, headers) {
                if (err) {
                    reject(err);
                } else {
                    resolve([data, headers]);
                }
            };
            source.getTile(z, x, y, _.extend(callback, opts));
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Utility method to check the type of the object's property
 */
module.exports.checkType = function(obj, field, expType, mustHave, min, max) {
    var value = typeof(obj) === 'object' ? obj[field] : obj;
    if (value === undefined) {
        if (mustHave === true) {
            throw new Err('Value %s of type %s is missing', field, expType);
        }
        if (mustHave === false || mustHave === undefined) {
            delete obj[field];
        } else {
            obj[field] = mustHave;
        }
        return false;
    }
    // Try to convert value to expected type
    var type = expType[0] === '[' ? Object.prototype.toString.call(value) : typeof value;
    if (type === 'string') {
        switch (expType) {
            case 'number':
                value = core.strToFloat(value);
                type = typeof value;
                break;
            case 'integer':
            case 'zoom':
                obj[field] = value = core.strToInt(value);
                type = typeof value;
                break;
            case 'boolean':
                obj[field] = value = (value ? true : false);
                type = typeof value;
                break;
            case 'string-array':
                obj[field] = value = [value];
                type = typeof value;
                break;
            case 'number-array':
                value = core.strToFloat(value);
                type = typeof value;
                if (type === 'number') {
                    obj[field] = value = [value];
                }
                break;
        }
    } else if (type === 'number' && expType === 'number-array') {
        obj[field] = value = [value];
        type = typeof value;
    }
    // validate the type
    switch (expType) {
        case 'string-array':
            if (!Array.isArray(value) || !_.all(value, function (v) {
                    return typeof(v) === 'string';
                }))
                throw new Err('Invalid %s param: expecting a string or an array of strings', field);
            break;
        case 'number-array':
            var isValid = Array.isArray(value);
            if (isValid) {
                value = _.map(value, function(v) {
                    v = core.strToFloat(v);
                    if (typeof v !== 'number')
                        isValid = false;
                    return v;
                });
            }
            if (!isValid)
                throw new Err('Invalid %s param: expecting a number or an array of numbers', field);
            obj[field] = value;
            break;
        case 'integer':
            if (!core.isInteger(value))
                throw new Err('Invalid %s param type %s given, was expecting an integer', field, type);
            break;
        case 'zoom':
            if (!core.isValidZoom(value))
                throw new Err('Invalid %s param - an integer zoom value was expected', field);
            break;
        default:
            if (type !== expType)
                throw new Err('Invalid %s param type %s given, was expecting %s', field, type, expType);
            break;
    }
    // validate ranges
    switch (expType) {
        case 'number':
        case 'integer':
        case 'zoom':
            if (min !== undefined && value < min) {
                throw new Err('Invalid %s param - must be at least %d, but given %d', field, min, value);
            }
            if (max !== undefined && value > max) {
                throw new Err('Invalid %s param - must be at most %d, but given %d', field, max, value);
            }
            break;
        case 'string':
            if (min !== undefined && value.length < min) {
                throw new Err('Invalid %s param - the string must be at least %d symbols', field, min);
            }
            break;
        case 'boolean':
            if (value === false) {
                // convert false into undefined
                delete obj[field];
                return false;
            }
            break;
        case 'string-array':
        case 'number-array':
            if (min !== undefined && value.length < min) {
                throw new Err('Invalid %s param - it must have at least %d values, but given %d', field, min, value.length);
            }
            if (max !== undefined && value.length > max) {
                throw new Err('Invalid %s param - it must have at least %d values, but given %d', field, max, value.length);
            }
            break;
    }
    return true;
};

/**
 * given a list, async wait on each element before proceeding to the next
 */
module.exports.mapSequentialAsync = function(list, iterator) {
    return _.reduce(list, function (promise, value, key) {
        return promise.then(function () {
            return iterator(value, key);
        });
    }, BBPromise.resolve()).return(list);
};

module.exports.loadSource = function(sourceUri, tilelive) {
    return tilelive.loadAsync(sourceUri).then(function (handler) {
        return BBPromise.promisifyAll(handler);
    });
};

module.exports.safeLoadAndRegister = function(libs, tilelive) {
    if (!Array.isArray(libs)) {
        libs = [libs];
    }
    _.each(libs, function(libname) {
        var lib;
        try {
            lib = require(core.resolveModule(libname));
        } catch (err) {
            _log('info', util.format('Failed to load %s: %s ', libname, err.message));
            return; // Ignore loading error
        }
        lib.registerProtocols(tilelive);
        _log('info', 'Loaded ' + libname);
    });
};
<commit_msg>Added String.endsWith(), removed getStaticOpts()<commit_after>'use strict';

var util = require('util');
var qs = require('querystring');
var urllib = require('url');
var _ = require('underscore');
var BBPromise = require('bluebird');

var mapnik = require('mapnik');
BBPromise.promisifyAll(mapnik.Map.prototype);
BBPromise.promisifyAll(mapnik.VectorTile.prototype);

var zlib = require('zlib');
BBPromise.promisifyAll(zlib);

// Make sure there is String.endsWith()
if (!String.prototype.endsWith) {
    String.prototype.endsWith = function(searchString, position) {
        var subjectString = this.toString();
        if (position === undefined || position > subjectString.length) {
            position = subjectString.length;
        }
        position -= searchString.length;
        var lastIndex = subjectString.indexOf(searchString, position);
        return lastIndex !== -1 && lastIndex === position;
    };
}

module.exports = {
    maxValidZoom: 26,
    maxValidCoordinate: Math.pow(2, 26),
    maxValidIndex: Math.pow(4, 26)
};

var Err = require('./Err');
var core = module.exports;
var _log, _rootDir, _npmResolver;

/**
 * Initializes the core
 * @param logger logger object that implements log(group, message) function
 * @param rootDir Absolute path of the root directory of the main app
 * @param npmResolver function that performs 'require.resolve(moduleName)' in the context of the main app
 *
 * TODO: Any suggestions about how to get rid of this ugly hack are welcome
 *
 * For example, if your main code is in ./routes/nnn.js, you would use this snipet at the top:
 * var core = require('kartotherian-core');
 * core.init(app.logger, require('path').resolve(__dirname, '..'), function (module) { return require.resolve(module); });
 */
module.exports.init = function(logger, rootDir, npmResolver) {
    _log = logger.log.bind(logger);
    _rootDir = rootDir;
    _npmResolver = npmResolver;
};

/**
 * Log info
 */
module.exports.log = function(group, message) {
    if (!_log) {
        console.log.apply(null, arguments);
    } else {
        _log.apply(null, arguments);
    }
};

/**
 * Attempt to convert Error to anything printable (with stacktrace)
 */
module.exports.errToStr = function(err) {
    return (err.body && (err.body.stack || err.body.detail)) || err.stack || err;
};

/**
 * Performs 'require()' in the context of the main app
 */
module.exports.resolveModule = function(moduleName) {
    if (!_npmResolver) throw new Err('core.init() has not been called');
    return _npmResolver(moduleName);
};

/**
 * Returns the root dir of the app, as specified in the init() call
 */
module.exports.getAppRootDir = function() {
    if (!_rootDir) throw new Err('core.init() has not been called');
    return _rootDir;
};

/**
 * Performs 'require()' in the context of the main app
 */
module.exports.resolveModule = function(moduleName) {
    if (!_npmResolver) throw new Err('core.init() has not been called');
    return _npmResolver(moduleName);
};

/**
 * Throw "standard" tile does not exist error.
 * The error message string is often used to check if tile existance, so it has to be exact
 */
module.exports.throwNoTile = function() {
    throw new Error('Tile does not exist');
};

/**
 * Checks if the error indicates the tile does not exist
 */
module.exports.isNoTileError = function(err) {
    return err.message === 'Tile does not exist';
};

/**
 * Parse and normalize URI, ensuring it returns an object with query object field
 * @param uri
 * @returns {*}
 */
module.exports.normalizeUri = function(uri) {
    if (typeof uri === 'string') {
        uri = urllib.parse(uri, true);
    } else if (typeof uri.query === 'string') {
        uri.query = qs.parse(uri.query);
    }
    uri.query = uri.query || {};
    return uri;
};

/**
 * Tests if x or y coordinate is valid for the given zoom
 */
module.exports.isValidCoordinate = function(val, zoom) {
    if (zoom === undefined) {
        return core.isInteger(val) && 0 <= val && val < module.exports.maxValidCoordinate;
    } else {
        return core.isInteger(val) && core.isValidZoom(zoom) && 0 <= val && val < Math.pow(2, zoom);
    }
};

/**
 * Tests if xy index is valid for the given zoom
 */
module.exports.isValidIndex = function(val, zoom) {
    if (zoom === undefined) {
        return core.isInteger(val) && 0 <= val && val < module.exports.maxValidIndex;
    } else {
        return core.isInteger(val) && core.isValidZoom(zoom) && 0 <= val && val < Math.pow(4, zoom);
    }
};

/**
 * Tests if zoom is valid. Zoom may not exceed 26 because the index coordinate we use
 * will exceed the largest JavaScript int of 2^53  (which is 4^26)
 */
module.exports.isValidZoom = function(val) {
    return core.isInteger(val) && 0 <= val && val <= module.exports.maxValidZoom;
};

/**
 * Convert x,y into a single integer with alternating bits
 * @param x
 * @param y
 * @param zoom optional zoom level to validate x,y coordinates
 */
module.exports.xyToIndex = function(x, y, zoom) {
    if (!module.exports.isValidCoordinate(x, zoom) || !module.exports.isValidCoordinate(y, zoom)) {
        throw new Err('Invalid coordinates %s, %s', x, y);
    }
    var mult = 1, result = 0;
    while (x || y) {
        result += (mult * (x % 2));
        x = Math.floor(x / 2);
        mult *= 2;
        result += (mult * (y % 2));
        y = Math.floor(y / 2);
        mult *= 2;
    }
    return result;
};

/**
 * Convert a single integer into the x,y coordinates
 * Given an integer, extract every odd/even bit into two integer values
 */
module.exports.indexToXY = function(index) {
    if (!module.exports.isValidIndex(index)) {
        throw new Err('Invalid index %j', index);
    }
    var x = 0, y = 0, mult = 1;
    while (index) {
        x += mult * (index % 2);
        index = Math.floor(index / 2);
        y += mult * (index % 2);
        index = Math.floor(index / 2);
        mult *= 2;
    }
    return [x, y];
};

module.exports.isInteger = function(value) {
    return typeof value === 'number' && value % 1 === 0;
};

/**
 * Converts value to integer if possible, or returns the original
 */
module.exports.strToInt = function(value) {
    if (typeof value === 'string') {
        var v = parseInt(value);
        if (v.toString() === value) {
            return v;
        }
    }
    return value;
};

/**
 * Converts value to float if possible, or returns the original
 */
module.exports.strToFloat = function(value) {
    if (typeof value === 'string') {
        var v = parseFloat(value);
        if (v.toString() === value) {
            return v;
        }
    }
    return value;
};

module.exports.uncompressAsync = function(data) {
    return BBPromise.try(function () {
        if (data && data.length) {
            if (data[0] == 0x1F && data[1] == 0x8B) {
                return zlib.gunzipAsync(data);
            } else if (data[0] == 0x78 && data[1] == 0x9C) {
                return zlib.inflateAsync(data);
            }
        }
        return data;
    });
};

/**
 * Extract portion of a higher zoom tile as a new tile
 * @param baseTileRawPbf uncompressed vector tile pbf
 * @param z desired zoom of the subtile
 * @param x subtile's x
 * @param y subtile's y
 * @param bz source tile's zoom
 * @param bx source tile's x
 * @param by source tile's y
 * @returns {string|*}
 */
module.exports.extractSubTileAsync = function(baseTileRawPbf, z, x, y, bz, bx, by) {
    return BBPromise
        .try(function () {
            if (bz >= z) {
                throw new Err('Base tile zoom is not less than z');
            }
            var baseTile = new mapnik.VectorTile(bz, bx, by);
            // TODO: setData has an async version - we might want to use it instead
            baseTile.setData(baseTileRawPbf);
            var subTile = new mapnik.VectorTile(+z, +x, +y);
            // TODO: should we do a ".return(subTile)" after compositeAsync()?
            return subTile.compositeAsync([baseTile]);
        }).then(function (vtile) {
            return vtile.getData();
        });
};

module.exports.compressPbfAsync2 = function(data, headers) {
    return zlib
        .gzipAsync(data)
        .then(function (pbfz) {
            headers['Content-Encoding'] = 'gzip';
            return [pbfz, headers];
        });
};

/**
 * Wrapper around the backwards-style getTile() call, where extra args are passed by attaching them to the callback
 */
module.exports.getTitleWithParamsAsync = function(source, z, x, y, opts) {
    return new BBPromise(function (resolve, reject) {
        try {
            var callback = function (err, data, headers) {
                if (err) {
                    reject(err);
                } else {
                    resolve([data, headers]);
                }
            };
            source.getTile(z, x, y, _.extend(callback, opts));
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Utility method to check the type of the object's property
 */
module.exports.checkType = function(obj, field, expType, mustHave, min, max) {
    var value = typeof(obj) === 'object' ? obj[field] : obj;
    if (value === undefined) {
        if (mustHave === true) {
            throw new Err('Value %s of type %s is missing', field, expType);
        }
        if (mustHave === false || mustHave === undefined) {
            delete obj[field];
        } else {
            obj[field] = mustHave;
        }
        return false;
    }
    // Try to convert value to expected type
    var type = expType[0] === '[' ? Object.prototype.toString.call(value) : typeof value;
    if (type === 'string') {
        switch (expType) {
            case 'number':
                value = core.strToFloat(value);
                type = typeof value;
                break;
            case 'integer':
            case 'zoom':
                obj[field] = value = core.strToInt(value);
                type = typeof value;
                break;
            case 'boolean':
                obj[field] = value = (value ? true : false);
                type = typeof value;
                break;
            case 'string-array':
                obj[field] = value = [value];
                type = typeof value;
                break;
            case 'number-array':
                value = core.strToFloat(value);
                type = typeof value;
                if (type === 'number') {
                    obj[field] = value = [value];
                }
                break;
        }
    } else if (type === 'number' && expType === 'number-array') {
        obj[field] = value = [value];
        type = typeof value;
    }
    // validate the type
    switch (expType) {
        case 'string-array':
            if (!Array.isArray(value) || !_.all(value, function (v) {
                    return typeof(v) === 'string';
                }))
                throw new Err('Invalid %s param: expecting a string or an array of strings', field);
            break;
        case 'number-array':
            var isValid = Array.isArray(value);
            if (isValid) {
                value = _.map(value, function(v) {
                    v = core.strToFloat(v);
                    if (typeof v !== 'number')
                        isValid = false;
                    return v;
                });
            }
            if (!isValid)
                throw new Err('Invalid %s param: expecting a number or an array of numbers', field);
            obj[field] = value;
            break;
        case 'integer':
            if (!core.isInteger(value))
                throw new Err('Invalid %s param type %s given, was expecting an integer', field, type);
            break;
        case 'zoom':
            if (!core.isValidZoom(value))
                throw new Err('Invalid %s param - an integer zoom value was expected', field);
            break;
        default:
            if (type !== expType)
                throw new Err('Invalid %s param type %s given, was expecting %s', field, type, expType);
            break;
    }
    // validate ranges
    switch (expType) {
        case 'number':
        case 'integer':
        case 'zoom':
            if (min !== undefined && value < min) {
                throw new Err('Invalid %s param - must be at least %d, but given %d', field, min, value);
            }
            if (max !== undefined && value > max) {
                throw new Err('Invalid %s param - must be at most %d, but given %d', field, max, value);
            }
            break;
        case 'string':
            if (min !== undefined && value.length < min) {
                throw new Err('Invalid %s param - the string must be at least %d symbols', field, min);
            }
            break;
        case 'boolean':
            if (value === false) {
                // convert false into undefined
                delete obj[field];
                return false;
            }
            break;
        case 'string-array':
        case 'number-array':
            if (min !== undefined && value.length < min) {
                throw new Err('Invalid %s param - it must have at least %d values, but given %d', field, min, value.length);
            }
            if (max !== undefined && value.length > max) {
                throw new Err('Invalid %s param - it must have at least %d values, but given %d', field, max, value.length);
            }
            break;
    }
    return true;
};

/**
 * given a list, async wait on each element before proceeding to the next
 */
module.exports.mapSequentialAsync = function(list, iterator) {
    return _.reduce(list, function (promise, value, key) {
        return promise.then(function () {
            return iterator(value, key);
        });
    }, BBPromise.resolve()).return(list);
};

module.exports.loadSource = function(sourceUri, tilelive) {
    return tilelive.loadAsync(sourceUri).then(function (handler) {
        return BBPromise.promisifyAll(handler);
    });
};

module.exports.safeLoadAndRegister = function(libs, tilelive) {
    if (!Array.isArray(libs)) {
        libs = [libs];
    }
    _.each(libs, function(libname) {
        var lib;
        try {
            lib = require(core.resolveModule(libname));
        } catch (err) {
            _log('info', util.format('Failed to load %s: %s ', libname, err.message));
            return; // Ignore loading error
        }
        lib.registerProtocols(tilelive);
        _log('info', 'Loaded ' + libname);
    });
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {Grid, Row, Col, Button} from 'react-bootstrap';
import './Calculator.css';

class Calculator extends Component {
  constructor() {
    super();
    this.state = {
      value: 0
    };
  }
  handleClickButton(buttonValue) {
    if (typeof buttonValue === 'number') {
      this.setState({
        value: (this.state.value === 0)? buttonValue: this.state.value * 10 + buttonValue
      });
      return ;
    }

    switch(buttonValue) {
      case 'C': this.setState({value: 0});
        break;
    }
  }
  render() {
    return (

 {this.state.value}

        <Grid className='calculator__buttons'>
          <Row>
            <Col xs={6} className='calculator__button'><Button onClick={() => this.handleClickButton('C')}>CLR</Button></Col>
            <Col xs={6} className='calculator__button'><Button onClick={() => this.handleClickButton('C')}>√</Button></Col>
          </Row>
          <Row>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(7)}>7</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(8)}>8</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(9)}>9</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('+')}>+</Button></Col>
          </Row>
          <Row>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(4)}>4</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(5)}>5</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(6)}>6</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('-')}>-</Button></Col>
          </Row>
          <Row>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(1)}>1</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(2)}>2</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(3)}>3</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('*')}>*</Button></Col>
          </Row>
          <Row>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(0)}>0</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('.')}>.</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('/')}>/</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('=')}>=</Button></Col>
          </Row>
        </Grid>

    );
  }
}

export default Calculator;
<commit_msg>Added calculator functionality for the operators<commit_after>import React, { Component } from 'react';
import {Grid, Row, Col, Button} from 'react-bootstrap';
import './Calculator.css';

class Calculator extends Component {
  constructor() {
    super();
    this.state = {
      prevValue: 0,
      curValue: 0,
      answer: 0,
      computation: '',
      operator: ''
    };
  }

  evaluate(a, b, operator) {
    switch (operator) {
      case '+': return a + b;
      case '-': return a - b;
      case '*': return a * b;
      case '/': return a / b;
    }
  }

  handleClickButton(buttonValue) {
    let state = Object.assign({}, this.state);
    let operators = ['+', '-', '*', '/'];

    if (operators.indexOf(buttonValue) >= 0) {
      // if last character is operator, return
      if (operators.indexOf(state.computation.slice(-1)) >= 0) return;

      state.prevValue = state.answer;
      state.curValue = 0;
      state.answer = 0;
      state.operator = buttonValue;
    }

    // change computation
    switch(buttonValue) {
      case 'squareRoot':
        state.computation = `√(${this.state.computation})`;
        break;
      case 'clear':
        state.computation = '';
        break;
      default:
        state.computation += buttonValue;
    }

    if (typeof buttonValue === 'number') {
      if (state.operator) {
        state.curValue = (state.curValue === 0)? buttonValue: state.curValue * 10 + buttonValue;
        state.answer = +(this.evaluate(state.prevValue, state.curValue, state.operator).toFixed(2));
      }
      else {
        state.answer = (state.answer === 0)? buttonValue: state.answer * 10 + buttonValue;
      }
    }

    switch(buttonValue) {
      case 'clear':
        state.answer = 0;
        state.operator = '';
        break;
      case 'squareRoot':
        state.answer = +(Math.sqrt(state.answer).toFixed(2));
        break;
      case '=':
        state.computation = state.answer.toString();
        state.operator = '';
        break;
    }

    this.setState(state);
  }

  render() {
    return (

            {this.state.answer}

            {this.state.computation}

        <Grid className='calculator__buttons'>
          <Row>
            <Col xs={6} className='calculator__button'><Button onClick={() => this.handleClickButton('clear')}>CLR</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('squareRoot')}>√</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('+')}>+</Button></Col>
          </Row>
          <Row>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(7)}>7</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(8)}>8</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(9)}>9</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('-')}>-</Button></Col>
          </Row>
          <Row>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(4)}>4</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(5)}>5</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(6)}>6</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('*')}>*</Button></Col>
          </Row>
          <Row>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(1)}>1</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(2)}>2</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(3)}>3</Button></Col>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton('/')}>/</Button></Col>
          </Row>
          <Row>
            <Col xs={3} className='calculator__button'><Button onClick={() => this.handleClickButton(0)}>0</Button></Col>
            <Col xs={9} className='calculator__button'><Button onClick={() => this.handleClickButton('=')}>=</Button></Col>
          </Row>
        </Grid>

    );
  }
}

export default Calculator;
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2012 Andreas Madsen
 * MIT License
 */

var parseDocument = require('./parse.js');
var Search; // will be lazy-loaded by Node.find

function Node(document, elem) {
  this.document = document;
  this.elem = elem;

  this.isChunked = false;
  this.isContainer = false;

  // allow node object to be reused
  document.elemCache.push(elem);
  document.nodeCache.push(this);
}

module.exports = Node;

// this function will check the cache and
// return a new Node object if it don't exist
// in cache, or return the cached Node object.
Node.create = function (document, elem) {
  // check cache
  var index = document.elemCache.indexOf(elem);

  // not cached, create new
  if (index === -1) {
    return new Node(document, elem);
  }

  // return cache
  return document.nodeCache[index];
};

Node.prototype.tagName = function () {
  var elem = this.elem;
  if (elem.isRoot) throw new Error('root has no tagname');

  return elem.tagname;
};

Node.prototype.isSingleton = function () {
  return !!this.elem.singleton;
};

Node.prototype.isRoot = function () {
  return !!this.elem.isRoot;
};

Node.prototype.getParent = function () {
  var elem = this.elem;
  if (elem.isRoot) throw new Error('root has no parent');

  return Node.create(this.document, elem.parent);
};

Node.prototype.getChildren = function () {
  var elem = this.elem;
  if (elem.singleton) throw new Error('singleton element has no children');

  var doc = this.document;
  return elem.childrens.map(function (child) {
    return Node.create(doc, child);
  });
};

Node.prototype.isParentTo = function (node) {
  var parent = node.elem.parent;

  return !!parent && this.elem === parent;
};

Node.prototype.done = function () {
  if (!this.isContainer) return this;

  var elem = this.elem;
  if (elem.modify === false) return this;

  // set modify of flag
  elem.modify = false;
  this._childModify(false);

  // send next content chunk
  this.document._send(this);

  return this;
};

Node.prototype._prepearModify = function (beforeAppend) {
  if (this.elem.modify === false && this.document.useStream === true) {
    throw new Error('container can only be modified while online');
  }

  if (beforeAppend === true && this.isChunked) {
    throw new Error('can not set attribute after .append or .done');
  }
};

Node.prototype._childModify = function (bool) {
  if (this.isChunked) return;

  setChildModify(this.elem, bool);
};

function setChildModify(elem, bool) {
  if (elem.singleton) return;

  var childs = elem.childrens,
      i = childs.length, child;

  while(i--) {
    child = childs[i];
    child.modify = bool;
    setChildModify(child, bool);
  }
}

Node.prototype.insert = function (where, content) {
  this._prepearModify(true);

  if (insertAdjacentMethods.hasOwnProperty(where) === false) {
    throw new Error('did not understand first argument');
  }

  insertAdjacent(this, where, content);

  return this;
};

Node.prototype.append = function (content) {
  this._prepearModify(false);

  var elem = this.elem;
  if (elem.singleton) throw new Error('can not append to singleton element');

  // append content
  insertAdjacent(this, 'beforeend', content);

  // just append content if this is an subcontainer
  if (!this.isContainer) return this;

  // set modify of flag
  this._childModify(false);

  // send next content chunk
  this.document._send(this);

  return this;
};

Node.prototype.trim = function () {
  this._prepearModify(true);

  var elem = this.elem;
  if (elem.singleton) throw new Error('can not remove content from singleton element');

  // get positions and size
  var before = elem.pos.beforebegin + elem.pos.afterbegin + 1,
      after = elem.pos.beforeend,
      move = before - after; // should be negative or zero

  // remove any node children
  elem.childrens = [];

  // remove content from document
  removeContent(this, before, after);

  // update all other tags (both start and end) there are to follow
  moveTagPointers(elem, move);

  return this;
};

Node.prototype.getContent = function () {
  var elem = this.elem;
  if (elem.singleton) throw new Error('can not get content from singleton element');

  var pos = elem.pos,
      before = pos.beforebegin + pos.afterbegin + 1,
      after = pos.beforeend;
  return this.document.content.slice(before, after);
};

Node.prototype.setContent = function (content) {
  this._prepearModify(true);

  var elem = this.elem;
  if (elem.singleton) throw new Error('can not set content to singleton element');

  // get postions and sizes
  var before = elem.pos.beforebegin + elem.pos.afterbegin + 1,
      after = elem.pos.beforeend,
      length = content.length,
      move = before - after + length; // should be negative

  // remove any node children
  elem.childrens = [];

  // remove content from document
  replaceContent(this, before, after, content);

  // update all other tags (both start and end) there are to follow
  moveTagPointers(elem, move);

  // insert elements intro the document tree
  if (this.document.liveParsing === true) {
    insertElements(elem, 0, before, content);
  }

  return this;
};

Node.prototype.getAttr = function (name) {
  if (this.elem.keys.indexOf(name) === -1) {
    return null;
  }

  return this.elem.attr[name].value || '';
};

Node.prototype.hasAttr = function (name) {
  return this.elem.keys.indexOf(name) !== -1;
};

Node.prototype.setAttr = function (name, value) {
  this._prepearModify(true);

  var elem = this.elem;
  if (elem.isRoot) throw new Error('can not set attribute on root element');

  var keys = elem.keys,
      attr, before, after, start, move;

  var content = name + '="' + value + '"',
      length = content.length;

  // attribute do not exist: do nothing
  if (this.hasAttr(name)) {
    attr = elem.attr[name];

    // get postions and sizes
    before = elem.pos.beforebegin + attr.start;
    after = before + attr.end + 1;
    move = -attr.end - 1 + length;

    // remove element from keys array and attr
    var index = keys.indexOf(name);

    // replace content from document
    replaceContent(this, before, after, content);

    // move following attibutes
    attr.value = value;

    if (move !== 0) {
      attr.end = length - 1;
      moveAttibutePointers(elem, index + 1, move);

      // update all other tags (both start and end) there are to follow
      elem.pos.afterbegin += move;
      moveTagPointers(elem, move);
    }

    return this;
  }

  // get last attribute
  attr = elem.attr[keys[keys.length - 1]];

  start = attr.start + attr.end;
  after = before = elem.pos.beforebegin + start + 1;
  move = length + 1;

  // create attribute
  keys.push(name);
  attr = elem.attr[name] = {
    start: start + 2,
    name: name,
    end: length - 1,
    value: value
  };

  // replace content from document
  replaceContent(this, before, after, " " + content);

  // update all other tags (both start and end) there are to follow
  elem.pos.afterbegin += move;
  moveTagPointers(elem, move);

  return this;
};

Node.prototype.removeAttr = function (name) {
  this._prepearModify(true);

  var elem = this.elem;
  if (elem.isRoot) throw new Error('can not remove attribute from root element');

  // attribute do not exist: do nothing
  if (this.hasAttr(name) === false) {
    return this;
  }

  var keys = elem.keys,
      attr = elem.attr[name];

  // get postions and sizes
  var before = elem.pos.beforebegin + attr.start,
      after = before + attr.end,
      move = -attr.end - 1; // should be negative

  // remove element from keys array and attr
  var index = keys.indexOf(name);
  keys.splice(index, 1);
  delete elem.attr[name];

  // remove content from document
  removeContent(this, before, after + 1);

  // move following attibutes
  moveAttibutePointers(elem, index, move);

  // update all other tags (both start and end) there are to follow
  elem.pos.afterbegin += move;
  moveTagPointers(elem, move);

  return this;
};

var Search;
Node.prototype.find = function () {
  // To prevent require loops search needs to be lazy loaded,
  // but since it is already in cache that shouldn't be a problem
  if (!Search) Search = require('./search.js');

  return new Search(this.document, this.elem);
};

function insertAdjacent(node, where, content) {
  var elem = node.elem;

  // skip if content is empty
  var move = content.length;
  if (move === 0) return;

  // insert content and move the parts all parts except
  // "moveParentSiblings" since that will always be needed
  insertAdjacentMethods[where](node, elem, content, move);
}

var insertAdjacentMethods = {
  'beforebegin': function (node, elem, content, move) {
    if (elem.isRoot) throw new Error('can not insert content at beforebegin on root element');

    // get positions and size
    var insert = elem.pos.beforebegin;

    // remove content from document
    replaceContent(node, insert, insert, content);

    // update all other tags (both start and end) there are to follow
    // move the end tag
    elem.pos.beforebegin += move;
    elem.pos.beforeend += move;
    moveChildPointers(elem, move);

    // move all next siblings to this element
    moveParentSiblings(elem, move);

    // insert elements intro the document tree
    if (node.document.liveParsing === true) {
      var parent = elem.parent;
      insertElements(parent, parent.childrens.indexOf(elem), insert, content);
    }
  },

  'afterbegin': function (node, elem, content, move) {
    if (elem.singleton) throw new Error('can not insert content intro singleton element');

    // get positions and size
    var insert = elem.pos.beforebegin + elem.pos.afterbegin + 1;

    // remove content from document
    replaceContent(node, insert, insert, content);

    // update all other tags (both start and end) there are to follow
    // move the end tag
    elem.pos.beforeend += move;
    moveChildPointers(elem, move);

    // move all next siblings to this element
    moveParentSiblings(elem, move);

    // insert elements intro the document tree
    if (node.document.liveParsing === true) {
      insertElements(elem, 0, insert, content);
    }
  },

  'beforeend': function (node, elem, content, move) {
    if (elem.singleton) throw new Error('can not insert content intro singleton element');

    // get positions and size
    var insert = elem.pos.beforeend;

    // remove content from document
    replaceContent(node, insert, insert, content);

    // Update the end tag
    elem.pos.beforeend += move;

    // move all next siblings to this element
    moveParentSiblings(elem, move);

    // insert elements intro the document tree
    if (node.document.liveParsing === true) {
      insertElements(elem, elem.childrens.length, insert, content);
    }
  },

  'afterend': function (node, elem, content, move) {
    if (elem.isRoot) throw new Error('can not insert content at beforebegin on root element');

    // get positions and size
    var insert = elem.pos.beforeend + elem.pos.afterend + 1;

    // remove content from document
    replaceContent(node, insert, insert, content);

    // move all next siblings to this element
    moveParentSiblings(elem, move);

    // insert elements intro the document tree
    if (node.document.liveParsing === true) {
      var parent = elem.parent;
      insertElements(parent, parent.childrens.indexOf(elem) + 1, insert, content);
    }
  }
};

function removeContent(node, from, to) {
  var doc = node.document;
  var text = doc.content;

  doc.content = text.slice(0, from) + text.slice(to);
}

function replaceContent(node, from, to, content) {
  var doc = node.document;
  var text = doc.content;
  doc.content = text.slice(0, from) + content + text.slice(to);
}

function insertElements(parent, index, offset, content) {
  // create subdocument
  var parsed = parseDocument(content);
  moveChildPointers(parsed, offset);

  // insert intro master tree
  var childrens = parent.childrens;
  Array.prototype.splice.apply(childrens, [index, 0].concat(parsed.childrens));

  // reset parent pointer
  var i = childrens.length;
  while(i--) {
    childrens[i].parent = parent;
  }
}

function moveAttibutePointers(elem, index, move) {
  var attr = elem.attr,
      nested = elem.keys.slice(index),
      i = nested.length;

  while (i--) {
    attr[nested[i]].start += move;
  }
}

function moveTagPointers(elem, move) {
  // optimise for equal pointer
  if (move === 0) return;

  if (!elem.singleton) {
    // move the end tag
    elem.pos.beforeend += move;

    // move childrens positions
    moveChildPointers(elem, move);
  }

  // move all next siblings to this element
  moveParentSiblings(elem, move);
}

function moveChildPointers(elem, move) {
  elem.childrens.forEach(function (child) {
    child.pos.beforebegin += move;

    // deep move childrens
    if (!child.singleton) {
      child.pos.beforeend += move;

      moveChildPointers(child, move);
    }
  });
}

function moveParentSiblings(elem, move) {
  if (elem.parent === undefined) return;

  var parent = elem.parent;
  var siblings = parent.childrens;

  // move end tag of this parent
  parent.pos.beforeend += move;

  // find and move all next siblings
  var nested = siblings.slice(siblings.indexOf(elem) + 1);
  nested.forEach(function (sibling) {
    sibling.pos.beforebegin += move;

    // deep move childrens
    if (!sibling.singleton) {
      sibling.pos.beforeend += move;

      moveChildPointers(sibling, move);
    }
  });

  // move next parent
  moveParentSiblings(parent, move);
}
<commit_msg>[feature] add support for node.remove()<commit_after>/**
 * Copyright (c) 2012 Andreas Madsen
 * MIT License
 */

var parseDocument = require('./parse.js');
var Search; // will be lazy-loaded by Node.find

function Node(document, elem) {
  this.document = document;
  this.elem = elem;

  this.isChunked = false;
  this.isContainer = false;

  // allow node object to be reused
  document.elemCache.push(elem);
  document.nodeCache.push(this);
}

module.exports = Node;

// this function will check the cache and
// return a new Node object if it don't exist
// in cache, or return the cached Node object.
Node.create = function (document, elem) {
  // check cache
  var index = document.elemCache.indexOf(elem);

  // not cached, create new
  if (index === -1) {
    return new Node(document, elem);
  }

  // return cache
  return document.nodeCache[index];
};

Node.prototype.tagName = function () {
  var elem = this.elem;
  if (elem.isRoot) throw new Error('root has no tagname');

  return elem.tagname;
};

Node.prototype.isSingleton = function () {
  return !!this.elem.singleton;
};

Node.prototype.isRoot = function () {
  return !!this.elem.isRoot;
};

Node.prototype.getParent = function () {
  var elem = this.elem;
  if (elem.isRoot) throw new Error('root has no parent');

  return Node.create(this.document, elem.parent);
};

Node.prototype.getChildren = function () {
  var elem = this.elem;
  if (elem.singleton) throw new Error('singleton element has no children');

  var doc = this.document;
  return elem.childrens.map(function (child) {
    return Node.create(doc, child);
  });
};

Node.prototype.isParentTo = function (node) {
  var parent = node.elem.parent;

  return !!parent && this.elem === parent;
};

Node.prototype.done = function () {
  if (!this.isContainer) return this;

  var elem = this.elem;
  if (elem.modify === false) return this;

  // set modify of flag
  elem.modify = false;
  this._childModify(false);

  // send next content chunk
  this.document._send(this);

  return this;
};

Node.prototype._prepearModify = function (allowChunk) {
  if (this.elem.modify === false && this.document.useStream === true) {
    throw new Error('container can only be modified while online');
  }

  if (allowChunk === false && this.isChunked) {
    throw new Error('can not set attribute after .append or .done');
  }
};

Node.prototype._childModify = function (bool) {
  if (this.isChunked) return;

  setChildModify(this.elem, bool);
};

function setChildModify(elem, bool) {
  if (elem.singleton) return;

  var childs = elem.childrens,
      i = childs.length, child;

  while(i--) {
    child = childs[i];
    child.modify = bool;
    setChildModify(child, bool);
  }
}

Node.prototype.insert = function (where, content) {
  this._prepearModify(false);

  if (insertAdjacentMethods.hasOwnProperty(where) === false) {
    throw new Error('did not understand first argument');
  }

  insertAdjacent(this, where, content);

  return this;
};

Node.prototype.append = function (content) {
  this._prepearModify(true);

  var elem = this.elem;
  if (elem.singleton) throw new Error('can not append to singleton element');

  // append content
  insertAdjacent(this, 'beforeend', content);

  // just append content if this is an subcontainer
  if (!this.isContainer) return this;

  // set modify of flag
  this._childModify(false);

  // send next content chunk
  this.document._send(this);

  return this;
};

Node.prototype.remove = function () {
  this._prepearModify(false);

  var elem = this.elem;
  var before = elem.pos.beforebegin,
      after = elem.pos.beforeend + elem.pos.afterend + 1,
      move = before - after;

  // remove content from document
  removeContent(this, before, after);

  // update all other tags (both start and end) there are to follow
  moveParentSiblings(elem, move);

  // remove this node from parent
  var childrens = elem.parent.childrens;
  childrens.splice(childrens.indexOf(elem), 1);

  return this;
};

Node.prototype.trim = function () {
  this._prepearModify(false);

  var elem = this.elem;
  if (elem.singleton) throw new Error('can not remove content from singleton element');

  // get positions and size
  var before = elem.pos.beforebegin + elem.pos.afterbegin + 1,
      after = elem.pos.beforeend,
      move = before - after; // should be negative or zero

  // remove any node children
  elem.childrens = [];

  // remove content from document
  removeContent(this, before, after);

  // update all other tags (both start and end) there are to follow
  moveTagPointers(elem, move);

  return this;
};

Node.prototype.getContent = function () {
  var elem = this.elem;
  if (elem.singleton) throw new Error('can not get content from singleton element');

  var pos = elem.pos,
      before = pos.beforebegin + pos.afterbegin + 1,
      after = pos.beforeend;
  return this.document.content.slice(before, after);
};

Node.prototype.setContent = function (content) {
  this._prepearModify(false);

  var elem = this.elem;
  if (elem.singleton) throw new Error('can not set content to singleton element');

  // get postions and sizes
  var before = elem.pos.beforebegin + elem.pos.afterbegin + 1,
      after = elem.pos.beforeend,
      length = content.length,
      move = before - after + length; // should be negative

  // remove any node children
  elem.childrens = [];

  // remove content from document
  replaceContent(this, before, after, content);

  // update all other tags (both start and end) there are to follow
  moveTagPointers(elem, move);

  // insert elements intro the document tree
  if (this.document.liveParsing === true) {
    insertElements(elem, 0, before, content);
  }

  return this;
};

Node.prototype.getAttr = function (name) {
  if (this.elem.keys.indexOf(name) === -1) {
    return null;
  }

  return this.elem.attr[name].value || '';
};

Node.prototype.hasAttr = function (name) {
  return this.elem.keys.indexOf(name) !== -1;
};

Node.prototype.setAttr = function (name, value) {
  this._prepearModify(false);

  var elem = this.elem;
  if (elem.isRoot) throw new Error('can not set attribute on root element');

  var keys = elem.keys,
      attr, before, after, start, move;

  var content = name + '="' + value + '"',
      length = content.length;

  // attribute do not exist: do nothing
  if (this.hasAttr(name)) {
    attr = elem.attr[name];

    // get postions and sizes
    before = elem.pos.beforebegin + attr.start;
    after = before + attr.end + 1;
    move = -attr.end - 1 + length;

    // remove element from keys array and attr
    var index = keys.indexOf(name);

    // replace content from document
    replaceContent(this, before, after, content);

    // move following attibutes
    attr.value = value;

    if (move !== 0) {
      attr.end = length - 1;
      moveAttibutePointers(elem, index + 1, move);

      // update all other tags (both start and end) there are to follow
      elem.pos.afterbegin += move;
      moveTagPointers(elem, move);
    }

    return this;
  }

  // get last attribute
  attr = elem.attr[keys[keys.length - 1]];

  start = attr.start + attr.end;
  after = before = elem.pos.beforebegin + start + 1;
  move = length + 1;

  // create attribute
  keys.push(name);
  attr = elem.attr[name] = {
    start: start + 2,
    name: name,
    end: length - 1,
    value: value
  };

  // replace content from document
  replaceContent(this, before, after, " " + content);

  // update all other tags (both start and end) there are to follow
  elem.pos.afterbegin += move;
  moveTagPointers(elem, move);

  return this;
};

Node.prototype.removeAttr = function (name) {
  this._prepearModify(false);

  var elem = this.elem;
  if (elem.isRoot) throw new Error('can not remove attribute from root element');

  // attribute do not exist: do nothing
  if (this.hasAttr(name) === false) {
    return this;
  }

  var keys = elem.keys,
      attr = elem.attr[name];

  // get postions and sizes
  var before = elem.pos.beforebegin + attr.start,
      after = before + attr.end,
      move = -attr.end - 1; // should be negative

  // remove element from keys array and attr
  var index = keys.indexOf(name);
  keys.splice(index, 1);
  delete elem.attr[name];

  // remove content from document
  removeContent(this, before, after + 1);

  // move following attibutes
  moveAttibutePointers(elem, index, move);

  // update all other tags (both start and end) there are to follow
  elem.pos.afterbegin += move;
  moveTagPointers(elem, move);

  return this;
};

var Search;
Node.prototype.find = function () {
  // To prevent require loops search needs to be lazy loaded,
  // but since it is already in cache that shouldn't be a problem
  if (!Search) Search = require('./search.js');

  return new Search(this.document, this.elem);
};

function insertAdjacent(node, where, content) {
  var elem = node.elem;

  // skip if content is empty
  var move = content.length;
  if (move === 0) return;

  // insert content and move the parts all parts except
  // "moveParentSiblings" since that will always be needed
  insertAdjacentMethods[where](node, elem, content, move);
}

var insertAdjacentMethods = {
  'beforebegin': function (node, elem, content, move) {
    if (elem.isRoot) throw new Error('can not insert content at beforebegin on root element');

    // get positions and size
    var insert = elem.pos.beforebegin;

    // remove content from document
    replaceContent(node, insert, insert, content);

    // update all other tags (both start and end) there are to follow
    // move the end tag
    elem.pos.beforebegin += move;
    elem.pos.beforeend += move;
    moveChildPointers(elem, move);

    // move all next siblings to this element
    moveParentSiblings(elem, move);

    // insert elements intro the document tree
    if (node.document.liveParsing === true) {
      var parent = elem.parent;
      insertElements(parent, parent.childrens.indexOf(elem), insert, content);
    }
  },

  'afterbegin': function (node, elem, content, move) {
    if (elem.singleton) throw new Error('can not insert content intro singleton element');

    // get positions and size
    var insert = elem.pos.beforebegin + elem.pos.afterbegin + 1;

    // remove content from document
    replaceContent(node, insert, insert, content);

    // update all other tags (both start and end) there are to follow
    // move the end tag
    elem.pos.beforeend += move;
    moveChildPointers(elem, move);

    // move all next siblings to this element
    moveParentSiblings(elem, move);

    // insert elements intro the document tree
    if (node.document.liveParsing === true) {
      insertElements(elem, 0, insert, content);
    }
  },

  'beforeend': function (node, elem, content, move) {
    if (elem.singleton) throw new Error('can not insert content intro singleton element');

    // get positions and size
    var insert = elem.pos.beforeend;

    // remove content from document
    replaceContent(node, insert, insert, content);

    // Update the end tag
    elem.pos.beforeend += move;

    // move all next siblings to this element
    moveParentSiblings(elem, move);

    // insert elements intro the document tree
    if (node.document.liveParsing === true) {
      insertElements(elem, elem.childrens.length, insert, content);
    }
  },

  'afterend': function (node, elem, content, move) {
    if (elem.isRoot) throw new Error('can not insert content at beforebegin on root element');

    // get positions and size
    var insert = elem.pos.beforeend + elem.pos.afterend + 1;

    // remove content from document
    replaceContent(node, insert, insert, content);

    // move all next siblings to this element
    moveParentSiblings(elem, move);

    // insert elements intro the document tree
    if (node.document.liveParsing === true) {
      var parent = elem.parent;
      insertElements(parent, parent.childrens.indexOf(elem) + 1, insert, content);
    }
  }
};

function removeContent(node, from, to) {
  var doc = node.document;
  var text = doc.content;

  doc.content = text.slice(0, from) + text.slice(to);
}

function replaceContent(node, from, to, content) {
  var doc = node.document;
  var text = doc.content;
  doc.content = text.slice(0, from) + content + text.slice(to);
}

function insertElements(parent, index, offset, content) {
  // create subdocument
  var parsed = parseDocument(content);
  moveChildPointers(parsed, offset);

  // insert intro master tree
  var childrens = parent.childrens;
  Array.prototype.splice.apply(childrens, [index, 0].concat(parsed.childrens));

  // reset parent pointer
  var i = childrens.length;
  while(i--) {
    childrens[i].parent = parent;
  }
}

function moveAttibutePointers(elem, index, move) {
  var attr = elem.attr,
      nested = elem.keys.slice(index),
      i = nested.length;

  while (i--) {
    attr[nested[i]].start += move;
  }
}

function moveTagPointers(elem, move) {
  // optimise for equal pointer
  if (move === 0) return;

  if (!elem.singleton) {
    // move the end tag
    elem.pos.beforeend += move;

    // move childrens positions
    moveChildPointers(elem, move);
  }

  // move all next siblings to this element
  moveParentSiblings(elem, move);
}

function moveChildPointers(elem, move) {
  elem.childrens.forEach(function (child) {
    child.pos.beforebegin += move;

    // deep move childrens
    if (!child.singleton) {
      child.pos.beforeend += move;

      moveChildPointers(child, move);
    }
  });
}

function moveParentSiblings(elem, move) {
  if (elem.parent === undefined) return;

  var parent = elem.parent;
  var siblings = parent.childrens;

  // move end tag of this parent
  parent.pos.beforeend += move;

  // find and move all next siblings
  var nested = siblings.slice(siblings.indexOf(elem) + 1);
  nested.forEach(function (sibling) {
    sibling.pos.beforebegin += move;

    // deep move childrens
    if (!sibling.singleton) {
      sibling.pos.beforeend += move;

      moveChildPointers(sibling, move);
    }
  });

  // move next parent
  moveParentSiblings(parent, move);
}
<|endoftext|>