<commit_before>var config = require(__dirname + '/../config/config'),
	mysql = require(__dirname + '/../lib/mysql'),
	mongo = require(__dirname + '/../lib/mongoskin'),
	util = require(__dirname + '/../helpers/util'),
	as_helper = require(__dirname + '/../helpers/auth_server');

exports.find_applicants = function(req, res, next){
    var data = {},
        stat,
        page = 1,
        size = 10,
		queryApplicants = "SELECT _id, user_id, linked_cms, channel_username, channel_name, network_id, " +
						"network_name, last30_days, total_views, total_comments, total_subscribers, " +
						"overall_goodstanding, created_at FROM channel WHERE partnership_status = 0 "+
						"ORDER BY created_at DESC LIMIT ?, ?;",
        query = function () {

            if (req.query.page && !isNaN(req.query.page)) {
                page = req.query.page;;
            }

			page = (page - 1) * 10;

            if (req.query.page && !isNaN(req.query.size)) {
                size = parseInt(req.query.size,10);

                if (size >= 100) {
                    size = 100;
                }
            }

            mysql.open(config.db_freedom)
                .query(queryApplicants, [page, size], function (err, result) {
                    if (err) return next(err);

                    res.send(200, result);
                })
				.end();
	}

    if (req.is_admin)
        as_helper.has_scopes(req.signedCookies.access_token, 'admin.view_all', query, next);
    else
		next("Unauthorized");
};

exports.accept_applicant = function (req, res, next) {
    var data = {},
    update = function () {
        mongo.collection('partnership')
            .update(
                {channel : req.body.id},
                {$set : {
                            "approver.admin.status" : true
                        }
                },
                {},
                send_response
			);
    },
    send_response = function (err, countModif) {
        if(err) return next(err);

        if(countModif > 0)
            check_all_approvs();
        else
			next("Admin acceptance failed");
    },
    check_all_approvs = function () {
        mongo.collection('partnership')
            .find({channel: req.body.id})
            .toArray(function (err, result) {
                if (err) return next(err);

                var approvers = result[0].approver;

                // check if all status are true
                for (var i in approvers){

                    //  if one of the status are false, other approvers haven't approved yet
                    if (approvers[i].status === false){
                        return res.send(200, {message: "admin"});
                    }
                }

                // all approvers have status  === true, now update SQL database;
                mysql.open(config.db_freedom)
                    .query("UPDATE channel SET partnership_status = 1 where _id = ?", [req.body.id], function (err, result){
                        if (err) return next(err);

                        res.send(200, {message: "all"});
                    })
                    .end();
            });
    };

    if (req.is_admin)
        as_helper.has_scopes(req.signedCookies.access_token, 'admin.add_all', update, next);
    else
		next("Unauthorized");
};
<commit_msg>done with requests<commit_after>var config = require(__dirname + '/../config/config'),
	mysql = require(__dirname + '/../lib/mysql'),
	mongo = require(__dirname + '/../lib/mongoskin'),
	util = require(__dirname + '/../helpers/util'),
	as_helper = require(__dirname + '/../helpers/auth_server');

exports.find_applicants = function(req, res, next){
    var data = {},
        stat,
        page = 1,
        size = 10,
		queryApplicants = "SELECT _id, user_id, linked_cms, channel_username, channel_name, network_id, \
						network_name, last30_days, total_views, total_comments, total_subscribers, \
						overall_goodstanding, created_at FROM channel WHERE partnership_status = 0 \
						ORDER BY created_at DESC LIMIT ?, ?;",
        query = function () {

            if (req.query.page && !isNaN(req.query.page)) {
                page = req.query.page;;
            }

			page = (page - 1) * 10;

            if (req.query.page && !isNaN(req.query.size)) {
                size = parseInt(req.query.size,10);

                if (size >= 100) {
                    size = 100;
                }
            }

            mysql.open(config.db_freedom)
                .query(queryApplicants, [page, size], function (err, result) {
                    if (err) return next(err);

                    res.send(200, result);
                })
				.end();
	}

    if (req.is_admin)
        as_helper.has_scopes(req.access_token, 'admin.view_all', query, next);
    else
		next("Unauthorized");
};

exports.accept_applicant = function (req, res, next) {
    var data = {},
	approvers,
	i,
    update = function () {
        mongo.collection('partnership')
            .update(
                {channel : req.body.id},
                {$set : {
                            "approver.admin.status" : true
                        }
                },
                {},
                send_response
			);
    },
    send_response = function (err, countModif) {
        if (err) return next(err);

        if (countModif > 0)
            check_all_approvs();
        else
			next("Admin acceptance failed");
    },
    check_all_approvs = function () {
        mongo.collection('partnership')
            .find({channel: req.body.id})
            .toArray(function (err, result) {
                if (err) return next(err);

                approvers = result[0].approver;

                // check if all status are true
                for (in approvers){

                    //  if one of the status are false, other approvers haven't approved yet
                    if (!approvers[i].status){
                        return res.send(200, {message: "admin"});
                    }
                }

                // all approvers have status  === true, now update SQL database;
                mysql.open(config.db_freedom)
                    .query("UPDATE channel SET partnership_status = 1 where _id = ?", [req.body.id], function (err, result){
                        if (err) return next(err);

                        res.send(200, {message: "all"});
                    })
                    .end();
            });
    };

    if (req.is_admin)
        as_helper.has_scopes(req.access_token, 'admin.add_all', update, next);
    else
		next("Unauthorized");
};
<|endoftext|>


<commit_before>/**
 * http://www.privacyidea.org
 * (c) cornelius kölbel, cornelius@privacyidea.org
 *
 * 2018-07-31 Friedrich Weber, <friedrich.weber@netknights.it>
 *
 * This code is free software; you can redistribute it and/or
 * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or any later version.
 *
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
myApp.controller("periodicTaskController", function($scope, $stateParams, $state,
                                             $location, ConfigFactory) {
    if ($location.path() === "/config/periodictasks") {
        $location.path("/config/periodictasks/list");
    }
    $('html,body').scrollTop(0);

    $scope.getPeriodicTasks = function () {
        ConfigFactory.getPeriodicTasks(function(data) {
            $scope.periodictasks = data.result.value;
        });
    };

    $scope.delPeriodicTask = function (ptaskid) {
        ConfigFactory.delPeriodicTask(ptaskid, function(data) {
            $scope.getPeriodicTasks();
            $state.go("config.periodictasks.list");
        });
    };

    $scope.enablePeriodicTask = function (ptaskid) {
        ConfigFactory.enablePeriodicTask(ptaskid, function () {
            $scope.getPeriodicTasks();
        });
    };

    $scope.disablePeriodicTask = function (ptaskid) {
        ConfigFactory.disablePeriodicTask(ptaskid, function () {
            $scope.getPeriodicTasks();
        });
    };
    $scope.orderChanged = function (ptask) {
        // we cannot directly pass ``ptask`` because we need to join the nodes list
        var params = {
            "id": ptask.id,
            "interval": ptask.interval,
            "name": ptask.name,
            "taskmodule": ptask.taskmodule,
            "nodes": ptask.nodes.join(", "),
            "ordering": ptask.ordering,
            "options": ptask.options,
        };
        ConfigFactory.setPeriodicTask(params, function() {
            $scope.getPeriodicTasks();
        });
    };

    // Get all tasks
    $scope.getPeriodicTasks();

    // listen to the reload broadcast
    $scope.$on("piReload", $scope.getPeriodicTasks);
});

myApp.controller("periodicTaskDetailController", function($scope, $stateParams, ConfigFactory, $state) {
    // init
    $scope.form = {
        "ordering": 0
    };
    $scope.ptaskid = $stateParams.ptaskid;
    $scope.opts = {};
    $('html,body').scrollTop(0);

    $scope.getAvailableNodes = function (cb) {
        ConfigFactory.getNodes(function(response) {
            // prepare the input model for the multi-select box
            $scope.availableNodes = [];
            angular.forEach(response.result.value, function (node) {
                $scope.availableNodes.push({
                    "name": node,
                    "ticked": false,
                });
            });
            cb();
        });
    }

    $scope.taskmoduleChanged = function () {
        $scope.getTaskmoduleOptions();
    }

    $scope.getTaskmoduleOptions = function () {
        ConfigFactory.getPeriodicTaskmoduleOptions($scope.form.taskmodule, function(response) {
            var taskmoduleOptions = response.result.value;
            $scope.taskmoduleOptions = taskmoduleOptions;
        });
    }

    $scope.getPeriodicTask = function () {
        ConfigFactory.getPeriodicTask($scope.ptaskid, function(response1) {
            var ptask = response1.result.value;
            $scope.form = ptask;
            // tick the appropriate nodes
            angular.forEach($scope.availableNodes, function (row) {
                row["ticked"] = ptask.nodes.indexOf(row.name) >= 0;
            });
            $scope.noLastRuns = angular.equals($scope.form.last_runs, {});
            $scope.getTaskmoduleOptions();
        });
    };
    $scope.getTaskModules = function () {
        ConfigFactory.getPeriodicTaskmodules(function(data) {
            $scope.taskmodules = data.result.value;
        });
    };

    $scope.createPeriodicTask = function () {
        // get list of nodes from multi-select box
        var nodes = [];
        angular.forEach($scope.selectedNodes, function(node) {
            if (node.ticked) {
                nodes.push(node.name);
            };
        });
        // filter options to only contain the current task module's options
        var options = {};
        angular.forEach($scope.form.options, function(value, key) {
            if ($scope.taskmoduleOptions.hasOwnProperty(key)) {
                options[key] = value;
            }
        });
        var params = {
            "interval": $scope.form.interval,
            "name": $scope.form.name,
            "taskmodule": $scope.form.taskmodule,
            "nodes": nodes.join(", "),
            "ordering": $scope.form.ordering,
            "options": options,
        };
        if ($scope.ptaskid) {
            params["id"] = $scope.ptaskid;
        }
        ConfigFactory.setPeriodicTask(params, function() {
            $state.go("config.periodictasks.list");
        });
        $('html,body').scrollTop(0);
    };

    $scope.enablePeriodicTask = function (ptaskid) {
        ConfigFactory.enablePeriodicTask(ptaskid, function () {
            $scope.getPeriodicTask();
        });
    };

    $scope.disablePeriodicTask = function (ptaskid) {
        ConfigFactory.disablePeriodicTask(ptaskid, function () {
            $scope.getPeriodicTask();
        });
    };

    $scope.getTaskModules();
    // ensure that the nodes are available before we fetch the task
    $scope.getAvailableNodes(function () {
        if ($scope.ptaskid) {
            $scope.getPeriodicTask();
        }
    });
});
<commit_msg>Fix bug in which editing periodic tasks would activate them<commit_after>/**
 * http://www.privacyidea.org
 * (c) cornelius kölbel, cornelius@privacyidea.org
 *
 * 2018-07-31 Friedrich Weber, <friedrich.weber@netknights.it>
 *
 * This code is free software; you can redistribute it and/or
 * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or any later version.
 *
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
myApp.controller("periodicTaskController", function($scope, $stateParams, $state,
                                             $location, ConfigFactory) {
    if ($location.path() === "/config/periodictasks") {
        $location.path("/config/periodictasks/list");
    }
    $('html,body').scrollTop(0);

    $scope.getPeriodicTasks = function () {
        ConfigFactory.getPeriodicTasks(function(data) {
            $scope.periodictasks = data.result.value;
        });
    };

    $scope.delPeriodicTask = function (ptaskid) {
        ConfigFactory.delPeriodicTask(ptaskid, function(data) {
            $scope.getPeriodicTasks();
            $state.go("config.periodictasks.list");
        });
    };

    $scope.enablePeriodicTask = function (ptaskid) {
        ConfigFactory.enablePeriodicTask(ptaskid, function () {
            $scope.getPeriodicTasks();
        });
    };

    $scope.disablePeriodicTask = function (ptaskid) {
        ConfigFactory.disablePeriodicTask(ptaskid, function () {
            $scope.getPeriodicTasks();
        });
    };
    $scope.orderChanged = function (ptask) {
        // we cannot directly pass ``ptask`` because we need to join the nodes list
        var params = {
            "id": ptask.id,
            "active": ptask.active,
            "interval": ptask.interval,
            "name": ptask.name,
            "taskmodule": ptask.taskmodule,
            "nodes": ptask.nodes.join(", "),
            "ordering": ptask.ordering,
            "options": ptask.options,
        };
        ConfigFactory.setPeriodicTask(params, function() {
            $scope.getPeriodicTasks();
        });
    };

    // Get all tasks
    $scope.getPeriodicTasks();

    // listen to the reload broadcast
    $scope.$on("piReload", $scope.getPeriodicTasks);
});

myApp.controller("periodicTaskDetailController", function($scope, $stateParams, ConfigFactory, $state) {
    // init
    $scope.form = {
        "ordering": 0
    };
    $scope.ptaskid = $stateParams.ptaskid;
    $scope.opts = {};
    $('html,body').scrollTop(0);

    $scope.getAvailableNodes = function (cb) {
        ConfigFactory.getNodes(function(response) {
            // prepare the input model for the multi-select box
            $scope.availableNodes = [];
            angular.forEach(response.result.value, function (node) {
                $scope.availableNodes.push({
                    "name": node,
                    "ticked": false,
                });
            });
            cb();
        });
    }

    $scope.taskmoduleChanged = function () {
        $scope.getTaskmoduleOptions();
    }

    $scope.getTaskmoduleOptions = function () {
        ConfigFactory.getPeriodicTaskmoduleOptions($scope.form.taskmodule, function(response) {
            var taskmoduleOptions = response.result.value;
            $scope.taskmoduleOptions = taskmoduleOptions;
        });
    }

    $scope.getPeriodicTask = function () {
        ConfigFactory.getPeriodicTask($scope.ptaskid, function(response1) {
            var ptask = response1.result.value;
            $scope.form = ptask;
            // tick the appropriate nodes
            angular.forEach($scope.availableNodes, function (row) {
                row["ticked"] = ptask.nodes.indexOf(row.name) >= 0;
            });
            $scope.noLastRuns = angular.equals($scope.form.last_runs, {});
            $scope.getTaskmoduleOptions();
        });
    };
    $scope.getTaskModules = function () {
        ConfigFactory.getPeriodicTaskmodules(function(data) {
            $scope.taskmodules = data.result.value;
        });
    };

    $scope.createPeriodicTask = function () {
        // get list of nodes from multi-select box
        var nodes = [];
        angular.forEach($scope.selectedNodes, function(node) {
            if (node.ticked) {
                nodes.push(node.name);
            };
        });
        // filter options to only contain the current task module's options
        var options = {};
        angular.forEach($scope.form.options, function(value, key) {
            if ($scope.taskmoduleOptions.hasOwnProperty(key)) {
                options[key] = value;
            }
        });
        var params = {
            "interval": $scope.form.interval,
            "active": $scope.form.active,
            "name": $scope.form.name,
            "taskmodule": $scope.form.taskmodule,
            "nodes": nodes.join(", "),
            "ordering": $scope.form.ordering,
            "options": options,
        };
        if ($scope.ptaskid) {
            params["id"] = $scope.ptaskid;
        }
        ConfigFactory.setPeriodicTask(params, function() {
            $state.go("config.periodictasks.list");
        });
        $('html,body').scrollTop(0);
    };

    $scope.enablePeriodicTask = function (ptaskid) {
        ConfigFactory.enablePeriodicTask(ptaskid, function () {
            $scope.getPeriodicTask();
        });
    };

    $scope.disablePeriodicTask = function (ptaskid) {
        ConfigFactory.disablePeriodicTask(ptaskid, function () {
            $scope.getPeriodicTask();
        });
    };

    $scope.getTaskModules();
    // ensure that the nodes are available before we fetch the task
    $scope.getAvailableNodes(function () {
        if ($scope.ptaskid) {
            $scope.getPeriodicTask();
        }
    });
});
<|endoftext|>


<commit_before>(function(root, factory) {
  if (typeof define === "function" && define.amd) {
    // AMD
    define([], factory);
  } else if (typeof exports === "object") {
    // CommonJS
    module.exports = factory();
  } else {
    // Browser globals
    root.IncrementalIndexedDBAdapter = factory();
  }
})(this, function() {
  return (function() {
    "use strict";

    /**
     * An improved Loki persistence adapter for IndexedDB (not compatible with LokiIndexedAdapter)
     *     Unlike LokiIndexedAdapter, the database is saved not as one big JSON blob, but split into
     *     small chunks with individual collection documents. When saving, only the chunks with changed
     *     documents (and database metadata) is saved to IndexedDB. This speeds up small incremental
     *     saves by an order of magnitude on large (tens of thousands of records) databases. It also
     *     avoids Safari 13 bug that would cause the database to balloon in size to gigabytes
     *
     *     The `appname` argument is not provided - to distinguish between multiple app on the same
     *     domain, simply use a different Loki database name
     *
     * @example
     * var adapter = new IncrementalIndexedDBAdapter();
     *
     * @constructor IncrementalIndexedDBAdapter
     *
     * @param {object=} options Configuration options for the adapter
     * @param {boolean} options.onversionchange Function to call on `IDBDatabase.onversionchange` event
     *     (most likely database deleted from another browser tab)
     */
    function IncrementalIndexedDBAdapter(options) {
      this.mode = "incremental";
      this.options = options || {};
      this.chunkSize = 100;
      this.idb = null; // will be lazily loaded on first operation that needs it
    }

    // chunkId - index of the data chunk - e.g. chunk 0 will be lokiIds 0-99
    IncrementalIndexedDBAdapter.prototype._getChunk = function(collection, chunkId) {
      // 0-99, 100-199, etc.
      var minId = chunkId * this.chunkSize;
      var maxId = minId + this.chunkSize - 1;

      // use idIndex to find first collection.data position within the $loki range
      var idIndex = collection.idIndex;

      var firstDataPosition = null;

      var max = idIndex.length - 1,
        min = 0,
        mid;

      while (idIndex[min] < idIndex[max]) {
        mid = (min + max) >> 1;

        if (idIndex[mid] < minId) {
          min = mid + 1;
        } else {
          max = mid;
        }
      }

      if (max === min && idIndex[min] >= minId) {
        firstDataPosition = min;
      }

      if (firstDataPosition === null) {
        // no elements in this chunk
        return [];
      }

      // find last position
      // if loki IDs are contiguous (no removed elements), last position will be first + chunk - 1
      // (and we look back in case there are missing pieces)
      // TODO: Binary search (not as important as first position, worst case scanario is only chunkSize steps)
      var lastDataPosition = null;
      for (var i = firstDataPosition + this.chunkSize - 1; i >= firstDataPosition; i--) {
        if (idIndex[i] <= maxId) {
          lastDataPosition = i;
          break;
        }
      }

      // TODO: remove sanity checks when everything is fully tested
      var firstElement = collection.data[firstDataPosition];
      if (!(firstElement && firstElement.$loki >= minId && firstElement.$loki <= maxId)) {
        throw new Error("broken invariant firstelement");
      }

      var lastElement = collection.data[lastDataPosition];
      if (!(lastElement && lastElement.$loki >= minId && lastElement.$loki <= maxId)) {
        throw new Error("broken invariant lastElement");
      }

      // this will have *up to* 'this.chunkSize' elements (might have less, because $loki ids
      // will have holes when data is deleted)
      var chunkData = collection.data.slice(firstDataPosition, lastDataPosition + 1);

      // TODO: remove sanity checks when everything is fully tested
      if (chunkData.length > this.chunkSize) {
        throw new Error("broken invariant - chunk size");
      }

      return chunkData;
    };

    /**
     * Incrementally saves the database to IndexedDB
     *
     * @example
     * var idbAdapter = new IncrementalIndexedDBAdapter();
     * var db = new loki('test', { adapter: idbAdapter });
     * var coll = db.addCollection('testColl');
     * coll.insert({test: 'val'});
     * db.saveDatabase();
     *
     * @param {string} dbname - the name to give the serialized database
     * @param {object} dbcopy - copy of the Loki database
     * @param {function} callback - (Optional) callback passed obj.success with true or false
     * @memberof IncrementalIndexedDBAdapter
     */
    IncrementalIndexedDBAdapter.prototype.saveDatabase = function(dbname, loki, callback) {
      var that = this;
      console.log("exportDatabase - begin");
      console.time("exportDatabase");

      var chunksToSave = [];

      loki.collections.forEach(function(collection, i) {
        // Find dirty chunk ids
        var dirtyChunks = new Set();
        collection.dirtyIds.forEach(function(lokiId) {
          var chunkId = (lokiId / that.chunkSize) | 0;
          dirtyChunks.add(chunkId);
        });
        collection.dirtyIds = [];

        // Serialize chunks to save
        dirtyChunks.forEach(function(chunkId) {
          var chunkData = that._getChunk(collection, chunkId);
          // we must stringify now, because IDB is asynchronous, and underlying objects are mutable
          chunksToSave.push({
            key: collection.name + ".chunk." + chunkId,
            value: JSON.stringify(chunkData),
          });
        });

        collection.data = [];
        // this is recreated on load anyway, so we can make metadata smaller
        collection.isIndex = [];

        // save collection metadata as separate chunk, leave only names in loki
        // TODO: To reduce IO, we should only save this chunk when it has changed
        chunksToSave.push({
          key: collection.name + ".metadata",
          value: JSON.stringify(collection),
        });
        loki.collections[i] = { name: collection.name };
      });

      var serializedMetadata = JSON.stringify(loki);
      loki = null; // allow GC of the DB copy

      chunksToSave.push({ key: "loki", value: serializedMetadata });

      that._saveChunks(dbname, chunksToSave, callback);
    };

    /**
     * Retrieves a serialized db string from the catalog.
     *
     * @example
     * // LOAD
     * var idbAdapter = new IncrementalIndexedDBAdapter();
     * var db = new loki('test', { adapter: idbAdapter });
     * db.loadDatabase(function(result) {
     *   console.log('done');
     * });
     *
     * @param {string} dbname - the name of the database to retrieve.
     * @param {function} callback - callback should accept string param containing serialized db string.
     * @memberof IncrementalIndexedDBAdapter
     */
    IncrementalIndexedDBAdapter.prototype.loadDatabase = function(dbname, callback) {
      var that = this;
      console.log("loadDatabase - begin");
      console.time("loadDatabase");
      this._getAllChunks(dbname, function(chunks) {
        if (!Array.isArray(chunks)) {
          // we got an error
          console.timeEnd("loadDatabase");
          callback(chunks);
        }

        if (!chunks.length) {
          console.timeEnd("loadDatabase");
          callback(null);
          return;
        }

        console.log("Found chunks:", chunks.length);

        that._sortChunksInPlace(chunks);

        // repack chunks into a map
        var loki;
        var chunkCollections = {};

        chunks.forEach(function(object) {
          var key = object.key;
          var value = object.value;
          if (key === "loki") {
            loki = value;
            return;
          } else if (key.includes(".")) {
            var keySegments = key.split(".");
            if (keySegments.length === 3 && keySegments[1] === "chunk") {
              var colName = keySegments[0];
              if (chunkCollections[colName]) {
                chunkCollections[colName].dataChunks.push(value);
              } else {
                chunkCollections[colName] = {
                  metadata: null,
                  dataChunks: [value],
                };
              }
              return;
            } else if (keySegments.length === 2 && keySegments[1] === "metadata") {
              var name = keySegments[0];
              if (chunkCollections[name]) {
                chunkCollections[name].metadata = value;
              } else {
                chunkCollections[name] = { metadata: value, dataChunks: [] };
              }
              return;
            }
          }

          console.error("Unknown chunk " + key);
          callback(new Error("Invalid database - unknown chunk found"));
        });
        chunks = null;

        if (!loki) {
          callback(new Error("Invalid database - missing database metadata"));
        }

        // parse Loki object
        loki = JSON.parse(loki);

        // populate collections with data
        that._populate(loki, chunkCollections);
        chunkCollections = null;

        console.timeEnd("loadDatabase");
        callback(loki);
      });
    };

    IncrementalIndexedDBAdapter.prototype._sortChunksInPlace = function(chunks) {
      // sort chunks in place to load data in the right order (ascending loki ids)
      // on both Safari and Chrome, we'll get chunks in order like this: 0, 1, 10, 100...
      var getSortKey = function(object) {
        var key = object.key;
        if (key.includes(".")) {
          var segments = key.split(".");
          if (segments.length === 3 && segments[1] === "chunk") {
            return parseInt(segments[2], 10);
          }
        }

        return -1; // consistent type must be returned
      };
      chunks.sort(function(a, b) {
        var aKey = getSortKey(a),
          bKey = getSortKey(b);
        if (aKey < bKey) return -1;
        if (aKey > bKey) return 1;
        return 0;
      });
    };

    IncrementalIndexedDBAdapter.prototype._populate = function(loki, chunkCollections) {
      loki.collections.forEach(function(collectionStub, i) {
        var chunkCollection = chunkCollections[collectionStub.name];

        if (chunkCollection) {
          // TODO: What if metadata is missing?
          var collection = JSON.parse(chunkCollection.metadata);
          chunkCollection.metadata = null;

          loki.collections[i] = collection;

          var dataChunks = chunkCollection.dataChunks;
          dataChunks.forEach(function(chunkObj, i) {
            var chunk = JSON.parse(chunkObj);
            chunkObj = null; // make string available for GC
            dataChunks[i] = null;

            chunk.forEach(function(doc) {
              collection.data.push(doc);
            });
          });
        }
      });
    };

    IncrementalIndexedDBAdapter.prototype._initializeIDB = function(dbname, onError, onSuccess) {
      var that = this;
      console.log("initializing idb");

      if (this.idbInitInProgress) {
        throw new Error("Cannot open IndexedDB because open is already in progress");
      }
      this.idbInitInProgress = true;

      var openRequest = indexedDB.open(dbname, 1);

      openRequest.onupgradeneeded = function(e) {
        var db = e.target.result;
        console.log('onupgradeneeded, old version: ' + e.oldVersion);

        if (e.oldVersion < 1) {
          // Version 1 - Initial - Create database
          db.createObjectStore('LokiIncrementalData', { keyPath: "key" });
        } else {
          // Unknown version
          throw new Error("Invalid old version " + e.oldVersion + " for IndexedDB upgrade");
        }
      };

      openRequest.onsuccess = function(e) {
        that.idbInitInProgress = false;
        that.idb = e.target.result;

        if (!that.idb.objectStoreNames.contains('LokiIncrementalData')) {
          onError(new Error("Missing LokiIncrementalData"));
          // Attempt to recover (after reload) by deleting database, since it's damaged anyway
          that.deleteDatabase(dbname);
          return;
        }

        console.log("init success");

        that.idb.onversionchange = function(versionChangeEvent) {
          console.log('IDB version change', versionChangeEvent);
          // This function will be called if another connection changed DB version
          // (Most likely database was deleted from another browser tab, unless there's a new version
          // of this adapter, or someone makes a connection to IDB outside of this adapter)
          // We must close the database to avoid blocking concurrent deletes.
          // The database will be unusable after this. Be sure to supply `onversionchange` option
          // to force logout
          that.idb.close();
          if (that.options.onversionchange) {
            that.options.onversionchange(versionChangeEvent);
          }
        };

        onSuccess();
      };

      openRequest.onblocked = function(e) {
        console.error("IndexedDB open is blocked", e);
        onError(new Error("IndexedDB open is blocked by open connection"));
      };

      openRequest.onerror = function(e) {
        that.idbInitInProgress = false;
        console.error("IndexeddB open error", e);
        onError(e);
      };
    };

    IncrementalIndexedDBAdapter.prototype._saveChunks = function(dbname, chunks, callback) {
      var that = this;
      if (!this.idb) {
        this._initializeIDB(dbname, callback, function() {
          that._saveChunks(dbname, chunks, callback);
        });
        return;
      }

      if (this.operationInProgress) {
        throw new Error("Error while saving to database - another operation is already in progress. Please use throttledSaves=true option on Loki object");
      }

      this.operationInProgress = true;

      var tx = this.idb.transaction(['LokiIncrementalData'], "readwrite");
      tx.oncomplete = function() {
        that.operationInProgress = false;
        console.timeEnd("exportDatabase");
        callback();
      };

      tx.onerror = function(e) {
        that.operationInProgress = false;
        callback(e);
      };

      tx.onabort = function(e) {
        that.operationInProgress = false;
        callback(e);
      };

      var store = tx.objectStore('LokiIncrementalData');

      chunks.forEach(function(object) {
        store.put(object);
      });
    };

    IncrementalIndexedDBAdapter.prototype._getAllChunks = function(dbname, callback) {
      var that = this;
      if (!this.idb) {
        this._initializeIDB(dbname, callback, function() {
          that._getAllChunks(dbname, callback);
        });
        return;
      }

      if (this.operationInProgress) {
        throw new Error("Error while loading database - another operation is already in progress. Please use throttledSaves=true option on Loki object");
      }

      this.operationInProgress = true;

      var tx = this.idb.transaction(['LokiIncrementalData'], "readonly");

      var request = tx.objectStore('LokiIncrementalData').getAll();
      request.onsuccess = function(e) {
        that.operationInProgress = false;
        var chunks = e.target.result;
        callback(chunks);
      };

      request.onerror = function(e) {
        that.operationInProgress = false;
        callback(e);
      };
    };

    /**
     * Deletes a database from IndexedDB
     *
     * @example
     * // DELETE DATABASE
     * // delete 'finance'/'test' value from catalog
     * idbAdapter.deleteDatabase('test', function {
     *   // database deleted
     * });
     *
     * @param {string} dbname - the name of the database to delete from IDB
     * @param {function=} callback - (Optional) executed on database delete
     * @memberof IncrementalIndexedDBAdapter
     */
    IncrementalIndexedDBAdapter.prototype.deleteDatabase = function(dbname, callback) {
      if (this.operationInProgress) {
        throw new Error("Error while deleting database - another operation is already in progress. Please use throttledSaves=true option on Loki object");
      }

      this.operationInProgress = true;

      var that = this;
      console.log("deleteDatabase - begin");
      console.time("deleteDatabase");

      if (this.idb) {
        this.idb.close();
        this.idb = null;
      }

      var request = indexedDB.deleteDatabase(dbname);

      request.onsuccess = function() {
        that.operationInProgress = false;
        console.timeEnd("deleteDatabase");
        callback({ success: true });
      };

      request.onerror = function(e) {
        that.operationInProgress = false;
        console.error("Error while deleting database", e);
        callback({ success: false });
      };

      request.onblocked = function(e) {
        // We can't call callback with failure status, because this will be called even if we
        // succeed in just a moment
        console.error("Deleting database failed because it's blocked by another connection", e);
      };
    };

    return IncrementalIndexedDBAdapter;
  })();
});
<commit_msg>Fix _getChunk when chunk is empty but next one is not<commit_after>(function(root, factory) {
  if (typeof define === "function" && define.amd) {
    // AMD
    define([], factory);
  } else if (typeof exports === "object") {
    // CommonJS
    module.exports = factory();
  } else {
    // Browser globals
    root.IncrementalIndexedDBAdapter = factory();
  }
})(this, function() {
  return (function() {
    "use strict";

    /**
     * An improved Loki persistence adapter for IndexedDB (not compatible with LokiIndexedAdapter)
     *     Unlike LokiIndexedAdapter, the database is saved not as one big JSON blob, but split into
     *     small chunks with individual collection documents. When saving, only the chunks with changed
     *     documents (and database metadata) is saved to IndexedDB. This speeds up small incremental
     *     saves by an order of magnitude on large (tens of thousands of records) databases. It also
     *     avoids Safari 13 bug that would cause the database to balloon in size to gigabytes
     *
     *     The `appname` argument is not provided - to distinguish between multiple app on the same
     *     domain, simply use a different Loki database name
     *
     * @example
     * var adapter = new IncrementalIndexedDBAdapter();
     *
     * @constructor IncrementalIndexedDBAdapter
     *
     * @param {object=} options Configuration options for the adapter
     * @param {boolean} options.onversionchange Function to call on `IDBDatabase.onversionchange` event
     *     (most likely database deleted from another browser tab)
     */
    function IncrementalIndexedDBAdapter(options) {
      this.mode = "incremental";
      this.options = options || {};
      this.chunkSize = 100;
      this.idb = null; // will be lazily loaded on first operation that needs it
    }

    // chunkId - index of the data chunk - e.g. chunk 0 will be lokiIds 0-99
    IncrementalIndexedDBAdapter.prototype._getChunk = function(collection, chunkId) {
      // 0-99, 100-199, etc.
      var minId = chunkId * this.chunkSize;
      var maxId = minId + this.chunkSize - 1;

      // use idIndex to find first collection.data position within the $loki range
      var idIndex = collection.idIndex;

      var firstDataPosition = null;

      var max = idIndex.length - 1,
        min = 0,
        mid;

      while (idIndex[min] < idIndex[max]) {
        mid = (min + max) >> 1;

        if (idIndex[mid] < minId) {
          min = mid + 1;
        } else {
          max = mid;
        }
      }

      if (max === min && idIndex[min] >= minId && idIndex[min] <= minId) {
        firstDataPosition = min;
      }

      if (firstDataPosition === null) {
        // no elements in this chunk
        return [];
      }

      // find last position
      // if loki IDs are contiguous (no removed elements), last position will be first + chunk - 1
      // (and we look back in case there are missing pieces)
      // TODO: Binary search (not as important as first position, worst case scanario is only chunkSize steps)
      var lastDataPosition = null;
      for (var i = firstDataPosition + this.chunkSize - 1; i >= firstDataPosition; i--) {
        if (idIndex[i] <= maxId) {
          lastDataPosition = i;
          break;
        }
      }

      // TODO: remove sanity checks when everything is fully tested
      var firstElement = collection.data[firstDataPosition];
      if (!(firstElement && firstElement.$loki >= minId && firstElement.$loki <= maxId)) {
        throw new Error("broken invariant firstelement");
      }

      var lastElement = collection.data[lastDataPosition];
      if (!(lastElement && lastElement.$loki >= minId && lastElement.$loki <= maxId)) {
        throw new Error("broken invariant lastElement");
      }

      // this will have *up to* 'this.chunkSize' elements (might have less, because $loki ids
      // will have holes when data is deleted)
      var chunkData = collection.data.slice(firstDataPosition, lastDataPosition + 1);

      // TODO: remove sanity checks when everything is fully tested
      if (chunkData.length > this.chunkSize) {
        throw new Error("broken invariant - chunk size");
      }

      return chunkData;
    };

    /**
     * Incrementally saves the database to IndexedDB
     *
     * @example
     * var idbAdapter = new IncrementalIndexedDBAdapter();
     * var db = new loki('test', { adapter: idbAdapter });
     * var coll = db.addCollection('testColl');
     * coll.insert({test: 'val'});
     * db.saveDatabase();
     *
     * @param {string} dbname - the name to give the serialized database
     * @param {object} dbcopy - copy of the Loki database
     * @param {function} callback - (Optional) callback passed obj.success with true or false
     * @memberof IncrementalIndexedDBAdapter
     */
    IncrementalIndexedDBAdapter.prototype.saveDatabase = function(dbname, loki, callback) {
      var that = this;
      console.log("exportDatabase - begin");
      console.time("exportDatabase");

      var chunksToSave = [];

      loki.collections.forEach(function(collection, i) {
        // Find dirty chunk ids
        var dirtyChunks = new Set();
        collection.dirtyIds.forEach(function(lokiId) {
          var chunkId = (lokiId / that.chunkSize) | 0;
          dirtyChunks.add(chunkId);
        });
        collection.dirtyIds = [];

        // Serialize chunks to save
        dirtyChunks.forEach(function(chunkId) {
          var chunkData = that._getChunk(collection, chunkId);
          // we must stringify now, because IDB is asynchronous, and underlying objects are mutable
          chunksToSave.push({
            key: collection.name + ".chunk." + chunkId,
            value: JSON.stringify(chunkData),
          });
        });

        collection.data = [];
        // this is recreated on load anyway, so we can make metadata smaller
        collection.isIndex = [];

        // save collection metadata as separate chunk, leave only names in loki
        // TODO: To reduce IO, we should only save this chunk when it has changed
        chunksToSave.push({
          key: collection.name + ".metadata",
          value: JSON.stringify(collection),
        });
        loki.collections[i] = { name: collection.name };
      });

      var serializedMetadata = JSON.stringify(loki);
      loki = null; // allow GC of the DB copy

      chunksToSave.push({ key: "loki", value: serializedMetadata });

      that._saveChunks(dbname, chunksToSave, callback);
    };

    /**
     * Retrieves a serialized db string from the catalog.
     *
     * @example
     * // LOAD
     * var idbAdapter = new IncrementalIndexedDBAdapter();
     * var db = new loki('test', { adapter: idbAdapter });
     * db.loadDatabase(function(result) {
     *   console.log('done');
     * });
     *
     * @param {string} dbname - the name of the database to retrieve.
     * @param {function} callback - callback should accept string param containing serialized db string.
     * @memberof IncrementalIndexedDBAdapter
     */
    IncrementalIndexedDBAdapter.prototype.loadDatabase = function(dbname, callback) {
      var that = this;
      console.log("loadDatabase - begin");
      console.time("loadDatabase");
      this._getAllChunks(dbname, function(chunks) {
        if (!Array.isArray(chunks)) {
          // we got an error
          console.timeEnd("loadDatabase");
          callback(chunks);
        }

        if (!chunks.length) {
          console.timeEnd("loadDatabase");
          callback(null);
          return;
        }

        console.log("Found chunks:", chunks.length);

        that._sortChunksInPlace(chunks);

        // repack chunks into a map
        var loki;
        var chunkCollections = {};

        chunks.forEach(function(object) {
          var key = object.key;
          var value = object.value;
          if (key === "loki") {
            loki = value;
            return;
          } else if (key.includes(".")) {
            var keySegments = key.split(".");
            if (keySegments.length === 3 && keySegments[1] === "chunk") {
              var colName = keySegments[0];
              if (chunkCollections[colName]) {
                chunkCollections[colName].dataChunks.push(value);
              } else {
                chunkCollections[colName] = {
                  metadata: null,
                  dataChunks: [value],
                };
              }
              return;
            } else if (keySegments.length === 2 && keySegments[1] === "metadata") {
              var name = keySegments[0];
              if (chunkCollections[name]) {
                chunkCollections[name].metadata = value;
              } else {
                chunkCollections[name] = { metadata: value, dataChunks: [] };
              }
              return;
            }
          }

          console.error("Unknown chunk " + key);
          callback(new Error("Invalid database - unknown chunk found"));
        });
        chunks = null;

        if (!loki) {
          callback(new Error("Invalid database - missing database metadata"));
        }

        // parse Loki object
        loki = JSON.parse(loki);

        // populate collections with data
        that._populate(loki, chunkCollections);
        chunkCollections = null;

        console.timeEnd("loadDatabase");
        callback(loki);
      });
    };

    IncrementalIndexedDBAdapter.prototype._sortChunksInPlace = function(chunks) {
      // sort chunks in place to load data in the right order (ascending loki ids)
      // on both Safari and Chrome, we'll get chunks in order like this: 0, 1, 10, 100...
      var getSortKey = function(object) {
        var key = object.key;
        if (key.includes(".")) {
          var segments = key.split(".");
          if (segments.length === 3 && segments[1] === "chunk") {
            return parseInt(segments[2], 10);
          }
        }

        return -1; // consistent type must be returned
      };
      chunks.sort(function(a, b) {
        var aKey = getSortKey(a),
          bKey = getSortKey(b);
        if (aKey < bKey) return -1;
        if (aKey > bKey) return 1;
        return 0;
      });
    };

    IncrementalIndexedDBAdapter.prototype._populate = function(loki, chunkCollections) {
      loki.collections.forEach(function(collectionStub, i) {
        var chunkCollection = chunkCollections[collectionStub.name];

        if (chunkCollection) {
          // TODO: What if metadata is missing?
          var collection = JSON.parse(chunkCollection.metadata);
          chunkCollection.metadata = null;

          loki.collections[i] = collection;

          var dataChunks = chunkCollection.dataChunks;
          dataChunks.forEach(function(chunkObj, i) {
            var chunk = JSON.parse(chunkObj);
            chunkObj = null; // make string available for GC
            dataChunks[i] = null;

            chunk.forEach(function(doc) {
              collection.data.push(doc);
            });
          });
        }
      });
    };

    IncrementalIndexedDBAdapter.prototype._initializeIDB = function(dbname, onError, onSuccess) {
      var that = this;
      console.log("initializing idb");

      if (this.idbInitInProgress) {
        throw new Error("Cannot open IndexedDB because open is already in progress");
      }
      this.idbInitInProgress = true;

      var openRequest = indexedDB.open(dbname, 1);

      openRequest.onupgradeneeded = function(e) {
        var db = e.target.result;
        console.log('onupgradeneeded, old version: ' + e.oldVersion);

        if (e.oldVersion < 1) {
          // Version 1 - Initial - Create database
          db.createObjectStore('LokiIncrementalData', { keyPath: "key" });
        } else {
          // Unknown version
          throw new Error("Invalid old version " + e.oldVersion + " for IndexedDB upgrade");
        }
      };

      openRequest.onsuccess = function(e) {
        that.idbInitInProgress = false;
        that.idb = e.target.result;

        if (!that.idb.objectStoreNames.contains('LokiIncrementalData')) {
          onError(new Error("Missing LokiIncrementalData"));
          // Attempt to recover (after reload) by deleting database, since it's damaged anyway
          that.deleteDatabase(dbname);
          return;
        }

        console.log("init success");

        that.idb.onversionchange = function(versionChangeEvent) {
          console.log('IDB version change', versionChangeEvent);
          // This function will be called if another connection changed DB version
          // (Most likely database was deleted from another browser tab, unless there's a new version
          // of this adapter, or someone makes a connection to IDB outside of this adapter)
          // We must close the database to avoid blocking concurrent deletes.
          // The database will be unusable after this. Be sure to supply `onversionchange` option
          // to force logout
          that.idb.close();
          if (that.options.onversionchange) {
            that.options.onversionchange(versionChangeEvent);
          }
        };

        onSuccess();
      };

      openRequest.onblocked = function(e) {
        console.error("IndexedDB open is blocked", e);
        onError(new Error("IndexedDB open is blocked by open connection"));
      };

      openRequest.onerror = function(e) {
        that.idbInitInProgress = false;
        console.error("IndexeddB open error", e);
        onError(e);
      };
    };

    IncrementalIndexedDBAdapter.prototype._saveChunks = function(dbname, chunks, callback) {
      var that = this;
      if (!this.idb) {
        this._initializeIDB(dbname, callback, function() {
          that._saveChunks(dbname, chunks, callback);
        });
        return;
      }

      if (this.operationInProgress) {
        throw new Error("Error while saving to database - another operation is already in progress. Please use throttledSaves=true option on Loki object");
      }

      this.operationInProgress = true;

      var tx = this.idb.transaction(['LokiIncrementalData'], "readwrite");
      tx.oncomplete = function() {
        that.operationInProgress = false;
        console.timeEnd("exportDatabase");
        callback();
      };

      tx.onerror = function(e) {
        that.operationInProgress = false;
        callback(e);
      };

      tx.onabort = function(e) {
        that.operationInProgress = false;
        callback(e);
      };

      var store = tx.objectStore('LokiIncrementalData');

      chunks.forEach(function(object) {
        store.put(object);
      });
    };

    IncrementalIndexedDBAdapter.prototype._getAllChunks = function(dbname, callback) {
      var that = this;
      if (!this.idb) {
        this._initializeIDB(dbname, callback, function() {
          that._getAllChunks(dbname, callback);
        });
        return;
      }

      if (this.operationInProgress) {
        throw new Error("Error while loading database - another operation is already in progress. Please use throttledSaves=true option on Loki object");
      }

      this.operationInProgress = true;

      var tx = this.idb.transaction(['LokiIncrementalData'], "readonly");

      var request = tx.objectStore('LokiIncrementalData').getAll();
      request.onsuccess = function(e) {
        that.operationInProgress = false;
        var chunks = e.target.result;
        callback(chunks);
      };

      request.onerror = function(e) {
        that.operationInProgress = false;
        callback(e);
      };
    };

    /**
     * Deletes a database from IndexedDB
     *
     * @example
     * // DELETE DATABASE
     * // delete 'finance'/'test' value from catalog
     * idbAdapter.deleteDatabase('test', function {
     *   // database deleted
     * });
     *
     * @param {string} dbname - the name of the database to delete from IDB
     * @param {function=} callback - (Optional) executed on database delete
     * @memberof IncrementalIndexedDBAdapter
     */
    IncrementalIndexedDBAdapter.prototype.deleteDatabase = function(dbname, callback) {
      if (this.operationInProgress) {
        throw new Error("Error while deleting database - another operation is already in progress. Please use throttledSaves=true option on Loki object");
      }

      this.operationInProgress = true;

      var that = this;
      console.log("deleteDatabase - begin");
      console.time("deleteDatabase");

      if (this.idb) {
        this.idb.close();
        this.idb = null;
      }

      var request = indexedDB.deleteDatabase(dbname);

      request.onsuccess = function() {
        that.operationInProgress = false;
        console.timeEnd("deleteDatabase");
        callback({ success: true });
      };

      request.onerror = function(e) {
        that.operationInProgress = false;
        console.error("Error while deleting database", e);
        callback({ success: false });
      };

      request.onblocked = function(e) {
        // We can't call callback with failure status, because this will be called even if we
        // succeed in just a moment
        console.error("Deleting database failed because it's blocked by another connection", e);
      };
    };

    return IncrementalIndexedDBAdapter;
  })();
});
<|endoftext|>


<commit_before>var path = require('path'),
    fs = require('fs');

exports.postImage = function(req, res){

    var fstream;
    req.pipe(req.busboy);
    req.busboy.on('file', function(fieldname, file, filename) {
        fstream = fs.createWriteStream(path.resolve('./uploads/'+filename));
        file.pipe(fstream);
        fstream.on('close', function() {
            // TODO: return file url.
            res.json({path:'hva med nei.png'});
        });
    });
};

exports.getImages = function(req, res){
    // TODO: List all urls available
    res.sendfile(path.resolve('uploads/'));
};

// TODO:
// exports.getImage = function(req, res){};
<commit_msg>POST sends a url back<commit_after>var path = require('path'),
    fs = require('fs');

exports.postImage = function(req, res){
    var fstream;
    req.pipe(req.busboy);
    req.busboy.on('file', function(fieldname, file, filename) {
        filename = filename.replace(/\s/g, '');
        fstream = fs.createWriteStream(path.resolve('./uploads/'+filename));
        file.pipe(fstream);
        fstream.on('close', function() {
            var url = req.protocol + '://'+ req.host + req.originalUrl + filename;
            res.json({halla: url});
        });
    });
};

exports.getImages = function(req, res){
    // TODO: List all urls available
    res.sendfile(path.resolve('uploads/'));
};

// TODO:
// exports.getImage = function(req, res){};
<|endoftext|>


<commit_before>'use strict';

Creep.execute = function(creep, methods) {
  for (var method of methods) {
    if (method(creep)) {
      return true;
    }
  }
};

Creep.upgradeControllerTask = function(creep) {
  if (creep.carry.energy === 0) {
    return false;
  }

  var range = creep.pos.getRangeTo(creep.room.controller);
  if (range <= 3) {
    let returnCode = creep.upgradeController(creep.room.controller);
    if (returnCode != OK) {
      creep.log('upgradeController: ' + returnCode);
    }
    creep.moveRandomWithin(creep.room.controller.pos);
    return true;
  } else {
    let search = PathFinder.search(
      creep.pos, {
        pos: creep.room.controller.pos,
        range: 3
      }, {
        roomCallback: creep.room.getAvoids(creep.room, {}, true),
        maxRooms: 0
      }
    );

    if (search.incomplete) {
      creep.say('incomplete');
      creep.moveTo(creep.room.controller.pos);
      return true;
    }
    creep.move(creep.pos.getDirectionTo(search.path[0]));
  }
  return true;
};

Creep.constructTask = function(creep) {
  //  creep.say('construct', true);
  return creep.construct();
};

Creep.transferEnergy = function(creep) {
  //  creep.say('transferEnergy', true);
  return creep.transferEnergyMy();
};

Creep.buildRoads = function(creep) {
  let room = Game.rooms[creep.room.name];

  // TODO extract to roomposition
  function checkForRoad(pos) {
    var structures = pos.lookFor('structure');
    for (let structuresIndex in structures) {
      if (structures[structuresIndex].structureType == STRUCTURE_ROAD) {
        return true;
      }
    }
    return false;
  }

  // TODO Redo for all path in room
  var path = room.memory.position.path;
  for (let pathIndex in path) {
    var pos = new RoomPosition(
      path[pathIndex].x,
      path[pathIndex].y,
      creep.room.name
    );
    if (checkForRoad(pos)) {
      continue;
    }

    let returnCode = pos.createConstructionSite(STRUCTURE_ROAD);
    if (returnCode == OK) {
      return true;
    }
    if (returnCode == ERR_FULL) {
      return true;
    }
    if (returnCode == ERR_INVALID_TARGET) {
      // FIXME Creep is standing on constructionSite, need to check why it is not building
      creep.moveRandom();
      continue;
    }
    creep.log('buildRoads: ' + returnCode + ' pos: ' + JSON.stringify(pos));
    return true;
  }
  return false;
};

Creep.recycleCreep = function(creep) {
  if (creep.memory.role == 'planer') {
    creep.room.buildStructures();
  }

  let spawn = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, {
    filter: {
      structureType: STRUCTURE_SPAWN
    }
  });
  if (spawn !== null) {
    creep.moveTo(spawn, {
      ignoreCreeps: true
    });
    spawn.recycleCreep(creep);
  }
  // TODO move back
  return true;
};

Creep.getEnergy = function(creep) {
  return creep.getEnergy();
};

Creep.repairStructure = function(creep) {
  return creep.repairStructure();
};

Creep.prototype.getEnergyFromHostileStructures = function() {
  if (this.carry.energy) {
    return false;
  }
  let hostileStructures = this.room.find(FIND_HOSTILE_STRUCTURES, {
    filter: function(object) {
      let table = {
        [STRUCTURE_CONTROLLER]: true,
        [STRUCTURE_RAMPART]: true,
        [STRUCTURE_EXTRACTOR]: true
      };
      return !table[object.structureType];
    }
  });
  if (!hostileStructures.length) {
    return false;
  }

  this.say('hostile');
  hostileStructures = _.sortBy(hostileStructures, function(object) {
    if (object.structureType == STRUCTURE_STORAGE) {
      return 1;
    }
    return 2;
  });

  let structure = _.max(hostileStructures, s => s.structureType === STRUCTURE_STORAGE);
  this.log(JSON.stringify(structure));
  if (structure.structureType === STRUCTURE_STORAGE) {
    if (structure.store.energy === 0) {
      structure.destroy();
      return true;
    }
  } else if (!structure.energy) {
    structure.destroy();
    return true;
  }

  let range = this.pos.getRangeTo(structure);
  this.moveTo(structure);
  this.withdraw(structure, RESOURCE_ENERGY);
  return true;
};

Creep.prototype.getEnergyFromStorage = function() {
  if (!this.room.storage || this.room.storage.store.energy < config.creep.energyFromStorageThreshold) {
    return false;
  }

  if (this.carry.energy) {
    return false;
  }

  var range = this.pos.getRangeTo(this.room.storage);
  if (range == 1) {
    this.withdraw(this.room.storage, RESOURCE_ENERGY);
  } else {
    let search = PathFinder.search(
      this.pos, {
        pos: this.room.storage.pos,
        range: 1
      }, {
        roomCallback: this.room.getAvoids(this.room, {}, true),
      }
    );
    if (search.incomplete) {
      this.say('incomplete', true);
      this.moveTo(this.room.storage.pos, {
        ignoreCreeps: true
      });
      return true;
    }
    let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
    if (returnCode != OK && returnCode != ERR_TIRED) {
      // this.log(`getEnergyFromStorage: ${returnCode}`);
    }
  }
  return true;
};

Creep.prototype.repairStructure = function() {
  var structure = null;
  var range = null;
  var i = null;
  var structures = null;

  if (this.memory.target) {
    var to_repair = Game.getObjectById(this.memory.target);
    if (!to_repair || to_repair === null) {
      delete this.memory.target;
      return false;
    }

    if (to_repair instanceof ConstructionSite) {
      this.build(to_repair);

      let search = PathFinder.search(
        this.pos, {
          pos: to_repair.pos,
          range: 3
        }, {
          roomCallback: this.room.getAvoids(this.room, {}, true),
          maxRooms: 0
        }
      );

      if (search.incomplete) {
        this.moveTo(to_repair);
        return true;
      }

      if (!this.pos.getDirectionTo(search.path[0])) {
        this.moveRandom();
        return true;
      }

      let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
      return true;
    } else if (to_repair.hits < 10000 || to_repair.hits < this.memory.step + 10000) {
      this.repair(to_repair);
      if (this.fatigue === 0) {
        range = this.pos.getRangeTo(to_repair);
        if (range <= 3) {
          this.moveRandomWithin(to_repair);
        } else {
          let search = PathFinder.search(
            this.pos, {
              pos: to_repair.pos,
              range: 3
            }, {
              roomCallback: this.room.getAvoids(this.room, {}, true),
              maxRooms: 0
            }
          );

          if (!this.pos.getDirectionTo(search.path[0])) {
            this.moveRandom();
            return true;
          }

          if (search.incomplete) {
            this.moveTo(to_repair.pos);
            return true;
          }

          let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
          this.memory.lastPosition = this.pos;
          if (returnCode == OK) {
            return true;
          }
          if (returnCode == ERR_NO_PATH) {
            this.memory.move_wait = 0;
            this.log('No path : ' + JSON.stringify(search));
            returnCode = this.moveTo(to_repair, {
              ignoreCreeps: true,
              costCallback: this.room.getAvoids(this.room, {
                power: true
              })
            });
          }
          this.log('config_creep_resources.repairStructure moveByPath.returnCode: ' + returnCode + ' search: ' + JSON.stringify(search) + ' start: ' + JSON.stringify(this.pos) + ' end: ' + JSON.stringify(to_repair.pos));
          return true;
        }
      }
    } else {
      delete this.memory.target;
    }
  }

  let nukes = this.room.find(FIND_NUKES);
  if (nukes.length > 0) {
    let spawns = this.room.find(FIND_MY_STRUCTURES, {
      filter: function(object) {
        if (object.structureType != STRUCTURE_SPAWN) {
          return false;
        }
        return true;
      }
    });
    if (spawns.length > 0) {
      for (let spawn of spawns) {
        let found = false;
        let rampart;
        structures = spawn.pos.lookFor(LOOK_STRUCTURES);
        for (structure of structures) {
          if (structure.structureType == STRUCTURE_RAMPART) {
            if (structure.hits < 1100000) {
              found = true;
              rampart = structure;
              break;
            }
          }
        }
        if (found) {
          this.memory.target = rampart.id;
          this.memory.step = 1200000;
          return true;
        }
      }
    }
  }

  // Repair low ramparts
  let lowRamparts = this.pos.findInRange(FIND_STRUCTURES, 4, {
    filter: function(object) {
      if (object.structureType == STRUCTURE_RAMPART && object.hits < 10000) {
        return true;
      }
      return false;
    }
  });

  if (lowRamparts.length > 0) {
    let lowRampart = lowRamparts[0];
    let range = this.pos.getRangeTo(lowRampart);
    if (range <= 3) {
      this.repair(lowRampart);
      this.moveRandomWithin(lowRampart);
    } else {
      let search = PathFinder.search(
        this.pos, {
          pos: lowRampart.pos,
          range: 3
        }, {
          roomCallback: this.room.getAvoids(this.room, {}, true),
          maxRooms: 0
        }
      );
      //     this.log('LowRampart: ' + lowRamparts[0].pos + ' search: ' + JSON.stringify(search));
      let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
    }
    return true;
  }

  // Build construction sites
  var target = this.pos.findClosestByRange(FIND_CONSTRUCTION_SITES, {
    filter: function(object) {
      if (object.structureType == 'constructedWall') {
        return true;
      }
      if (object.structureType == 'rampart') {
        return true;
      }
      return false;
    }
  });

  if (target !== null) {
    range = this.pos.getRangeTo(target);

    if (range <= 3) {
      this.build(target);
      this.memory.step = 0;
      var targetNew = this.pos.findClosestByRange(FIND_CONSTRUCTION_SITES, {
        filter: function(object) {
          if (object.id == target.id) {
            return false;
          }
          if (object.structureType == 'constructedWall') {
            return true;
          }
          if (object.structureType == 'rampart') {
            return true;
          }
          return false;
        }
      });
      if (targetNew !== null) {
        target = targetNew;
      }
    }
    let ignoreCreepsSwitch = true;
    let last_pos = this.memory.lastPosition;
    if (this.memory.lastPosition && this.pos.isEqualTo(new RoomPosition(last_pos.x, last_pos.y, this.room.name))) {
      this.memory.move_wait++;
      if (this.memory.move_wait > 5) {
        ignoreCreepsSwitch = false;
      }
    } else {
      this.memory.move_wait = 0;
    }

    let search = PathFinder.search(
      this.pos, {
        pos: target.pos,
        range: 3
      }, {
        roomCallback: this.room.getAvoids(this.room, {}, true),
        maxRooms: 0
      }
    );
    //    this.log('ConstructionSite: ' + target.pos + ' search: ' + JSON.stringify(search));
    // for (let x = 19; x < 31; x++) {
    // for (let y = 2; y < 7; y++) {
    // let costmatrix = this.room.getAvoids(this.room, {}, true)(this.room.name);
    // this.log(x + ',' + y + ' ' + costmatrix.get(x, y));
    // }
    // }
    let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
    this.memory.lastPosition = this.pos;
    this.memory.target = target.id;
    return true;
  }

  var creep = this;
  structure = this.pos.findClosestByRange(FIND_STRUCTURES, {
    filter: function(object) {
      // Newbie zone walls have no hits
      if (!object.hits) {
        return false;
      }

      if (object.hits >= Math.min(creep.memory.step, object.hitsMax)) {
        return false;
      }

      if (object.structureType == 'constructedWall') {
        return true;
      }

      if (object.structureType == 'rampart') {
        return true;
      }
      return false;
    }
  });
  if (structure && structure !== null) {
    this.memory.target = structure.id;
    return true;
  }

  if (this.memory.step === 0) {
    this.memory.step = this.room.controller.level * 10000;
  }
  this.memory.step = (this.memory.step * 1.1) + 1;

  //   this.log('Nothing found: ' + this.memory.step);
  return false;
};

Creep.prototype.getDroppedEnergy = function() {
  let target = this.pos.findClosestByRange(FIND_DROPPED_ENERGY, {
    filter: function(object) {
      return 0 < object.energy;
    }
  });
  if (target !== null) {
    var energyRange = this.pos.getRangeTo(target.pos);
    if (energyRange <= 1) {
      this.pickup(target);
      return true;
    }
    if (target.energy > (energyRange * 10) * (this.carry.energy + 1)) {
      let search = PathFinder.search(
        this.pos, {
          pos: target.pos,
          range: 1
        }, {
          roomCallback: this.room.getAvoids(this.room, {}, true),
          maxRooms: 0
        }
      );
      if (search.path.length === 0 || search.incomplete) {
        this.say('deir');
        this.moveRandom();
        return true;
      }
      let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
      return true;
    }
  }
  return false;
};
<commit_msg>force move and try pass if path incomplete<commit_after>'use strict';

Creep.execute = function(creep, methods) {
  for (var method of methods) {
    if (method(creep)) {
      return true;
    }
  }
};

Creep.upgradeControllerTask = function(creep) {
  if (creep.carry.energy === 0) {
    return false;
  }

  var range = creep.pos.getRangeTo(creep.room.controller);
  if (range <= 3) {
    let returnCode = creep.upgradeController(creep.room.controller);
    if (returnCode != OK) {
      creep.log('upgradeController: ' + returnCode);
    }
    creep.moveRandomWithin(creep.room.controller.pos);
    return true;
  } else {
    let search = PathFinder.search(
      creep.pos, {
        pos: creep.room.controller.pos,
        range: 3
      }, {
        roomCallback: creep.room.getAvoids(creep.room, {}, true),
        maxRooms: 0
      }
    );

    if (search.incomplete) {
      creep.say('incomplete');
      creep.moveTo(creep.room.controller.pos);
      return true;
    }
    creep.move(creep.pos.getDirectionTo(search.path[0]));
  }
  return true;
};

Creep.constructTask = function(creep) {
  //  creep.say('construct', true);
  return creep.construct();
};

Creep.transferEnergy = function(creep) {
  //  creep.say('transferEnergy', true);
  return creep.transferEnergyMy();
};

Creep.buildRoads = function(creep) {
  let room = Game.rooms[creep.room.name];

  // TODO extract to roomposition
  function checkForRoad(pos) {
    var structures = pos.lookFor('structure');
    for (let structuresIndex in structures) {
      if (structures[structuresIndex].structureType == STRUCTURE_ROAD) {
        return true;
      }
    }
    return false;
  }

  // TODO Redo for all path in room
  var path = room.memory.position.path;
  for (let pathIndex in path) {
    var pos = new RoomPosition(
      path[pathIndex].x,
      path[pathIndex].y,
      creep.room.name
    );
    if (checkForRoad(pos)) {
      continue;
    }

    let returnCode = pos.createConstructionSite(STRUCTURE_ROAD);
    if (returnCode == OK) {
      return true;
    }
    if (returnCode == ERR_FULL) {
      return true;
    }
    if (returnCode == ERR_INVALID_TARGET) {
      // FIXME Creep is standing on constructionSite, need to check why it is not building
      creep.moveRandom();
      continue;
    }
    creep.log('buildRoads: ' + returnCode + ' pos: ' + JSON.stringify(pos));
    return true;
  }
  return false;
};

Creep.recycleCreep = function(creep) {
  if (creep.memory.role == 'planer') {
    creep.room.buildStructures();
  }

  let spawn = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, {
    filter: {
      structureType: STRUCTURE_SPAWN
    }
  });
  if (spawn !== null) {
    creep.moveTo(spawn, {
      ignoreCreeps: true
    });
    spawn.recycleCreep(creep);
  }
  // TODO move back
  return true;
};

Creep.getEnergy = function(creep) {
  return creep.getEnergy();
};

Creep.repairStructure = function(creep) {
  return creep.repairStructure();
};

Creep.prototype.getEnergyFromHostileStructures = function() {
  if (this.carry.energy) {
    return false;
  }
  let hostileStructures = this.room.find(FIND_HOSTILE_STRUCTURES, {
    filter: function(object) {
      let table = {
        [STRUCTURE_CONTROLLER]: true,
        [STRUCTURE_RAMPART]: true,
        [STRUCTURE_EXTRACTOR]: true
      };
      return !table[object.structureType];
    }
  });
  if (!hostileStructures.length) {
    return false;
  }

  this.say('hostile');
  hostileStructures = _.sortBy(hostileStructures, function(object) {
    if (object.structureType == STRUCTURE_STORAGE) {
      return 1;
    }
    return 2;
  });

  let structure = _.max(hostileStructures, s => s.structureType === STRUCTURE_STORAGE);
  this.log(JSON.stringify(structure));
  if (structure.structureType === STRUCTURE_STORAGE) {
    if (structure.store.energy === 0) {
      structure.destroy();
      return true;
    }
  } else if (!structure.energy) {
    structure.destroy();
    return true;
  }

  let range = this.pos.getRangeTo(structure);
  this.moveTo(structure);
  this.withdraw(structure, RESOURCE_ENERGY);
  return true;
};

Creep.prototype.getEnergyFromStorage = function() {
  if (!this.room.storage || this.room.storage.store.energy < config.creep.energyFromStorageThreshold) {
    return false;
  }

  if (this.carry.energy) {
    return false;
  }

  var range = this.pos.getRangeTo(this.room.storage);
  if (range == 1) {
    this.withdraw(this.room.storage, RESOURCE_ENERGY);
  } else {
    let search = PathFinder.search(
      this.pos, {
        pos: this.room.storage.pos,
        range: 1
      }, {
        roomCallback: this.room.getAvoids(this.room, {}, true),
      }
    );
    if (search.incomplete) {
      this.say('incomplete', true);
      this.moveTo(this.room.storage.pos, {
        ignoreCreeps: true
      });
      return true;
    }
    let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
    if (returnCode != OK && returnCode != ERR_TIRED) {
      // this.log(`getEnergyFromStorage: ${returnCode}`);
    }
  }
  return true;
};

Creep.prototype.repairStructure = function() {
  var structure = null;
  var range = null;
  var i = null;
  var structures = null;

  if (this.memory.target) {
    var to_repair = Game.getObjectById(this.memory.target);
    if (!to_repair || to_repair === null) {
      delete this.memory.target;
      return false;
    }

    if (to_repair instanceof ConstructionSite) {
      this.build(to_repair);

      let search = PathFinder.search(
        this.pos, {
          pos: to_repair.pos,
          range: 3
        }, {
          roomCallback: this.room.getAvoids(this.room, {}, true),
          maxRooms: 0
        }
      );

      if (search.incomplete) {
        this.moveTo(to_repair);
        return true;
      }

      if (!this.pos.getDirectionTo(search.path[0])) {
        this.moveRandom();
        return true;
      }

      let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
      return true;
    } else if (to_repair.hits < 10000 || to_repair.hits < this.memory.step + 10000) {
      this.repair(to_repair);
      if (this.fatigue === 0) {
        range = this.pos.getRangeTo(to_repair);
        if (range <= 3) {
          this.moveRandomWithin(to_repair);
        } else {
          let search = PathFinder.search(
            this.pos, {
              pos: to_repair.pos,
              range: 3
            }, {
              roomCallback: this.room.getAvoids(this.room, {}, true),
              maxRooms: 0
            }
          );

          if (!this.pos.getDirectionTo(search.path[0])) {
            this.moveRandom();
            return true;
          }

          if (search.incomplete) {
            this.moveTo(to_repair.pos);
            return true;
          }

          let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
          this.memory.lastPosition = this.pos;
          if (returnCode == OK) {
            return true;
          }
          if (returnCode == ERR_NO_PATH) {
            this.memory.move_wait = 0;
            this.log('No path : ' + JSON.stringify(search));
            returnCode = this.moveTo(to_repair, {
              ignoreCreeps: true,
              costCallback: this.room.getAvoids(this.room, {
                power: true
              })
            });
          }
          this.log('config_creep_resources.repairStructure moveByPath.returnCode: ' + returnCode + ' search: ' + JSON.stringify(search) + ' start: ' + JSON.stringify(this.pos) + ' end: ' + JSON.stringify(to_repair.pos));
          return true;
        }
      }
    } else {
      delete this.memory.target;
    }
  }

  let nukes = this.room.find(FIND_NUKES);
  if (nukes.length > 0) {
    let spawns = this.room.find(FIND_MY_STRUCTURES, {
      filter: function(object) {
        if (object.structureType != STRUCTURE_SPAWN) {
          return false;
        }
        return true;
      }
    });
    if (spawns.length > 0) {
      for (let spawn of spawns) {
        let found = false;
        let rampart;
        structures = spawn.pos.lookFor(LOOK_STRUCTURES);
        for (structure of structures) {
          if (structure.structureType == STRUCTURE_RAMPART) {
            if (structure.hits < 1100000) {
              found = true;
              rampart = structure;
              break;
            }
          }
        }
        if (found) {
          this.memory.target = rampart.id;
          this.memory.step = 1200000;
          return true;
        }
      }
    }
  }

  // Repair low ramparts
  let lowRamparts = this.pos.findInRange(FIND_STRUCTURES, 4, {
    filter: function(object) {
      if (object.structureType == STRUCTURE_RAMPART && object.hits < 10000) {
        return true;
      }
      return false;
    }
  });

  if (lowRamparts.length > 0) {
    let lowRampart = lowRamparts[0];
    let range = this.pos.getRangeTo(lowRampart);
    if (range <= 3) {
      this.repair(lowRampart);
      this.moveRandomWithin(lowRampart);
    } else {
      let search = PathFinder.search(
        this.pos, {
          pos: lowRampart.pos,
          range: 3
        }, {
          roomCallback: this.room.getAvoids(this.room, {}, true),
          maxRooms: 0
        }
      );
      //     this.log('LowRampart: ' + lowRamparts[0].pos + ' search: ' + JSON.stringify(search));
      let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
    }
    return true;
  }

  // Build construction sites
  var target = this.pos.findClosestByRange(FIND_CONSTRUCTION_SITES, {
    filter: function(object) {
      if (object.structureType == 'constructedWall') {
        return true;
      }
      if (object.structureType == 'rampart') {
        return true;
      }
      return false;
    }
  });

  if (target !== null) {
    range = this.pos.getRangeTo(target);

    if (range <= 3) {
      this.build(target);
      this.memory.step = 0;
      var targetNew = this.pos.findClosestByRange(FIND_CONSTRUCTION_SITES, {
        filter: function(object) {
          if (object.id == target.id) {
            return false;
          }
          if (object.structureType == 'constructedWall') {
            return true;
          }
          if (object.structureType == 'rampart') {
            return true;
          }
          return false;
        }
      });
      if (targetNew !== null) {
        target = targetNew;
      }
    }
    let ignoreCreepsSwitch = true;
    let last_pos = this.memory.lastPosition;
    if (this.memory.lastPosition && this.pos.isEqualTo(new RoomPosition(last_pos.x, last_pos.y, this.room.name))) {
      this.memory.move_wait++;
      if (this.memory.move_wait > 5) {
        ignoreCreepsSwitch = false;
      }
    } else {
      this.memory.move_wait = 0;
    }

    let search = PathFinder.search(
      this.pos, {
        pos: target.pos,
        range: 3
      }, {
        roomCallback: this.room.getAvoids(this.room, {}, true),
        maxRooms: 0
      }
    );
    //    this.log('ConstructionSite: ' + target.pos + ' search: ' + JSON.stringify(search));
    // for (let x = 19; x < 31; x++) {
    // for (let y = 2; y < 7; y++) {
    // let costmatrix = this.room.getAvoids(this.room, {}, true)(this.room.name);
    // this.log(x + ',' + y + ' ' + costmatrix.get(x, y));
    // }
    // }
    let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
    this.memory.lastPosition = this.pos;
    this.memory.target = target.id;
    return true;
  }

  var creep = this;
  structure = this.pos.findClosestByRange(FIND_STRUCTURES, {
    filter: function(object) {
      // Newbie zone walls have no hits
      if (!object.hits) {
        return false;
      }

      if (object.hits >= Math.min(creep.memory.step, object.hitsMax)) {
        return false;
      }

      if (object.structureType == 'constructedWall') {
        return true;
      }

      if (object.structureType == 'rampart') {
        return true;
      }
      return false;
    }
  });
  if (structure && structure !== null) {
    this.memory.target = structure.id;
    return true;
  }

  if (this.memory.step === 0) {
    this.memory.step = this.room.controller.level * 10000;
  }
  this.memory.step = (this.memory.step * 1.1) + 1;

  //   this.log('Nothing found: ' + this.memory.step);
  return false;
};

Creep.prototype.getDroppedEnergy = function() {
  let target = this.pos.findClosestByRange(FIND_DROPPED_ENERGY, {
    filter: function(object) {
      return 0 < object.energy;
    }
  });
  if (target !== null) {
    var energyRange = this.pos.getRangeTo(target.pos);
    if (energyRange <= 1) {
      this.pickup(target);
      return true;
    }
    if (target.energy > (energyRange * 10) * (this.carry.energy + 1)) {
      let search = PathFinder.search(
        this.pos, {
          pos: target.pos,
          range: 1
        }, {
          roomCallback: this.room.getAvoids(this.room, {}, true),
          maxRooms: 0
        }
      );
      if (search.path.length === 0 || (search.incomplete && !search[1])) {
        this.say('deir');
        this.moveRandom();
        return true;
      }
      let returnCode = this.move(this.pos.getDirectionTo(search.path[0]));
      return true;
    }
  }
  return false;
};
<|endoftext|>