<commit_before>var intelManager = require('manager.intel');

/**
 * Calculates a central room position with some free space around it for placing a storage later.
 * If a storage already exists, its position is returned.
 */
Room.prototype.getStorageLocation = function () {
    var room = this;

    if (!this.controller) {
        return;
    }

    if (!room.memory.storage) {
        if (room.storage) {
            room.memory.storage = {
                x: room.storage.pos.x,
                y: room.storage.pos.y
            };
        }
        else {
            var sites = room.find(FIND_MY_CONSTRUCTION_SITES, {
                filter: (site) => site.structureType == STRUCTURE_STORAGE
            });
            if (sites && sites.length > 0) {
                room.memory.storage = {
                    x: sites[0].pos.x,
                    y: sites[0].pos.y
                };
            }
            else {
                // Determine decent storage spot by averaging source and spawner locations.
                var count = 1;
                var x = room.controller.pos.x;
                var y = room.controller.pos.y;

                for (var i in room.sources) {
                    x += room.sources[i].pos.x;
                    y += room.sources[i].pos.y;
                    count++;
                }
                var spawns = room.find(FIND_STRUCTURES, {
                    filter: (structure) => structure.structureType == STRUCTURE_SPAWN
                });
                for (var i in spawns) {
                    x += spawns[i].pos.x;
                    y += spawns[i].pos.y;
                    count++;
                }

                x = Math.round(x / count);
                y = Math.round(y / count);

                // Now that we have a base position, try to find the
                // closest spot that is surrounded by empty tiles.
                var dist = 0;
                var found = false;
                while (!found && dist < 10) {
                    for (var tx = x - dist; tx <= x + dist; tx++) {
                        for (var ty = y - dist; ty <= y + dist; ty++) {
                            if (found) {
                                continue;
                            }

                            if (tx == x - dist || tx == x + dist || ty == y - dist || ty == y + dist) {
                                // Tile is only valid if it and all surrounding tiles are empty.
                                var contents = room.lookAtArea(ty - 1, tx - 1, ty + 1, tx + 1, true);
                                var clean = true;
                                for (var i in contents) {
                                    var tile = contents[i];
                                    if (tile.type == 'terrain' && tile.terrain != 'plain' && tile.terrain != 'swamp') {
                                        clean = false;
                                        break;
                                    }
                                    if (tile.type == 'structure' || tile.type == 'constructionSite') {
                                        clean = false;
                                        break;
                                    }
                                }

                                if (clean) {
                                    found = true;
                                    room.memory.storage = {
                                        x: tx,
                                        y: ty
                                    };
                                }
                            }
                        }
                    }

                    // @todo Limit dist and find "worse" free spot otherwise.
                    dist++;
                }
            }
        }
    }

    return room.memory.storage;
};

/**
 * Gathers information about a rooms sources and saves it to memory for faster access.
 */
Room.prototype.scan = function () {
    var room = this;

    //console.log('scanning', room.name);

    // Check if the controller has a container nearby.
    var structures = room.find(FIND_STRUCTURES, {
        filter: (structure) => structure.structureType == STRUCTURE_CONTAINER && structure.pos.getRangeTo(room.controller) <= 3
    });
    if (structures && structures.length > 0) {
        room.memory.controllerContainer = structures[0].id;
    }
    else {
        delete room.memory.controllerContainer;
    }

    // Check if the controller has a link nearby.
    var structures = room.find(FIND_STRUCTURES, {
        filter: (structure) => structure.structureType == STRUCTURE_LINK && structure.pos.getRangeTo(room.controller) <= 3
    });
    if (structures && structures.length > 0) {
        room.memory.controllerLink = structures[0].id;
    }
    else {
        delete room.memory.controllerLink;
    }

    // Check if storage has a link nearby.
    if (room.storage) {
        var structures = room.find(FIND_STRUCTURES, {
            filter: (structure) => structure.structureType == STRUCTURE_LINK && structure.pos.getRangeTo(room.storage) <= 3
        });
        if (structures && structures.length > 0) {
            room.memory.storageLink = structures[0].id;
        }
        else {
            delete room.memory.storageLink;
        }
    }

    // Scan room for labs.
    // @todo Find labs not used for reactions, to do creep boosts.
    if (!room.memory.labsLastChecked || room.memory.labsLastChecked < Game.time - 3267) {
        room.memory.labsLastChecked = Game.time;
        room.memory.canPerformReactions = false;

        var labs = room.find(FIND_STRUCTURES, {
            filter: (structure) => structure.structureType == STRUCTURE_LAB
        });
        if (labs.length >= 3) {
            for (let i in labs) {
                var lab = labs[i];

                // Check if there's at least 2 labs nearby for doing reactions.
                var closeLabs = lab.pos.findInRange(FIND_STRUCTURES, 2, {
                    filter: (structure) => structure.structureType == STRUCTURE_LAB && structure.id != lab.id
                });
                if (closeLabs.length < 2) continue;

                room.memory.canPerformReactions = true;
                room.memory.labs = {
                    reactor: [lab.id],
                    source1: closeLabs[0].id,
                    source2: closeLabs[1].id,
                };

                // Find other labs close to sources.
                let close2 = closeLabs[0].pos.findInRange(FIND_STRUCTURES, 2, {
                    filter: (structure) => structure.structureType == STRUCTURE_LAB && structure.id != lab.id && structure.id != closeLabs[0].id && structure.id != closeLabs[1].id
                });
                let close3 = closeLabs[1].pos.findInRange(FIND_STRUCTURES, 2, {
                    filter: (structure) => structure.structureType == STRUCTURE_LAB && structure.id != lab.id && structure.id != closeLabs[0].id && structure.id != closeLabs[1].id
                });
                for (let j in close2) {
                    for (let k in close3) {
                        if (close2[j].id == close3[k].id) {
                            room.memory.labs.reactor.push(close2[j].id);
                            break;
                        }
                    }
                }

                break;
            }
        }
    }
};

var pathPrecalculated = false;

var utilities = {

    precalculatePaths: function (room, sourceFlag) {
        if (pathPrecalculated) return;

        var start = Game.cpu.getUsed();
        //console.log('precalculate harvest paths', room, sourceFlag);

        var flagPosition = utilities.encodePosition(sourceFlag.pos);

        if (!room.memory.remoteHarvesting) {
            room.memory.remoteHarvesting = {};
        }
        if (!room.memory.remoteHarvesting[flagPosition]) {
            room.memory.remoteHarvesting[flagPosition] = {};
        }
        var harvestMemory = room.memory.remoteHarvesting[flagPosition];

        if (harvestMemory.cachedPath && Game.time - harvestMemory.cachedPath.lastCalculated < 1000) {
            // No need to recalculate path.
            return;
        }

        var startPosition = room.getStorageLocation();
        startPosition = new RoomPosition(startPosition.x, startPosition.y, room.name);
        if (room.storage) {
            startPosition = room.storage.pos;
        }

        var endPosition = sourceFlag.pos;
        //console.log('Finding path between', startPosition, 'and', endPosition);

        var result = utilities.getPath(startPosition, {pos: endPosition, range: 1});
        pathPrecalculated = true;

        if (result) {
            //console.log('found path in', result.ops, 'operations', result.path);

            harvestMemory.cachedPath = {
                lastCalculated: Game.time,
                path: Room.serializePositionPath(result.path),
            };
        }
        else {
            console.log('No path found!');
        }

        var end = Game.cpu.getUsed();
        //console.log('Total time:', end - start);
    },

    getPath: function (startPosition, endPosition, allowDanger) {
        return PathFinder.search(startPosition, endPosition, {
            plainCost: 2,
            swampCost: 10,
            maxOps: 10000, // The default 2000 can be too little even at a distance of only 2 rooms.

            roomCallback: function (roomName) {
                let room = Game.rooms[roomName];

                // If a room is considered inaccessible, don't look for paths through it.
                if (!allowDanger && intelManager.isRoomInaccessible(roomName)) return false;

                // If we have no sight in a room, assume it is empty.
                if (!room) return new PathFinder.CostMatrix;

                // Work with roads and structures in a room.
                // @todo Let intel manager generate the CostMatrixes and reuse them here.
                let costs = new PathFinder.CostMatrix;

                room.find(FIND_STRUCTURES).forEach(function (structure) {
                    if (structure.structureType === STRUCTURE_ROAD) {
                        // Only do this if no structure is on the road.
                        if (costs.get(structure.pos.x, structure.pos.y) <= 0) {
                            // Favor roads over plain tiles.
                            costs.set(structure.pos.x, structure.pos.y, 1);
                        }
                    } else if (structure.structureType !== STRUCTURE_CONTAINER && (structure.structureType !== STRUCTURE_RAMPART || !structure.my)) {
                        // Can't walk through non-walkable buildings.
                        costs.set(structure.pos.x, structure.pos.y, 0xff);
                    }
                });

                // Also try not to drive through bays.
                room.find(FIND_FLAGS, {
                    filter: (flag) => flag.name.startsWith('Bay:')
                }).forEach(function (flag) {
                    if (costs.get(flag.pos.x, flag.pos.y) <= 20) {
                        costs.set(flag.pos.x, flag.pos.y, 20);
                    }
                });

                // @todo Try not to drive to close to sources / minerals / controllers.

                return costs;
            },
        });
    },

    getClosest: function (creep, targets) {
        if (targets.length > 0) {
            var target = creep.pos.findClosestByRange(targets);
            if (target) {
                return target.id;
            }
        }
        return null;
    },

    getBestOption: function (options) {
        var best = null;

        for (var i in options) {
            if (!best || options[i].priority > best.priority || (options[i].priority == best.priority && options[i].weight > best.weight)) {
                best = options[i];
            }
        }

        return best;
    },

    getBodyCost: function (creep) {
        var cost = 0;
        for (var i in creep.body) {
            cost += BODYPART_COST[creep.body[i].type];
        }

        return cost;
    },

    getBodyParts: function (creep) {
        return creep.memory.body;
    },

    generateCreepBody: function (weights, maxCost, maxParts) {
        var newParts = {};
        var size = 0;
        var cost = 0;

        if (!maxCost) {
            maxCost = 300;
        }

        // Generate initial body containing at least one of each part.
        for (var part in weights) {
            newParts[part] = 1;
            size++;
            cost += BODYPART_COST[part];
        }

        if (cost > maxCost) {
            return null;
        }

        var done = false;
        while (!done && size < 50) {
            done = true;
            for (var part in BODYPART_COST) {
                var currentWeight = newParts[part] / size;
                if (currentWeight <= weights[part] && cost + BODYPART_COST[part] <= maxCost) {
                    if (!maxParts || !maxParts[part] || newParts[part] < maxParts[part]) {
                        done = false;
                        newParts[part]++;
                        size++;
                        cost += BODYPART_COST[part];
                        if (size >= 50) {
                            break;
                        }
                    }
                    else {
                        // Limit for this bodypart has been reached, so stop adding.
                        done = true;
                        break;
                    }
                }
            }
        }

        //console.log('total cost of new body: ' + cost);

        // Chain the generated configuration into an array of body parts.
        var body = [];

        if (newParts.tough) {
            for (var i = 0; i < newParts.tough; i++) {
                body.push(TOUGH);
            }
            delete newParts.tough;
        }
        if (newParts.move) {
            // One move part will be added last.
            newParts.move--;
        }
        var done = false;
        while (!done) {
            done = true;
            for (var part in newParts) {
                if (newParts[part] > 0) {
                    body.push(part);
                    newParts[part]--;
                    done = false;
                }
            }
        }
        if (newParts.move !== undefined) {
            // Add last move part to make sure creep is always mobile.
            body.push(MOVE);
        }

        return body;
    },

    encodePosition: function (position) {
        return position.roomName + '@' + position.x + 'x' + position.y;
    },

    decodePosition: function (position) {
        var parts = position.match(/^(.*)@([0-9]*)x([0-9]*)$/);

        if (parts && parts.length > 0) {
            return new RoomPosition(parts[2], parts[3], parts[1]);
        }
        return null;
    }

};

module.exports = utilities;
<commit_msg>Minimal pathfinding adjustment<commit_after>var intelManager = require('manager.intel');

/**
 * Calculates a central room position with some free space around it for placing a storage later.
 * If a storage already exists, its position is returned.
 */
Room.prototype.getStorageLocation = function () {
    var room = this;

    if (!this.controller) {
        return;
    }

    if (!room.memory.storage) {
        if (room.storage) {
            room.memory.storage = {
                x: room.storage.pos.x,
                y: room.storage.pos.y
            };
        }
        else {
            var sites = room.find(FIND_MY_CONSTRUCTION_SITES, {
                filter: (site) => site.structureType == STRUCTURE_STORAGE
            });
            if (sites && sites.length > 0) {
                room.memory.storage = {
                    x: sites[0].pos.x,
                    y: sites[0].pos.y
                };
            }
            else {
                // Determine decent storage spot by averaging source and spawner locations.
                var count = 1;
                var x = room.controller.pos.x;
                var y = room.controller.pos.y;

                for (var i in room.sources) {
                    x += room.sources[i].pos.x;
                    y += room.sources[i].pos.y;
                    count++;
                }
                var spawns = room.find(FIND_STRUCTURES, {
                    filter: (structure) => structure.structureType == STRUCTURE_SPAWN
                });
                for (var i in spawns) {
                    x += spawns[i].pos.x;
                    y += spawns[i].pos.y;
                    count++;
                }

                x = Math.round(x / count);
                y = Math.round(y / count);

                // Now that we have a base position, try to find the
                // closest spot that is surrounded by empty tiles.
                var dist = 0;
                var found = false;
                while (!found && dist < 10) {
                    for (var tx = x - dist; tx <= x + dist; tx++) {
                        for (var ty = y - dist; ty <= y + dist; ty++) {
                            if (found) {
                                continue;
                            }

                            if (tx == x - dist || tx == x + dist || ty == y - dist || ty == y + dist) {
                                // Tile is only valid if it and all surrounding tiles are empty.
                                var contents = room.lookAtArea(ty - 1, tx - 1, ty + 1, tx + 1, true);
                                var clean = true;
                                for (var i in contents) {
                                    var tile = contents[i];
                                    if (tile.type == 'terrain' && tile.terrain != 'plain' && tile.terrain != 'swamp') {
                                        clean = false;
                                        break;
                                    }
                                    if (tile.type == 'structure' || tile.type == 'constructionSite') {
                                        clean = false;
                                        break;
                                    }
                                }

                                if (clean) {
                                    found = true;
                                    room.memory.storage = {
                                        x: tx,
                                        y: ty
                                    };
                                }
                            }
                        }
                    }

                    // @todo Limit dist and find "worse" free spot otherwise.
                    dist++;
                }
            }
        }
    }

    return room.memory.storage;
};

/**
 * Gathers information about a rooms sources and saves it to memory for faster access.
 */
Room.prototype.scan = function () {
    var room = this;

    //console.log('scanning', room.name);

    // Check if the controller has a container nearby.
    var structures = room.find(FIND_STRUCTURES, {
        filter: (structure) => structure.structureType == STRUCTURE_CONTAINER && structure.pos.getRangeTo(room.controller) <= 3
    });
    if (structures && structures.length > 0) {
        room.memory.controllerContainer = structures[0].id;
    }
    else {
        delete room.memory.controllerContainer;
    }

    // Check if the controller has a link nearby.
    var structures = room.find(FIND_STRUCTURES, {
        filter: (structure) => structure.structureType == STRUCTURE_LINK && structure.pos.getRangeTo(room.controller) <= 3
    });
    if (structures && structures.length > 0) {
        room.memory.controllerLink = structures[0].id;
    }
    else {
        delete room.memory.controllerLink;
    }

    // Check if storage has a link nearby.
    if (room.storage) {
        var structures = room.find(FIND_STRUCTURES, {
            filter: (structure) => structure.structureType == STRUCTURE_LINK && structure.pos.getRangeTo(room.storage) <= 3
        });
        if (structures && structures.length > 0) {
            room.memory.storageLink = structures[0].id;
        }
        else {
            delete room.memory.storageLink;
        }
    }

    // Scan room for labs.
    // @todo Find labs not used for reactions, to do creep boosts.
    if (!room.memory.labsLastChecked || room.memory.labsLastChecked < Game.time - 3267) {
        room.memory.labsLastChecked = Game.time;
        room.memory.canPerformReactions = false;

        var labs = room.find(FIND_STRUCTURES, {
            filter: (structure) => structure.structureType == STRUCTURE_LAB
        });
        if (labs.length >= 3) {
            for (let i in labs) {
                var lab = labs[i];

                // Check if there's at least 2 labs nearby for doing reactions.
                var closeLabs = lab.pos.findInRange(FIND_STRUCTURES, 2, {
                    filter: (structure) => structure.structureType == STRUCTURE_LAB && structure.id != lab.id
                });
                if (closeLabs.length < 2) continue;

                room.memory.canPerformReactions = true;
                room.memory.labs = {
                    reactor: [lab.id],
                    source1: closeLabs[0].id,
                    source2: closeLabs[1].id,
                };

                // Find other labs close to sources.
                let close2 = closeLabs[0].pos.findInRange(FIND_STRUCTURES, 2, {
                    filter: (structure) => structure.structureType == STRUCTURE_LAB && structure.id != lab.id && structure.id != closeLabs[0].id && structure.id != closeLabs[1].id
                });
                let close3 = closeLabs[1].pos.findInRange(FIND_STRUCTURES, 2, {
                    filter: (structure) => structure.structureType == STRUCTURE_LAB && structure.id != lab.id && structure.id != closeLabs[0].id && structure.id != closeLabs[1].id
                });
                for (let j in close2) {
                    for (let k in close3) {
                        if (close2[j].id == close3[k].id) {
                            room.memory.labs.reactor.push(close2[j].id);
                            break;
                        }
                    }
                }

                break;
            }
        }
    }
};

var pathPrecalculated = false;

var utilities = {

    precalculatePaths: function (room, sourceFlag) {
        if (pathPrecalculated) return;

        var start = Game.cpu.getUsed();
        //console.log('precalculate harvest paths', room, sourceFlag);

        var flagPosition = utilities.encodePosition(sourceFlag.pos);

        if (!room.memory.remoteHarvesting) {
            room.memory.remoteHarvesting = {};
        }
        if (!room.memory.remoteHarvesting[flagPosition]) {
            room.memory.remoteHarvesting[flagPosition] = {};
        }
        var harvestMemory = room.memory.remoteHarvesting[flagPosition];

        if (harvestMemory.cachedPath && Game.time - harvestMemory.cachedPath.lastCalculated < 4060) {
            // No need to recalculate path.
            return;
        }

        var startPosition = room.getStorageLocation();
        startPosition = new RoomPosition(startPosition.x, startPosition.y, room.name);
        if (room.storage) {
            startPosition = room.storage.pos;
        }

        var endPosition = sourceFlag.pos;
        //console.log('Finding path between', startPosition, 'and', endPosition);

        var result = utilities.getPath(startPosition, {pos: endPosition, range: 1});
        pathPrecalculated = true;

        if (result) {
            //console.log('found path in', result.ops, 'operations', result.path);
            console.log('[PathFinder] New path calculated.');

            harvestMemory.cachedPath = {
                lastCalculated: Game.time,
                path: Room.serializePositionPath(result.path),
            };
        }
        else {
            console.log('No path found!');
        }

        var end = Game.cpu.getUsed();
        //console.log('Total time:', end - start);
    },

    getPath: function (startPosition, endPosition, allowDanger) {
        return PathFinder.search(startPosition, endPosition, {
            plainCost: 2,
            swampCost: 10,
            maxOps: 10000, // The default 2000 can be too little even at a distance of only 2 rooms.

            roomCallback: function (roomName) {
                let room = Game.rooms[roomName];

                // If a room is considered inaccessible, don't look for paths through it.
                if (!allowDanger && intelManager.isRoomInaccessible(roomName)) return false;

                // If we have no sight in a room, assume it is empty.
                if (!room) return new PathFinder.CostMatrix;

                // Work with roads and structures in a room.
                // @todo Let intel manager generate the CostMatrixes and reuse them here.
                let costs = new PathFinder.CostMatrix;

                room.find(FIND_STRUCTURES).forEach(function (structure) {
                    if (structure.structureType === STRUCTURE_ROAD) {
                        // Only do this if no structure is on the road.
                        if (costs.get(structure.pos.x, structure.pos.y) <= 0) {
                            // Favor roads over plain tiles.
                            costs.set(structure.pos.x, structure.pos.y, 1);
                        }
                    } else if (structure.structureType !== STRUCTURE_CONTAINER && (structure.structureType !== STRUCTURE_RAMPART || !structure.my)) {
                        // Can't walk through non-walkable buildings.
                        costs.set(structure.pos.x, structure.pos.y, 0xff);
                    }
                });

                // Also try not to drive through bays.
                room.find(FIND_FLAGS, {
                    filter: (flag) => flag.name.startsWith('Bay:')
                }).forEach(function (flag) {
                    if (costs.get(flag.pos.x, flag.pos.y) <= 20) {
                        costs.set(flag.pos.x, flag.pos.y, 20);
                    }
                });

                // @todo Try not to drive to close to sources / minerals / controllers.

                return costs;
            },
        });
    },

    getClosest: function (creep, targets) {
        if (targets.length > 0) {
            var target = creep.pos.findClosestByRange(targets);
            if (target) {
                return target.id;
            }
        }
        return null;
    },

    getBestOption: function (options) {
        var best = null;

        for (var i in options) {
            if (!best || options[i].priority > best.priority || (options[i].priority == best.priority && options[i].weight > best.weight)) {
                best = options[i];
            }
        }

        return best;
    },

    getBodyCost: function (creep) {
        var cost = 0;
        for (var i in creep.body) {
            cost += BODYPART_COST[creep.body[i].type];
        }

        return cost;
    },

    getBodyParts: function (creep) {
        return creep.memory.body;
    },

    generateCreepBody: function (weights, maxCost, maxParts) {
        var newParts = {};
        var size = 0;
        var cost = 0;

        if (!maxCost) {
            maxCost = 300;
        }

        // Generate initial body containing at least one of each part.
        for (var part in weights) {
            newParts[part] = 1;
            size++;
            cost += BODYPART_COST[part];
        }

        if (cost > maxCost) {
            return null;
        }

        var done = false;
        while (!done && size < 50) {
            done = true;
            for (var part in BODYPART_COST) {
                var currentWeight = newParts[part] / size;
                if (currentWeight <= weights[part] && cost + BODYPART_COST[part] <= maxCost) {
                    if (!maxParts || !maxParts[part] || newParts[part] < maxParts[part]) {
                        done = false;
                        newParts[part]++;
                        size++;
                        cost += BODYPART_COST[part];
                        if (size >= 50) {
                            break;
                        }
                    }
                    else {
                        // Limit for this bodypart has been reached, so stop adding.
                        done = true;
                        break;
                    }
                }
            }
        }

        //console.log('total cost of new body: ' + cost);

        // Chain the generated configuration into an array of body parts.
        var body = [];

        if (newParts.tough) {
            for (var i = 0; i < newParts.tough; i++) {
                body.push(TOUGH);
            }
            delete newParts.tough;
        }
        if (newParts.move) {
            // One move part will be added last.
            newParts.move--;
        }
        var done = false;
        while (!done) {
            done = true;
            for (var part in newParts) {
                if (newParts[part] > 0) {
                    body.push(part);
                    newParts[part]--;
                    done = false;
                }
            }
        }
        if (newParts.move !== undefined) {
            // Add last move part to make sure creep is always mobile.
            body.push(MOVE);
        }

        return body;
    },

    encodePosition: function (position) {
        return position.roomName + '@' + position.x + 'x' + position.y;
    },

    decodePosition: function (position) {
        var parts = position.match(/^(.*)@([0-9]*)x([0-9]*)$/);

        if (parts && parts.length > 0) {
            return new RoomPosition(parts[2], parts[3], parts[1]);
        }
        return null;
    }

};

module.exports = utilities;
<|endoftext|>


<commit_before>var intelManager = require('manager.intel');

/**
 * Calculates a central room position with some free space around it for placing a storage later.
 * If a storage already exists, its position is returned.
 */
Room.prototype.getStorageLocation = function () {
    var room = this;

    if (!this.controller) {
        return;
    }

    if (!room.memory.storage) {
        if (room.storage) {
            room.memory.storage = {
                x: room.storage.pos.x,
                y: room.storage.pos.y
            };
        }
        else {
            var sites = room.find(FIND_MY_CONSTRUCTION_SITES, {
                filter: (site) => site.structureType == STRUCTURE_STORAGE
            });
            if (sites && sites.length > 0) {
                room.memory.storage = {
                    x: sites[0].pos.x,
                    y: sites[0].pos.y
                };
            }
            else {
                // Determine decent storage spot by averaging source and spawner locations.
                var count = 1;
                var x = room.controller.pos.x;
                var y = room.controller.pos.y;

                for (var i in room.sources) {
                    x += room.sources[i].pos.x;
                    y += room.sources[i].pos.y;
                    count++;
                }
                var spawns = room.find(FIND_STRUCTURES, {
                    filter: (structure) => structure.structureType == STRUCTURE_SPAWN
                });
                for (var i in spawns) {
                    x += spawns[i].pos.x;
                    y += spawns[i].pos.y;
                    count++;
                }

                x = Math.round(x / count);
                y = Math.round(y / count);

                // Now that we have a base position, try to find the
                // closest spot that is surrounded by empty tiles.
                var dist = 0;
                var found = false;
                while (!found && dist < 10) {
                    for (var tx = x - dist; tx <= x + dist; tx++) {
                        for (var ty = y - dist; ty <= y + dist; ty++) {
                            if (found) {
                                continue;
                            }

                            if (tx == x - dist || tx == x + dist || ty == y - dist || ty == y + dist) {
                                // Tile is only valid if it and all surrounding tiles are empty.
                                var contents = room.lookAtArea(ty - 1, tx - 1, ty + 1, tx + 1, true);
                                var clean = true;
                                for (var i in contents) {
                                    var tile = contents[i];
                                    if (tile.type == 'terrain' && tile.terrain != 'plain' && tile.terrain != 'swamp') {
                                        clean = false;
                                        break;
                                    }
                                    if (tile.type == 'structure' || tile.type == 'constructionSite') {
                                        clean = false;
                                        break;
                                    }
                                }

                                if (clean) {
                                    found = true;
                                    room.memory.storage = {
                                        x: tx,
                                        y: ty
                                    };
                                }
                            }
                        }
                    }

                    // @todo Limit dist and find "worse" free spot otherwise.
                    dist++;
                }
            }
        }
    }

    return room.memory.storage;
};

/**
 * Gathers information about a rooms sources and saves it to memory for faster access.
 */
Room.prototype.scan = function () {
    var room = this;

    //console.log('scanning', room.name);

    // Check if the controller has a container nearby.
    var structures = room.find(FIND_STRUCTURES, {
        filter: (structure) => structure.structureType == STRUCTURE_CONTAINER && structure.pos.getRangeTo(room.controller) <= 3
    });
    if (structures && structures.length > 0) {
        room.memory.controllerContainer = structures[0].id;
    }
    else {
        delete room.memory.controllerContainer;
    }

    // Check if the controller has a link nearby.
    var structures = room.find(FIND_STRUCTURES, {
        filter: (structure) => structure.structureType == STRUCTURE_LINK && structure.pos.getRangeTo(room.controller) <= 3
    });
    if (structures && structures.length > 0) {
        room.memory.controllerLink = structures[0].id;
    }
    else {
        delete room.memory.controllerLink;
    }

    // Check if storage has a link nearby.
    if (room.storage) {
        var structures = room.find(FIND_STRUCTURES, {
            filter: (structure) => structure.structureType == STRUCTURE_LINK && structure.pos.getRangeTo(room.storage) <= 3
        });
        if (structures && structures.length > 0) {
            room.memory.storageLink = structures[0].id;
        }
        else {
            delete room.memory.storageLink;
        }
    }

    // Scan room for labs.
    // @todo Find labs not used for reactions, to do creep boosts.
    if (!room.memory.canPerformReactions) {
        var labs = room.find(FIND_STRUCTURES, {
            filter: (structure) => structure.structureType == STRUCTURE_LAB
        });
        if (labs.length >= 3) {
            for (let i in labs) {
                var lab = labs[i];

                // Check if there's at least 2 labs nearby for doing reactions.
                var closeLabs = lab.pos.findInRange(FIND_STRUCTURES, 2, {
                    filter: (structure) => structure.structureType == STRUCTURE_LAB && structure.id != lab.id
                });
                if (closeLabs.length < 2) continue;

                room.memory.canPerformReactions = true;
                room.memory.labs = {
                    reactor: lab.id,
                    source1: closeLabs[0].id,
                    source2: closeLabs[1].id,
                };
                break;
            }
        }
    }
};

var pathPrecalculated = false;

var utilities = {

    precalculatePaths: function (room, sourceFlag) {
        if (pathPrecalculated) return;

        var start = Game.cpu.getUsed();
        //console.log('precalculate harvest paths', room, sourceFlag);

        var flagPosition = utilities.encodePosition(sourceFlag.pos);

        if (!room.memory.remoteHarvesting) {
            room.memory.remoteHarvesting = {};
        }
        if (!room.memory.remoteHarvesting[flagPosition]) {
            room.memory.remoteHarvesting[flagPosition] = {};
        }
        var harvestMemory = room.memory.remoteHarvesting[flagPosition];

        if (harvestMemory.cachedPath && Game.time - harvestMemory.cachedPath.lastCalculated < 1000) {
            // No need to recalculate path.
            return;
        }

        var startPosition = room.getStorageLocation();
        startPosition = new RoomPosition(startPosition.x, startPosition.y, room.name);
        if (room.storage) {
            startPosition = room.storage.pos;
        }

        var endPosition = sourceFlag.pos;
        //console.log('Finding path between', startPosition, 'and', endPosition);

        var result = PathFinder.search(startPosition, {pos: endPosition, range: 1}, {
            plainCost: 2,
            swampCost: 10,
            maxOps: 10000, // The default 2000 can be too little even at a distance of only 2 rooms.

            roomCallback: function (roomName) {
                let room = Game.rooms[roomName];

                // If a room is considered inaccessible, don't look for paths through it.
                if (intelManager.isRoomInaccessible(roomName)) return false;

                // If we have no sight in a room, assume it is empty.
                if (!room) return new PathFinder.CostMatrix;

                // Work with roads and structures in a room.
                // @todo Let intel manager generate the CostMatrixes and reuse them here.
                let costs = new PathFinder.CostMatrix;

                room.find(FIND_STRUCTURES).forEach(function (structure) {
                    if (structure.structureType === STRUCTURE_ROAD) {
                        // Only do this if no structure is on the road.
                        if (costs.get(structure.pos.x, structure.pos.y) <= 0) {
                            // Favor roads over plain tiles.
                            costs.set(structure.pos.x, structure.pos.y, 1);
                        }
                    } else if (structure.structureType !== STRUCTURE_CONTAINER && (structure.structureType !== STRUCTURE_RAMPART || !structure.my)) {
                        // Can't walk through non-walkable buildings.
                        costs.set(structure.pos.x, structure.pos.y, 0xff);
                    }
                });

                // Also try not to drive through bays.
                room.find(FIND_FLAGS, {
                    filter: (flag) => flag.name.startsWith('Bay:')
                }).forEach(function (flag) {
                    if (costs.get(flag.pos.x, flag.pos.y) <= 20) {
                        costs.set(flag.pos.x, flag.pos.y, 20);
                    }
                });

                return costs;
            },
        });
        pathPrecalculated = true;

        if (result) {
            //console.log('found path in', result.ops, 'operations', result.path);

            harvestMemory.cachedPath = {
                lastCalculated: Game.time,
                path: Room.serializePositionPath(result.path),
            };
        }
        else {
            console.log('No path found!');
        }

        var end = Game.cpu.getUsed();
        //console.log('Total time:', end - start);
    },

    getClosest: function (creep, targets) {
        if (targets.length > 0) {
            var target = creep.pos.findClosestByPath(targets);
            if (target) {
                return target.id;
            }
        }
        return null;
    },

    getBestOption: function (options) {
        var best = null;

        for (var i in options) {
            if (!best || options[i].priority > best.priority || (options[i].priority == best.priority && options[i].weight > best.weight)) {
                best = options[i];
            }
        }

        return best;
    },

    getBodyCost: function (creep) {
        var cost = 0;
        for (var i in creep.body) {
            cost += BODYPART_COST[creep.body[i].type];
        }

        return cost;
    },

    getBodyParts: function (creep) {
        return creep.memory.body;
    },

    generateCreepBody: function (weights, maxCost, maxParts) {
        var newParts = {};
        var size = 0;
        var cost = 0;

        if (!maxCost) {
            maxCost = 300;
        }

        // Generate initial body containing at least one of each part.
        for (var part in weights) {
            newParts[part] = 1;
            size++;
            cost += BODYPART_COST[part];
        }

        if (cost > maxCost) {
            return null;
        }

        var done = false;
        while (!done && size < 50) {
            done = true;
            for (var part in BODYPART_COST) {
                var currentWeight = newParts[part] / size;
                if (currentWeight <= weights[part] && cost + BODYPART_COST[part] <= maxCost) {
                    if (!maxParts || !maxParts[part] || newParts[part] < maxParts[part]) {
                        done = false;
                        newParts[part]++;
                        size++;
                        cost += BODYPART_COST[part];
                        if (size >= 50) {
                            break;
                        }
                    }
                    else {
                        // Limit for this bodypart has been reached, so stop adding.
                        done = true;
                        break;
                    }
                }
            }
        }

        //console.log('total cost of new body: ' + cost);

        // Chain the generated configuration into an array of body parts.
        var body = [];

        if (newParts.tough) {
            for (var i = 0; i < newParts.tough; i++) {
                body.push(TOUGH);
            }
            delete newParts.tough;
        }
        if (newParts.move) {
            // One move part will be added last.
            newParts.move--;
        }
        var done = false;
        while (!done) {
            done = true;
            for (var part in newParts) {
                if (newParts[part] > 0) {
                    body.push(part);
                    newParts[part]--;
                    done = false;
                }
            }
        }
        if (newParts.move !== undefined) {
            // Add last move part to make sure creep is always mobile.
            body.push(MOVE);
        }

        return body;
    },

    encodePosition: function (position) {
        return position.roomName + '@' + position.x + 'x' + position.y;
    },

    decodePosition: function (position) {
        var parts = position.match(/^(.*)@([0-9]*)x([0-9]*)$/);

        if (parts && parts.length > 0) {
            return new RoomPosition(parts[2], parts[3], parts[1]);
        }
        return null;
    }

};

module.exports = utilities;
<commit_msg>prefer searching by range to save on cpu<commit_after>var intelManager = require('manager.intel');

/**
 * Calculates a central room position with some free space around it for placing a storage later.
 * If a storage already exists, its position is returned.
 */
Room.prototype.getStorageLocation = function () {
    var room = this;

    if (!this.controller) {
        return;
    }

    if (!room.memory.storage) {
        if (room.storage) {
            room.memory.storage = {
                x: room.storage.pos.x,
                y: room.storage.pos.y
            };
        }
        else {
            var sites = room.find(FIND_MY_CONSTRUCTION_SITES, {
                filter: (site) => site.structureType == STRUCTURE_STORAGE
            });
            if (sites && sites.length > 0) {
                room.memory.storage = {
                    x: sites[0].pos.x,
                    y: sites[0].pos.y
                };
            }
            else {
                // Determine decent storage spot by averaging source and spawner locations.
                var count = 1;
                var x = room.controller.pos.x;
                var y = room.controller.pos.y;

                for (var i in room.sources) {
                    x += room.sources[i].pos.x;
                    y += room.sources[i].pos.y;
                    count++;
                }
                var spawns = room.find(FIND_STRUCTURES, {
                    filter: (structure) => structure.structureType == STRUCTURE_SPAWN
                });
                for (var i in spawns) {
                    x += spawns[i].pos.x;
                    y += spawns[i].pos.y;
                    count++;
                }

                x = Math.round(x / count);
                y = Math.round(y / count);

                // Now that we have a base position, try to find the
                // closest spot that is surrounded by empty tiles.
                var dist = 0;
                var found = false;
                while (!found && dist < 10) {
                    for (var tx = x - dist; tx <= x + dist; tx++) {
                        for (var ty = y - dist; ty <= y + dist; ty++) {
                            if (found) {
                                continue;
                            }

                            if (tx == x - dist || tx == x + dist || ty == y - dist || ty == y + dist) {
                                // Tile is only valid if it and all surrounding tiles are empty.
                                var contents = room.lookAtArea(ty - 1, tx - 1, ty + 1, tx + 1, true);
                                var clean = true;
                                for (var i in contents) {
                                    var tile = contents[i];
                                    if (tile.type == 'terrain' && tile.terrain != 'plain' && tile.terrain != 'swamp') {
                                        clean = false;
                                        break;
                                    }
                                    if (tile.type == 'structure' || tile.type == 'constructionSite') {
                                        clean = false;
                                        break;
                                    }
                                }

                                if (clean) {
                                    found = true;
                                    room.memory.storage = {
                                        x: tx,
                                        y: ty
                                    };
                                }
                            }
                        }
                    }

                    // @todo Limit dist and find "worse" free spot otherwise.
                    dist++;
                }
            }
        }
    }

    return room.memory.storage;
};

/**
 * Gathers information about a rooms sources and saves it to memory for faster access.
 */
Room.prototype.scan = function () {
    var room = this;

    //console.log('scanning', room.name);

    // Check if the controller has a container nearby.
    var structures = room.find(FIND_STRUCTURES, {
        filter: (structure) => structure.structureType == STRUCTURE_CONTAINER && structure.pos.getRangeTo(room.controller) <= 3
    });
    if (structures && structures.length > 0) {
        room.memory.controllerContainer = structures[0].id;
    }
    else {
        delete room.memory.controllerContainer;
    }

    // Check if the controller has a link nearby.
    var structures = room.find(FIND_STRUCTURES, {
        filter: (structure) => structure.structureType == STRUCTURE_LINK && structure.pos.getRangeTo(room.controller) <= 3
    });
    if (structures && structures.length > 0) {
        room.memory.controllerLink = structures[0].id;
    }
    else {
        delete room.memory.controllerLink;
    }

    // Check if storage has a link nearby.
    if (room.storage) {
        var structures = room.find(FIND_STRUCTURES, {
            filter: (structure) => structure.structureType == STRUCTURE_LINK && structure.pos.getRangeTo(room.storage) <= 3
        });
        if (structures && structures.length > 0) {
            room.memory.storageLink = structures[0].id;
        }
        else {
            delete room.memory.storageLink;
        }
    }

    // Scan room for labs.
    // @todo Find labs not used for reactions, to do creep boosts.
    if (!room.memory.canPerformReactions) {
        var labs = room.find(FIND_STRUCTURES, {
            filter: (structure) => structure.structureType == STRUCTURE_LAB
        });
        if (labs.length >= 3) {
            for (let i in labs) {
                var lab = labs[i];

                // Check if there's at least 2 labs nearby for doing reactions.
                var closeLabs = lab.pos.findInRange(FIND_STRUCTURES, 2, {
                    filter: (structure) => structure.structureType == STRUCTURE_LAB && structure.id != lab.id
                });
                if (closeLabs.length < 2) continue;

                room.memory.canPerformReactions = true;
                room.memory.labs = {
                    reactor: lab.id,
                    source1: closeLabs[0].id,
                    source2: closeLabs[1].id,
                };
                break;
            }
        }
    }
};

var pathPrecalculated = false;

var utilities = {

    precalculatePaths: function (room, sourceFlag) {
        if (pathPrecalculated) return;

        var start = Game.cpu.getUsed();
        //console.log('precalculate harvest paths', room, sourceFlag);

        var flagPosition = utilities.encodePosition(sourceFlag.pos);

        if (!room.memory.remoteHarvesting) {
            room.memory.remoteHarvesting = {};
        }
        if (!room.memory.remoteHarvesting[flagPosition]) {
            room.memory.remoteHarvesting[flagPosition] = {};
        }
        var harvestMemory = room.memory.remoteHarvesting[flagPosition];

        if (harvestMemory.cachedPath && Game.time - harvestMemory.cachedPath.lastCalculated < 1000) {
            // No need to recalculate path.
            return;
        }

        var startPosition = room.getStorageLocation();
        startPosition = new RoomPosition(startPosition.x, startPosition.y, room.name);
        if (room.storage) {
            startPosition = room.storage.pos;
        }

        var endPosition = sourceFlag.pos;
        //console.log('Finding path between', startPosition, 'and', endPosition);

        var result = PathFinder.search(startPosition, {pos: endPosition, range: 1}, {
            plainCost: 2,
            swampCost: 10,
            maxOps: 10000, // The default 2000 can be too little even at a distance of only 2 rooms.

            roomCallback: function (roomName) {
                let room = Game.rooms[roomName];

                // If a room is considered inaccessible, don't look for paths through it.
                if (intelManager.isRoomInaccessible(roomName)) return false;

                // If we have no sight in a room, assume it is empty.
                if (!room) return new PathFinder.CostMatrix;

                // Work with roads and structures in a room.
                // @todo Let intel manager generate the CostMatrixes and reuse them here.
                let costs = new PathFinder.CostMatrix;

                room.find(FIND_STRUCTURES).forEach(function (structure) {
                    if (structure.structureType === STRUCTURE_ROAD) {
                        // Only do this if no structure is on the road.
                        if (costs.get(structure.pos.x, structure.pos.y) <= 0) {
                            // Favor roads over plain tiles.
                            costs.set(structure.pos.x, structure.pos.y, 1);
                        }
                    } else if (structure.structureType !== STRUCTURE_CONTAINER && (structure.structureType !== STRUCTURE_RAMPART || !structure.my)) {
                        // Can't walk through non-walkable buildings.
                        costs.set(structure.pos.x, structure.pos.y, 0xff);
                    }
                });

                // Also try not to drive through bays.
                room.find(FIND_FLAGS, {
                    filter: (flag) => flag.name.startsWith('Bay:')
                }).forEach(function (flag) {
                    if (costs.get(flag.pos.x, flag.pos.y) <= 20) {
                        costs.set(flag.pos.x, flag.pos.y, 20);
                    }
                });

                return costs;
            },
        });
        pathPrecalculated = true;

        if (result) {
            //console.log('found path in', result.ops, 'operations', result.path);

            harvestMemory.cachedPath = {
                lastCalculated: Game.time,
                path: Room.serializePositionPath(result.path),
            };
        }
        else {
            console.log('No path found!');
        }

        var end = Game.cpu.getUsed();
        //console.log('Total time:', end - start);
    },

    getClosest: function (creep, targets) {
        if (targets.length > 0) {
            var target = creep.pos.findClosestByRange(targets);
            if (target) {
                return target.id;
            }
        }
        return null;
    },

    getBestOption: function (options) {
        var best = null;

        for (var i in options) {
            if (!best || options[i].priority > best.priority || (options[i].priority == best.priority && options[i].weight > best.weight)) {
                best = options[i];
            }
        }

        return best;
    },

    getBodyCost: function (creep) {
        var cost = 0;
        for (var i in creep.body) {
            cost += BODYPART_COST[creep.body[i].type];
        }

        return cost;
    },

    getBodyParts: function (creep) {
        return creep.memory.body;
    },

    generateCreepBody: function (weights, maxCost, maxParts) {
        var newParts = {};
        var size = 0;
        var cost = 0;

        if (!maxCost) {
            maxCost = 300;
        }

        // Generate initial body containing at least one of each part.
        for (var part in weights) {
            newParts[part] = 1;
            size++;
            cost += BODYPART_COST[part];
        }

        if (cost > maxCost) {
            return null;
        }

        var done = false;
        while (!done && size < 50) {
            done = true;
            for (var part in BODYPART_COST) {
                var currentWeight = newParts[part] / size;
                if (currentWeight <= weights[part] && cost + BODYPART_COST[part] <= maxCost) {
                    if (!maxParts || !maxParts[part] || newParts[part] < maxParts[part]) {
                        done = false;
                        newParts[part]++;
                        size++;
                        cost += BODYPART_COST[part];
                        if (size >= 50) {
                            break;
                        }
                    }
                    else {
                        // Limit for this bodypart has been reached, so stop adding.
                        done = true;
                        break;
                    }
                }
            }
        }

        //console.log('total cost of new body: ' + cost);

        // Chain the generated configuration into an array of body parts.
        var body = [];

        if (newParts.tough) {
            for (var i = 0; i < newParts.tough; i++) {
                body.push(TOUGH);
            }
            delete newParts.tough;
        }
        if (newParts.move) {
            // One move part will be added last.
            newParts.move--;
        }
        var done = false;
        while (!done) {
            done = true;
            for (var part in newParts) {
                if (newParts[part] > 0) {
                    body.push(part);
                    newParts[part]--;
                    done = false;
                }
            }
        }
        if (newParts.move !== undefined) {
            // Add last move part to make sure creep is always mobile.
            body.push(MOVE);
        }

        return body;
    },

    encodePosition: function (position) {
        return position.roomName + '@' + position.x + 'x' + position.y;
    },

    decodePosition: function (position) {
        var parts = position.match(/^(.*)@([0-9]*)x([0-9]*)$/);

        if (parts && parts.length > 0) {
            return new RoomPosition(parts[2], parts[3], parts[1]);
        }
        return null;
    }

};

module.exports = utilities;
<|endoftext|>


<commit_before>import merge from 'lodash/merge'
import { grpcService } from 'workers'
import { requestFees } from '@zap/utils/api'
import { mainLog } from '@zap/utils/log'

/**
 * estimateLndFee - Returns fee estimation for the specified @address @amount & @targetConf using LND gRPC API.
 *
 * @param {string} address Address
 * @param {number} amount Amount in satoshis
 * @param {number} targetConf Desired confirmation time
 * @returns {{fee_sat, feerate_sat_per_byte}|null} Fee data if success or null in case of any error
 */
export async function estimateLndFee(address, amount, targetConf) {
  // lnd fee estimator requires this params
  if (!address || !amount || !targetConf) {
    return null
  }

  try {
    const grpc = await grpcService
    const fees = await grpc.services.Lightning.estimateFee(address, amount, targetConf)
    // check if we actually got a meaningful response
    if (fees && fees.fee_sat) {
      return fees
    }

    return null
  } catch (e) {
    mainLog.warn(`estimate fee error: ${e}`)
    // something went wrong. potentially we are running LND <0.6 and this methods is unsupported
    // or tx output is dust or any other error. Use fallback instead
    return null
  }
}

/**
 * estimateFeeRange - Estimate fees for specified range.
 *
 * Expected range format is {fastestConfCount, halfHourConfCount, hourConfCount}
 * Fee estimation is based on LND endpoint. If it's unavailable then @fallback is used.
 *
 * @param {{address, amountInSats, range, asRate, fallback}} options Options
 * @returns {{fastestFee:number, halfHourFee:number, hourFee:number}} Fee data
 */
export async function estimateFeeRange({
  address,
  amountInSats,
  range,
  asRate = true,
  fallback = requestFees,
}) {
  const { fast, medium, slow } = range

  // lnd fee estimator requires this params
  if (!address || !amountInSats) {
    return fallback({ fast, medium, slow })
  }

  const [fastestFee, mediumFee, slowFee] = await Promise.all([
    estimateLndFee(address, amountInSats, fast),
    estimateLndFee(address, amountInSats, medium),
    estimateLndFee(address, amountInSats, slow),
  ])

  // check if we have at least one estimate and fill the gap with fallback values otherwise
  const fallbackFees =
    !fastestFee || !mediumFee || !slowFee ? await fallback({ fast, medium, slow }) : {}

  // extracts fee from a lnd grpc response
  const getFee = feeObj => {
    if (feeObj) {
      return asRate ? feeObj.feerate_sat_per_byte : feeObj.fee_sat
    }
    return undefined
  }

  // try to use any info from the gRPC call if it's available
  return merge(
    {
      fast: getFee(fastestFee),
      medium: getFee(mediumFee),
      slow: getFee(slowFee),
    },
    fallbackFees
  )
}
<commit_msg>fix(wallet): ensure minimum transaction fee of 1 sat per byte<commit_after>import merge from 'lodash/merge'
import mapValues from 'lodash/mapValues'
import { grpcService } from 'workers'
import { requestFees } from '@zap/utils/api'
import { mainLog } from '@zap/utils/log'

/**
 * sanitizeFeeRange - Sanitize a fee rate object ensuring that all fees are at least 1.
 *
 * @param  {object} fees Fee rate object
 * @returns {object} Sanitized fee rate object
 */
const sanitizeFeeRange = fees => mapValues(fees, fee => Math.max(1, fee))

/**
 * estimateLndFee - Returns fee estimation for the specified @address @amount & @targetConf using LND gRPC API.
 *
 * @param {string} address Address
 * @param {number} amount Amount in satoshis
 * @param {number} targetConf Desired confirmation time
 * @returns {{fee_sat, feerate_sat_per_byte}|null} Fee data if success or null in case of any error
 */
export async function estimateLndFee(address, amount, targetConf) {
  // lnd fee estimator requires this params
  if (!address || !amount || !targetConf) {
    return null
  }

  try {
    const grpc = await grpcService
    const fees = await grpc.services.Lightning.estimateFee(address, amount, targetConf)
    // check if we actually got a meaningful response
    if (fees && fees.fee_sat) {
      return sanitizeFeeRange(fees)
    }

    return null
  } catch (e) {
    mainLog.warn(`estimate fee error: ${e}`)
    // something went wrong. potentially we are running LND <0.6 and this methods is unsupported
    // or tx output is dust or any other error. Use fallback instead
    return null
  }
}

/**
 * estimateFeeRange - Estimate fees for specified range.
 *
 * Expected range format is {fastestConfCount, halfHourConfCount, hourConfCount}
 * Fee estimation is based on LND endpoint. If it's unavailable then @fallback is used.
 *
 * @param {{address, amountInSats, range, asRate, fallback}} options Options
 * @returns {{fastestFee:number, halfHourFee:number, hourFee:number}} Fee data
 */
export async function estimateFeeRange({
  address,
  amountInSats,
  range,
  asRate = true,
  fallback = requestFees,
}) {
  const { fast, medium, slow } = range

  // lnd fee estimator requires this params
  if (!address || !amountInSats) {
    const feeRange = await fallback({ fast, medium, slow })
    return sanitizeFeeRange(feeRange)
  }

  const [fastestFee, mediumFee, slowFee] = await Promise.all([
    estimateLndFee(address, amountInSats, fast),
    estimateLndFee(address, amountInSats, medium),
    estimateLndFee(address, amountInSats, slow),
  ])

  // check if we have at least one estimate and fill the gap with fallback values otherwise
  const fallbackFees =
    !fastestFee || !mediumFee || !slowFee ? await fallback({ fast, medium, slow }) : {}

  // extracts fee from a lnd grpc response
  const getFee = feeObj => {
    if (feeObj) {
      return asRate ? feeObj.feerate_sat_per_byte : feeObj.fee_sat
    }
    return undefined
  }

  // try to use any info from the gRPC call if it's available
  const feeRange = merge(
    {
      fast: getFee(fastestFee),
      medium: getFee(mediumFee),
      slow: getFee(slowFee),
    },
    fallbackFees
  )

  return sanitizeFeeRange(feeRange)
}
<|endoftext|>


<commit_before>dojo.provide("dojox.uuid.Uuid");

dojox.uuid.Uuid = function(/*String?*/ input){
	// summary:
	//		This is the constructor for the Uuid class.  The Uuid class offers
	//		methods for inspecting existing UUIDs.
	// input: A 36-character string that conforms to the UUID spec.
	// examples:
	//		var uuid;
	//		uuid = new dojox.uuid.Uuid("3b12f1df-5232-4804-897e-917bf397618a");
	//		uuid = new dojox.uuid.Uuid(); // "00000000-0000-0000-0000-000000000000"
	//		uuid = new dojox.uuid.Uuid(dojox.uuid.generateRandomUuid());
	//		uuid = new dojox.uuid.Uuid(dojox.uuid.generateTimeBasedUuid());
	//		dojox.uuid.Uuid.setGenerator(dojox.uuid.generateRandomUuid);
	//		uuid = new dojox.uuid.Uuid();
	//		dojox.uuid.assert(!uuid.isEqual(dojox.uuid.NIL_UUID));
	this._uuidString = dojox.uuid.NIL_UUID;
	if(input){
		dojox.uuid.assert(dojo.isString(input));
		this._uuidString = input.toLowerCase();
		dojox.uuid.assert(this.isValid());
	}else{
		var ourGenerator = dojox.uuid.Uuid.getGenerator();
		if(ourGenerator){
			this._uuidString = ourGenerator();
			dojox.uuid.assert(this.isValid());
		}
	}
};

dojox.uuid.Uuid.compare = function(/*dojox.uuid.Uuid*/ uuidOne, /*dojox.uuid.Uuid*/ uuidTwo){
	// summary:
	//		Given two UUIDs to compare, this method returns 0, 1, or -1.
	// description:
	//		This method is designed to be used by sorting routines, like the
	//		JavaScript built-in Array sort() method. This implementation is
	//		intended to match the sample implementation in IETF RFC 4122:
	//		http://www.ietf.org/rfc/rfc4122.txt
	// uuidOne: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	// uuidTwo: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.

	// examples:
	//		var uuid;
	//		var generator = dojox.uuid.TimeBasedGenerator;
	//		var a = new dojox.uuid.Uuid(generator);
	//		var b = new dojox.uuid.Uuid(generator);
	//		var c = new dojox.uuid.Uuid(generator);
	//		var array = new Array(a, b, c);
	//		array.sort(dojox.uuid.Uuid.compare);
	var uuidStringOne = uuidOne.toString();
	var uuidStringTwo = uuidTwo.toString();
	if (uuidStringOne > uuidStringTwo) return 1;   // integer
	if (uuidStringOne < uuidStringTwo) return -1;  // integer
	return 0; // integer (either 0, 1, or -1)
};

dojox.uuid.Uuid.setGenerator = function(/*Function?*/ generator){
	// summary:
	//		Sets the default generator, which will be used by the
	//		"new dojox.uuid.Uuid()" constructor if no parameters
	//		are passed in.
	// generator: A UUID generator function, such as dojox.uuid.generateTimeBasedUuid.
	dojox.uuid.assert(!generator || dojo.isFunction(generator));
	dojox.uuid.Uuid._ourGenerator = generator;
};

dojox.uuid.Uuid.getGenerator = function(){
	// summary:
	//		Returns the default generator.  See setGenerator().
	return dojox.uuid.Uuid._ourGenerator; // generator (A UUID generator, such as dojox.uuid.TimeBasedGenerator).
};

dojox.uuid.Uuid.prototype.toString = function(){
	// summary:
	//		This method returns a standard 36-character string representing
	//		the UUID, such as "3b12f1df-5232-4804-897e-917bf397618a".
	return this._uuidString; // string
};

dojox.uuid.Uuid.prototype.compare = function(/*dojox.uuid.Uuid*/ otherUuid){
	// summary:
	//		Compares this UUID to another UUID, and returns 0, 1, or -1.
	// description:
	//		This implementation is intended to match the sample implementation
	//		in IETF RFC 4122: http://www.ietf.org/rfc/rfc4122.txt
	// otherUuid: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	return dojox.uuid.Uuid.compare(this, otherUuid); // integer (either 0, 1, or -1)
};

dojox.uuid.Uuid.prototype.isEqual = function(/*dojox.uuid.Uuid*/ otherUuid){
	// summary:
	//		Returns true if this UUID is equal to the otherUuid, or false otherwise.
	// otherUuid: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	return (this.compare(otherUuid) == 0); // boolean
};

dojox.uuid.Uuid.prototype.isValid = function(){
	// summary:
	//		Returns true if the UUID was initialized with a valid value.
	return dojox.uuid.isValid(this);
};

dojox.uuid.Uuid.prototype.getVariant = function(){
	// summary:
	//		Returns a variant code that indicates what type of UUID this is.
	//		Returns one of the enumerated dojox.uuid.variant values.

	// example:
	//		var uuid = new dojox.uuid.Uuid("3b12f1df-5232-4804-897e-917bf397618a");
	//		var variant = uuid.getVariant();
	//		dojox.uuid.assert(variant == dojox.uuid.variant.DCE);
	// example:
	// "3b12f1df-5232-4804-897e-917bf397618a"
	//                     ^
	//                     |
	//         (variant "10__" == DCE)
	return dojox.uuid.getVariant(this);
};

dojox.uuid.Uuid.prototype.getVersion = function(){
	// summary:
	//		Returns a version number that indicates what type of UUID this is.
	//		Returns one of the enumerated dojox.uuid.version values.
	// example:
	//		var uuid = new dojox.uuid.Uuid("b4308fb0-86cd-11da-a72b-0800200c9a66");
	//		var version = uuid.getVersion();
	//		dojox.uuid.assert(version == dojox.uuid.version.TIME_BASED);
	// exceptions:
	//		Throws an Error if this is not a DCE Variant UUID.
	if(!this._versionNumber){
		this._versionNumber = dojox.uuid.getVersion(this);
	}
	return this._versionNumber; // dojox.uuid.version
};

dojox.uuid.Uuid.prototype.getNode = function(){
	// summary:
	//		If this is a version 1 UUID (a time-based UUID), getNode() returns a
	//		12-character string with the "node" or "pseudonode" portion of the UUID,
	//		which is the rightmost 12 characters.
	// exceptions:
	//		Throws an Error if this is not a version 1 UUID.
	if (!this._nodeString) {
		this._nodeString = dojox.uuid.getNode(this);
	}
	return this._nodeString; // String (a 12-character string, which will look something like "917bf397618a")
};

dojox.uuid.Uuid.prototype.getTimestamp = function(/*String?*/ returnType){
	// summary:
	//		If this is a version 1 UUID (a time-based UUID), this method returns
	//		the timestamp value encoded in the UUID.  The caller can ask for the
	//		timestamp to be returned either as a JavaScript Date object or as a
	//		15-character string of hex digits.
	// returnType: Any of these five values: "string", String, "hex", "date", Date
	// returns:
	//		Returns the timestamp value as a JavaScript Date object or a 15-character string of hex digits.
	// examples:
	//		var uuid = new dojox.uuid.Uuid("b4308fb0-86cd-11da-a72b-0800200c9a66");
	//		var date, string, hexString;
	//		date   = uuid.getTimestamp();         // returns a JavaScript Date
	//		date   = uuid.getTimestamp(Date);     //
	//		string = uuid.getTimestamp(String);   // "Mon, 16 Jan 2006 20:21:41 GMT"
	//		hexString = uuid.getTimestamp("hex"); // "1da86cdb4308fb0"
	// exceptions:
	//		Throws an Error if this is not a version 1 UUID.
	if(!returnType){returnType = null};
	switch(returnType){
		case "string":
		case String:
			return this.getTimestamp(Date).toUTCString(); // String (e.g. "Mon, 16 Jan 2006 20:21:41 GMT")
			break;
		case "hex":
			// Return a 15-character string of hex digits containing the
			// timestamp for this UUID, with the high-order bits first.
			if (!this._timestampAsHexString) {
				this._timestampAsHexString = dojox.uuid.getTimestamp(this, "hex");
			}
			return this._timestampAsHexString; // String (e.g. "1da86cdb4308fb0")
			break;
		case null: // no returnType was specified, so default to Date
		case "date":
		case Date:
			// Return a JavaScript Date object.
			if (!this._timestampAsDate) {
				this._timestampAsDate = dojox.uuid.getTimestamp(this, Date);
			}
			return this._timestampAsDate; // Date
			break;
		default:
			// we got passed something other than a valid returnType
			dojox.uuid.assert(false, "The getTimestamp() method dojox.uuid.Uuid was passed a bogus returnType: " + returnType);
			break;
	}
};
<commit_msg>added a missing require statement in dojox.uuid.Uuid<commit_after>dojo.provide("dojox.uuid.Uuid");
dojo.require("dojox.uuid");

dojox.uuid.Uuid = function(/*String?*/ input){
	// summary:
	//		This is the constructor for the Uuid class.  The Uuid class offers
	//		methods for inspecting existing UUIDs.
	// input: A 36-character string that conforms to the UUID spec.
	// examples:
	//		var uuid;
	//		uuid = new dojox.uuid.Uuid("3b12f1df-5232-4804-897e-917bf397618a");
	//		uuid = new dojox.uuid.Uuid(); // "00000000-0000-0000-0000-000000000000"
	//		uuid = new dojox.uuid.Uuid(dojox.uuid.generateRandomUuid());
	//		uuid = new dojox.uuid.Uuid(dojox.uuid.generateTimeBasedUuid());
	//		dojox.uuid.Uuid.setGenerator(dojox.uuid.generateRandomUuid);
	//		uuid = new dojox.uuid.Uuid();
	//		dojox.uuid.assert(!uuid.isEqual(dojox.uuid.NIL_UUID));
	this._uuidString = dojox.uuid.NIL_UUID;
	if(input){
		dojox.uuid.assert(dojo.isString(input));
		this._uuidString = input.toLowerCase();
		dojox.uuid.assert(this.isValid());
	}else{
		var ourGenerator = dojox.uuid.Uuid.getGenerator();
		if(ourGenerator){
			this._uuidString = ourGenerator();
			dojox.uuid.assert(this.isValid());
		}
	}
};

dojox.uuid.Uuid.compare = function(/*dojox.uuid.Uuid*/ uuidOne, /*dojox.uuid.Uuid*/ uuidTwo){
	// summary:
	//		Given two UUIDs to compare, this method returns 0, 1, or -1.
	// description:
	//		This method is designed to be used by sorting routines, like the
	//		JavaScript built-in Array sort() method. This implementation is
	//		intended to match the sample implementation in IETF RFC 4122:
	//		http://www.ietf.org/rfc/rfc4122.txt
	// uuidOne: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	// uuidTwo: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.

	// examples:
	//		var uuid;
	//		var generator = dojox.uuid.TimeBasedGenerator;
	//		var a = new dojox.uuid.Uuid(generator);
	//		var b = new dojox.uuid.Uuid(generator);
	//		var c = new dojox.uuid.Uuid(generator);
	//		var array = new Array(a, b, c);
	//		array.sort(dojox.uuid.Uuid.compare);
	var uuidStringOne = uuidOne.toString();
	var uuidStringTwo = uuidTwo.toString();
	if (uuidStringOne > uuidStringTwo) return 1;   // integer
	if (uuidStringOne < uuidStringTwo) return -1;  // integer
	return 0; // integer (either 0, 1, or -1)
};

dojox.uuid.Uuid.setGenerator = function(/*Function?*/ generator){
	// summary:
	//		Sets the default generator, which will be used by the
	//		"new dojox.uuid.Uuid()" constructor if no parameters
	//		are passed in.
	// generator: A UUID generator function, such as dojox.uuid.generateTimeBasedUuid.
	dojox.uuid.assert(!generator || dojo.isFunction(generator));
	dojox.uuid.Uuid._ourGenerator = generator;
};

dojox.uuid.Uuid.getGenerator = function(){
	// summary:
	//		Returns the default generator.  See setGenerator().
	return dojox.uuid.Uuid._ourGenerator; // generator (A UUID generator, such as dojox.uuid.TimeBasedGenerator).
};

dojox.uuid.Uuid.prototype.toString = function(){
	// summary:
	//		This method returns a standard 36-character string representing
	//		the UUID, such as "3b12f1df-5232-4804-897e-917bf397618a".
	return this._uuidString; // string
};

dojox.uuid.Uuid.prototype.compare = function(/*dojox.uuid.Uuid*/ otherUuid){
	// summary:
	//		Compares this UUID to another UUID, and returns 0, 1, or -1.
	// description:
	//		This implementation is intended to match the sample implementation
	//		in IETF RFC 4122: http://www.ietf.org/rfc/rfc4122.txt
	// otherUuid: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	return dojox.uuid.Uuid.compare(this, otherUuid); // integer (either 0, 1, or -1)
};

dojox.uuid.Uuid.prototype.isEqual = function(/*dojox.uuid.Uuid*/ otherUuid){
	// summary:
	//		Returns true if this UUID is equal to the otherUuid, or false otherwise.
	// otherUuid: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	return (this.compare(otherUuid) == 0); // boolean
};

dojox.uuid.Uuid.prototype.isValid = function(){
	// summary:
	//		Returns true if the UUID was initialized with a valid value.
	return dojox.uuid.isValid(this);
};

dojox.uuid.Uuid.prototype.getVariant = function(){
	// summary:
	//		Returns a variant code that indicates what type of UUID this is.
	//		Returns one of the enumerated dojox.uuid.variant values.

	// example:
	//		var uuid = new dojox.uuid.Uuid("3b12f1df-5232-4804-897e-917bf397618a");
	//		var variant = uuid.getVariant();
	//		dojox.uuid.assert(variant == dojox.uuid.variant.DCE);
	// example:
	// "3b12f1df-5232-4804-897e-917bf397618a"
	//                     ^
	//                     |
	//         (variant "10__" == DCE)
	return dojox.uuid.getVariant(this);
};

dojox.uuid.Uuid.prototype.getVersion = function(){
	// summary:
	//		Returns a version number that indicates what type of UUID this is.
	//		Returns one of the enumerated dojox.uuid.version values.
	// example:
	//		var uuid = new dojox.uuid.Uuid("b4308fb0-86cd-11da-a72b-0800200c9a66");
	//		var version = uuid.getVersion();
	//		dojox.uuid.assert(version == dojox.uuid.version.TIME_BASED);
	// exceptions:
	//		Throws an Error if this is not a DCE Variant UUID.
	if(!this._versionNumber){
		this._versionNumber = dojox.uuid.getVersion(this);
	}
	return this._versionNumber; // dojox.uuid.version
};

dojox.uuid.Uuid.prototype.getNode = function(){
	// summary:
	//		If this is a version 1 UUID (a time-based UUID), getNode() returns a
	//		12-character string with the "node" or "pseudonode" portion of the UUID,
	//		which is the rightmost 12 characters.
	// exceptions:
	//		Throws an Error if this is not a version 1 UUID.
	if (!this._nodeString) {
		this._nodeString = dojox.uuid.getNode(this);
	}
	return this._nodeString; // String (a 12-character string, which will look something like "917bf397618a")
};

dojox.uuid.Uuid.prototype.getTimestamp = function(/*String?*/ returnType){
	// summary:
	//		If this is a version 1 UUID (a time-based UUID), this method returns
	//		the timestamp value encoded in the UUID.  The caller can ask for the
	//		timestamp to be returned either as a JavaScript Date object or as a
	//		15-character string of hex digits.
	// returnType: Any of these five values: "string", String, "hex", "date", Date
	// returns:
	//		Returns the timestamp value as a JavaScript Date object or a 15-character string of hex digits.
	// examples:
	//		var uuid = new dojox.uuid.Uuid("b4308fb0-86cd-11da-a72b-0800200c9a66");
	//		var date, string, hexString;
	//		date   = uuid.getTimestamp();         // returns a JavaScript Date
	//		date   = uuid.getTimestamp(Date);     //
	//		string = uuid.getTimestamp(String);   // "Mon, 16 Jan 2006 20:21:41 GMT"
	//		hexString = uuid.getTimestamp("hex"); // "1da86cdb4308fb0"
	// exceptions:
	//		Throws an Error if this is not a version 1 UUID.
	if(!returnType){returnType = null};
	switch(returnType){
		case "string":
		case String:
			return this.getTimestamp(Date).toUTCString(); // String (e.g. "Mon, 16 Jan 2006 20:21:41 GMT")
			break;
		case "hex":
			// Return a 15-character string of hex digits containing the
			// timestamp for this UUID, with the high-order bits first.
			if (!this._timestampAsHexString) {
				this._timestampAsHexString = dojox.uuid.getTimestamp(this, "hex");
			}
			return this._timestampAsHexString; // String (e.g. "1da86cdb4308fb0")
			break;
		case null: // no returnType was specified, so default to Date
		case "date":
		case Date:
			// Return a JavaScript Date object.
			if (!this._timestampAsDate) {
				this._timestampAsDate = dojox.uuid.getTimestamp(this, Date);
			}
			return this._timestampAsDate; // Date
			break;
		default:
			// we got passed something other than a valid returnType
			dojox.uuid.assert(false, "The getTimestamp() method dojox.uuid.Uuid was passed a bogus returnType: " + returnType);
			break;
	}
};
<|endoftext|>


<commit_before>const { darken } = require('postcss-js-mixins/lib/colorHelpers');
const { defer } = require('postcss-variables/lib/helpers');
const register = require('postcss-variables/lib/register');

let variables = {};

variables.unit = {
	default: 'rem',
	fontSize: 'rem',
	lineHeight: 'em'
};

variables.root = {
	fontSize: '62.5%'
};

variables.default = {
	radius: '3px',
	opacity: 0.2,
	duration: '0.2s',
	timing: 'ease-in-out',
	delay: '0s'
};

variables.width = {
	min: 0,
	max: '1280px'
};

variables.bumper = {
	enabled: true,
	padding: '6%'
};

variables.block = {
	margin: {
		bottom: '4rem'
	}
};

variables.grid = {
	margin: '5%',
	columns: 8,
	spaceless: false
};

variables.colors = {
	primary: '#349bb9',
	secondary: '#70c1b3',
	tertiary: '#f18f01',
	info: '#00f',
	success: '#008000',
	warning: '#f00',
	white: '#fff',
	black: '#000'
};

variables.colors.lightestGray = defer(darken, ['$colors.white', 4]);
variables.colors.lighterGray = defer(darken, ['$colors.white', 10]);
variables.colors.lightGray = defer(darken, ['$colors.white', 25]);
variables.colors.gray = defer(darken, ['$colors.white', 35]);
variables.colors.darkGray = defer(darken, ['$colors.white', 55]);
variables.colors.darkerGray = defer(darken, ['$colors.white', 65]);
variables.colors.darkestGray = defer(darken, ['$colors.white', 75]);

variables.colors.body = {
	background: '$colors.white'
};

variables.font = {
	color: '$colors.darkestGray',
	family: 'Arial, Helvetica, sans-serif',
	size: '1.6rem',
	weight: {
		normal: 'normal',
		bold: 'bold'
	},
	lineHeight: '1em'
};

variables.heading = {
	color: '$font.color',
	family: 'Tahoma, Geneva, sans-serif',
	weight: '$font.weight.bold',
	lineHeight: '1.4em',
	margin: {
		bottom: '2rem'
	}
};

variables.h1 = '3.6rem';
variables.h2 = '3.2rem';
variables.h3 = '2.8rem';
variables.h4 = '2.4rem';
variables.h5 = '2rem';
variables.h6 = '1.6rem';

variables.mark = {
	color: '$font.color',
	background: 'yellow'
};

variables.abbr = {
	underline: 'dotted'
};

variables.border = {
	color: '$colors.lightGray',
	style: 'solid',
	width: '1px'
};

variables.paragraph = {
	color: '$font.color',
	weight: '$font.weight.normal',
	lineHeight: '1.7em',
	margin: {
		bottom: '2rem'
	}
};

variables.figure = {
	border: {
		color: false,
		radius: false
	},
	padding: '$block.margin.bottom'
};

variables.figCaption = {
	color: '$colors.darkGray',
	style: 'italic',
	lineHeight: '$paragraph.lineHeight'
};

variables.link = {
	color: '$colors.primary',
	decoration: 'none'
};

variables.link.hover = {
	color: defer(darken, ['$link.color', 10]),
	decoration: 'none'
};

variables.link.active = {
	color: defer(darken, ['$link.color', 20])
};

variables.selection = {
	color: '$colors.white',
	background: '$link.color'
};

variables.small = {
	size: '0.8em'
};

variables.quote = {
	color: '$colors.darkestGray',
	family: 'Georgia, Times, serif',
	size: '2rem',
	style: 'italic',
	weight: 'normal',
	lineHeight: '1.4em',
	padding: {
		horizontal: '2em',
		vertical: '1em'
	}
};

variables.cite = {
	color: '$colors.gray',
	family: '$font.family',
	size: '1.8rem',
	style: 'normal',
	weight: 'normal',
	lineHeight: '1.2em',
	margin: {
		top: '1.4rem'
	},
	indicator: "'\\2014\\00a0'"
};

variables.rule = {
	color: '$colors.lightGray',
	height: '1px',
	style: 'solid',
	margin: {
		vertical: '$block.margin.bottom'
	}
};

variables.address = {
	color: '$colors.darkestGray',
	family: '$font.family',
	size: '$font.size',
	weight: 'normal',
	style: 'normal',
	lineHeight: '$paragraph.lineHeight'
};

variables.list = {
	color: '$paragraph.color',
	lineHeight: '$paragraph.lineHeight',
	margin: {
		bottom: '$paragraph.margin.bottom',
		left: false
	},
	bullet: {
		style: 'disc',
		position: 'inside'
	}
};

variables.nestedList = {
	margin: {
		left: '2rem'
	}
};

variables.li = {
	margin: {
		bottom: '0.2rem'
	}
};

variables.dl = {
	margin: {
		bottom: '$block.margin.bottom'
	}
};

variables.dt = {
	color: '$colors.darkerGray',
	family: '$heading.family',
	size: '2rem',
	margin: {
		bottom: '0.2rem'
	}
};

variables.dd = {
	color: '$colors.gray',
	family: '$font.family',
	size: '$font.size',
	margin: {
		bottom: '1rem'
	}
};

variables.print = {
	page: {
		margin: '2cm .5cm'
	}
};

variables.button = {
	color: '$colors.white',
	family: '$font.family',
	size: '$font.size',
	weight: 'normal',
	padding: {
		horizontal: '3rem',
		vertical: '1.3rem'
	},
	margin: {
		bottom: 0
	},
	transition: {
		property: 'background-color',
		duration: '0.2s'
	},
	background: '$colors.darkGray',
	border: {
		color: false,
		radius: '$default.radius',
		width: 0
	}
};

variables.button.hover = {
	background: defer(darken, ['$button.background', 5])
};

variables.button.active = {
	background: defer(darken, ['$button.background', 10]),
	transition: {
		property: 'none'
	}
};

variables.coloredButton = {
	class: '.colored-button',
	color: '$colors.white',
	background: '$link.color',
	border: {
		color: false,
		radius: '$button.border.radius',
		width: '$button.border.width'
	}
};

variables.coloredButton.hover = {
	background: defer(darken, ['$coloredButton.background', 5])
};

variables.coloredButton.active = {
	background: defer(darken, ['$coloredButton.background', 10])
};

variables.button.disabled = {
	modifier: '.-is-disabled',
	color: '$colors.darkGray',
	background: '$colors.lightGray',
	border: {
		color: false
	},
	cursor: 'not-allowed'
};

variables.code = {
	color: '$colors.darkestGray',
	family: 'monospace',
	size: '$font.size',
	lineHeight: '1.4em',
	background: '$colors.lighterGray',
	border: {
		color: false,
		radius: false
	},
	padding: {
		horizontal: '0.5em',
		vertical: '0.2em'
	}
};

variables.code.block = {
	color: '$colors.lightestGray',
	family: '$code.family',
	size: '1.3rem',
	lineHeight: '$paragraph.lineHeight',
	tabSize: 4,
	wrap: false,
	margin: {
		bottom: '$block.margin.bottom'
	},
	background: '$colors.darkestGray',
	border: {
		color: '$code.border.color',
		radius: false
	},
	padding: {
		horizontal: '2rem',
		vertical: '1.4rem'
	}
};

variables.input = {
	background: '$colors.white',
	color: '$colors.darkerGray',
	family: '$font.family',
	size: '$font.size',
	weight: '$font.weight',
	margin: {
		bottom: '2rem'
	},
	padding: {
		horizontal: '1.6rem',
		vertical: '1rem'
	}
};

variables.input.disabled = {
	background: '$colors.lightestGray',
	color: '$colors.darkerGray',
	cursor: 'not-allowed'
};

variables.input.invalid = {
	background: '$colors.white',
	color: defer(darken, ['$input.invalid.border.color', 10]),
	border: {
		color: '#a41818',
		width: '1px' // false to disable
	}
};

variables.input.invalid.focus = {
	border: {
		color: defer(darken, ['$input.invalid.border.color', 10])
	}
};

variables.input.invalid.hover = {
	border: {
		color: defer(darken, ['$input.invalid.border.color', 20])
	}
};

variables.input.required = {
	color: defer(darken, ['$input.required.border.color', 10]),
	border: {
		color: '$colors.darkerGray',
		width: '1px' // false to disable
	}
};

variables.legend = {
	color: '$colors.darkerGray',
	family: '$font.family',
	size: '1.8rem',
	margin: {
		bottom: '1.4rem'
	}
};

variables.label = {
	weight: 'normal',
	lineHeight: '1.3em',
	margin: {
		bottom: '.4rem',
		right: '1rem'
	}
};

variables.checkbox = {
	margin: {
		bottom: '1rem',
		right: '.5rem'
	}
};

variables.multiSelect = {
	minHeight: '8rem'
};

variables.textarea = {
	lineHeight: '1.3em',
	minHeight: '8rem',
	resize: 'vertical',
	padding: {
		horizontal: '1.6rem',
		vertical: '1rem'
	}
};

variables.table = {
	size: '$font.size',
	bordered : {
		modifier: '.-is-bordered'
	},
	caption: {
		background: '$colors.lightestGray',
		style: 'italic',
		padding: {
			horizontal: '$table.cell.padding.horizontal',
			vertical: '1.2rem'
		}
	},
	cell: {
		border: {
			color: '$colors.lighterGray'
		},
		lineHeight: '$paragraph.lineHeight',
		padding: {
			horizontal: '1.6rem',
			vertical: '.6rem'
		}
	},
	striped: {
		background: '$colors.lightestGray',
		modifier: '.-is-striped',
		position: 'odd'
	}
};

module.exports = register(variables);<commit_msg>Finish adding form variables<commit_after>const { darken, lighten } = require('postcss-js-mixins/lib/colorHelpers');
const { defer } = require('postcss-variables/lib/helpers');
const register = require('postcss-variables/lib/register');

let variables = {};

variables.unit = {
	default: 'rem',
	fontSize: 'rem',
	lineHeight: 'em'
};

variables.root = {
	fontSize: '62.5%'
};

variables.default = {
	radius: '3px',
	opacity: 0.2,
	duration: '0.2s',
	timing: 'ease-in-out',
	delay: '0s'
};

variables.width = {
	min: 0,
	max: '1280px'
};

variables.bumper = {
	enabled: true,
	padding: '6%'
};

variables.block = {
	margin: {
		bottom: '4rem'
	}
};

variables.grid = {
	margin: '5%',
	columns: 8,
	spaceless: false
};

variables.colors = {
	primary: '#349bb9',
	secondary: '#70c1b3',
	tertiary: '#f18f01',
	info: '#00f',
	success: '#008000',
	warning: '#f00',
	white: '#fff',
	lightestGray: defer(darken, ['$colors.white', 4]),
	lighterGray: defer(darken, ['$colors.white', 10]),
	lightGray: defer(darken, ['$colors.white', 25]),
	gray: defer(darken, ['$colors.white', 35]),
	darkGray: defer(darken, ['$colors.white', 55]),
	darkerGray: defer(darken, ['$colors.white', 65]),
	darkestGray: defer(darken, ['$colors.white', 75]),
	black: '#000'
};

variables.colors.body = {
	background: '$colors.white'
};

variables.font = {
	color: '$colors.darkestGray',
	family: 'Arial, Helvetica, sans-serif',
	size: '1.6rem',
	weight: {
		normal: 'normal',
		bold: 'bold'
	},
	lineHeight: '1em'
};

variables.heading = {
	color: '$font.color',
	family: 'Tahoma, Geneva, sans-serif',
	weight: '$font.weight.bold',
	lineHeight: '1.4em',
	margin: {
		bottom: '2rem'
	}
};

variables.h1 = '3.6rem';
variables.h2 = '3.2rem';
variables.h3 = '2.8rem';
variables.h4 = '2.4rem';
variables.h5 = '2rem';
variables.h6 = '1.6rem';

variables.mark = {
	color: '$font.color',
	background: 'yellow'
};

variables.abbr = {
	underline: 'dotted'
};

variables.border = {
	color: '$colors.lightGray',
	style: 'solid',
	width: '1px'
};

variables.paragraph = {
	color: '$font.color',
	weight: '$font.weight.normal',
	lineHeight: '1.7em',
	margin: {
		bottom: '2rem'
	}
};

variables.figure = {
	border: {
		color: false,
		radius: false
	},
	padding: '$block.margin.bottom'
};

variables.figCaption = {
	color: '$colors.darkGray',
	style: 'italic',
	lineHeight: '$paragraph.lineHeight'
};

variables.link = {
	color: '$colors.primary',
	decoration: 'none'
};

variables.link.hover = {
	color: defer(darken, ['$link.color', 10]),
	decoration: 'none'
};

variables.link.active = {
	color: defer(darken, ['$link.color', 20])
};

variables.selection = {
	color: '$colors.white',
	background: '$link.color'
};

variables.small = {
	size: '0.8em'
};

variables.quote = {
	color: '$colors.darkestGray',
	family: 'Georgia, Times, serif',
	size: '2rem',
	style: 'italic',
	weight: 'normal',
	lineHeight: '1.4em',
	padding: {
		horizontal: '2em',
		vertical: '1em'
	}
};

variables.cite = {
	color: '$colors.gray',
	family: '$font.family',
	size: '1.8rem',
	style: 'normal',
	weight: 'normal',
	lineHeight: '1.2em',
	margin: {
		top: '1.4rem'
	},
	indicator: "'\\2014\\00a0'"
};

variables.rule = {
	color: '$colors.lightGray',
	height: '1px',
	style: 'solid',
	margin: {
		vertical: '$block.margin.bottom'
	}
};

variables.address = {
	color: '$colors.darkestGray',
	family: '$font.family',
	size: '$font.size',
	weight: 'normal',
	style: 'normal',
	lineHeight: '$paragraph.lineHeight'
};

variables.list = {
	color: '$paragraph.color',
	lineHeight: '$paragraph.lineHeight',
	margin: {
		bottom: '$paragraph.margin.bottom',
		left: false
	},
	bullet: {
		style: 'disc',
		position: 'inside'
	}
};

variables.nestedList = {
	margin: {
		left: '2rem'
	}
};

variables.li = {
	margin: {
		bottom: '0.2rem'
	}
};

variables.dl = {
	margin: {
		bottom: '$block.margin.bottom'
	}
};

variables.dt = {
	color: '$colors.darkerGray',
	family: '$heading.family',
	size: '2rem',
	margin: {
		bottom: '0.2rem'
	}
};

variables.dd = {
	color: '$colors.gray',
	family: '$font.family',
	size: '$font.size',
	margin: {
		bottom: '1rem'
	}
};

variables.print = {
	page: {
		margin: '2cm .5cm'
	}
};

variables.button = {
	color: '$colors.white',
	family: '$font.family',
	size: '$font.size',
	weight: 'normal',
	padding: {
		horizontal: '3rem',
		vertical: '1.3rem'
	},
	margin: {
		bottom: 0
	},
	transition: {
		property: 'background-color',
		duration: '0.2s'
	},
	background: '$colors.darkGray',
	border: {
		color: false,
		radius: '$default.radius',
		width: 0
	}
};

variables.button.hover = {
	background: defer(darken, ['$button.background', 5])
};

variables.button.active = {
	background: defer(darken, ['$button.background', 10]),
	transition: {
		property: 'none'
	}
};

variables.coloredButton = {
	class: '.colored-button',
	color: '$colors.white',
	background: '$link.color',
	border: {
		color: false,
		radius: '$button.border.radius',
		width: '$button.border.width'
	}
};

variables.coloredButton.hover = {
	background: defer(darken, ['$coloredButton.background', 5])
};

variables.coloredButton.active = {
	background: defer(darken, ['$coloredButton.background', 10])
};

variables.button.disabled = {
	modifier: '.-disabled',
	color: '$colors.darkGray',
	background: '$colors.lightGray',
	border: {
		color: false
	},
	cursor: 'not-allowed'
};

variables.code = {
	color: '$colors.darkestGray',
	family: 'monospace',
	size: '$font.size',
	lineHeight: '1.4em',
	background: '$colors.lighterGray',
	border: {
		color: false,
		radius: false
	},
	padding: {
		horizontal: '0.5em',
		vertical: '0.2em'
	}
};

variables.code.block = {
	color: '$colors.lightestGray',
	family: '$code.family',
	size: '1.3rem',
	lineHeight: '$paragraph.lineHeight',
	tabSize: 4,
	wrap: false,
	margin: {
		bottom: '$block.margin.bottom'
	},
	background: '$colors.darkestGray',
	border: {
		color: '$code.border.color',
		radius: false
	},
	padding: {
		horizontal: '2rem',
		vertical: '1.4rem'
	}
};

variables.input = {
	background: '$colors.white',
	color: '$colors.darkerGray',
	family: '$font.family',
	minHeight: '3rem', // false to disable
	minWidth: '20rem', // false to disable
	size: '$font.size',
	weight: '$font.weight',
	border: {
		color: '$colors.lighterGray',
		radius: '$default.radius', // false to disable
		width: '1px'
	},
	margin: {
		bottom: '2rem'
	},
	padding: {
		horizontal: '1.6rem',
		vertical: '1rem'
	},
	placeholder: {
		color: defer(lighten, ['$input.color', 40])
	}
};

variables.input.hover = {
	border: {
		color: defer(darken, ['$input.border.color', 10])
	}
};

variables.input.focus = {
	border: {
		color: defer(darken, ['$input.border.color', 20])
	}
};

variables.input.invalid = {
	background: '$colors.white',
	color: defer(darken, ['$input.invalid.border.color', 10]),
	border: {
		color: '#a41818',
		width: '1px' // false to disable
	}
};

variables.input.invalid.hover = {
	border: {
		color: defer(darken, ['$input.invalid.border.color', 20])
	}
};

variables.input.invalid.focus = {
	border: {
		color: defer(darken, ['$input.invalid.border.color', 10])
	}
};

variables.input.required = {
	background: '$colors.white',
	color: defer(darken, ['$input.required.border.color', 10]),
	border: {
		color: '$colors.darkerGray',
		width: '1px' // false to disable
	}
};

variables.input.required.hover = {
	border: {
		color: defer(darken, ['$input.required.border.color', 20])
	}
};

variables.input.required.focus = {
	border: {
		color: defer(darken, ['$input.required.border.color', 10])
	}
};

variables.input.disabled = {
	background: '$colors.lightestGray',
	color: '$colors.darkerGray',
	cursor: 'not-allowed',
	border: {
		width: false // false to disable
	}
};

variables.multiSelect = {
	minHeight: '8rem'
};

variables.checkbox = {
	margin: {
		bottom: '1rem',
		right: '.5rem'
	}
};

variables.textarea = {
	lineHeight: '1.3em',
	minHeight: '8rem',
	resize: 'vertical',
	padding: {
		horizontal: '1.6rem',
		vertical: '1rem'
	}
};

variables.legend = {
	color: '$colors.darkerGray',
	family: '$font.family',
	size: '1.8rem',
	margin: {
		bottom: '1.4rem'
	}
};

variables.label = {
	weight: 'normal',
	lineHeight: '1.3em',
	margin: {
		bottom: '.4rem',
		right: '1rem'
	}
};

variables.table = {
	size: '$font.size',
	bordered : {
		modifier: '.-bordered'
	},
	caption: {
		background: '$colors.lightestGray',
		style: 'italic',
		padding: {
			horizontal: '$table.cell.padding.horizontal',
			vertical: '1.2rem'
		}
	},
	cell: {
		border: {
			color: '$colors.lighterGray'
		},
		lineHeight: '$paragraph.lineHeight',
		padding: {
			horizontal: '1.6rem',
			vertical: '.6rem'
		}
	},
	striped: {
		background: '$colors.lightestGray',
		modifier: '.-striped',
		position: 'odd'
	}
};

module.exports = register(variables);<|endoftext|>