<commit_before>/*
 ***** 已使用的子域名
 * ***********************
 *
 * 目前以下子域名已经启用
 * 提交一个 PR， 添加你想使用的的域名
 *
 *
 **** 说明
 * ***********
 *
 * KEY:         你提交的域名（如：`foo` 表示自定义子域名为 `foo.js.cool`）
 *
 * VALUE:       以 Github 为例，`foo.github.io` 表示用户/组织的主页，
 *              或 `foo.github.io/bar` 表示项目主页，也可以绑定 Gitee、 CODING.NET 等其它开源托管服务商。
 *
 * CLOUDFLARE:  目前 JS.COOL 使用的 DNS 服务商为 CloudFlare。默认情况下代理状态为自动（支持 SSL），
 *              通过 HTTPS 链接（如： https://foo.js.cool ）进行访问。
 *              但如果你不希望通过 CloudFlare 加速，可以选择 `仅限 DNS` 选项，
 *              只需要在你提交的代码后面添加 `// noCF` 注释即可。
 */
module.exports = {
  // 请在此处区域内添加自定义域名
  "color-ui": "colorui-kit.github.io",
  "icns": "icnskit.github.io",
  "j2me_games": "waifu-project.github.io",
  'cnchar': 'theajack.github.io',
  'leader': 'willin.github.io',
  'codewars': 'js-cool.github.io',
  'dataloader': 'shiwangme.github.io',
  'hyperapp': 'willin.github.io',
  'anime': 'js-cool.github.io',
  'learn': 'hosting.gitbook.com',
  'vchart': 'willin.github.io',
  'graphql': 'willin.github.io',
  'speech': 'willin.github.io',
  'blockchain': 'willin.github.io',
  'antiadblock': 'js-cool.github.io',
  'noho': 'willin.github.io',
  //'jen': 'dirkhe1051931999.github.io',
  'uiw': 'uiwjs.github.io',
  'xrkffgg': 'xrkffgg.github.io',
  'interview': 'front-end-interview.netlify.app',
  'xiaomeiwu':'xiaomeiwu.github.io',
  'ip': 'ipip.vercel.app', // noCF
  'mingyan': 'lehs8n.coding-pages.com', //noCf
  'na': 'qq.mcust.cn',
  'rx': 'willin.github.io',
  'bbx': 'appser.gitee.io',
  'mengd': 'cname.vercel-dns.com',
  'kali': '551kdx.coding-pages.com',
  'zwt': 'zwtdyhm.github.io',
  'zwtdwz': 'zwtdzh.github.io',
  'zwtdwlzd': 'zwtdwlid.github.io',
  // 'histcat': 'jessejeson.github.io',
  'wangdabao-resume': 'wangdabaoqq.github.io',
  'wangdabao': 'wangdabaoqq.github.io',
  'resources': 'willin.github.io',
  'zwtdwzym': 'zwtduserid.github.io',
  'kaodan': 'kaodan.github.io',
  'gatsby-demo': 'whitematrix.github.io',
  'box': 'qikaile.github.io',
  'hualin': 'liaochenlanruo.github.io',
  'authing-next': 'cname.vercel-dns.com',
  // 请在此行之上新增一行并提交 Pull Request
  // 示例：
  // 'youarname': 'username.github.io' // noCF
  // 以下为已启用的保留域名，请勿修改
  '@': 'js-cool.github.io',
  'www': 'kv6xcc.coding-pages.com', // 国内镜像
  'logo': 'js-cool.github.io'
};
<commit_msg>feat: :sparkles: add public cdns<commit_after>/*
 ***** 已使用的子域名
 * ***********************
 *
 * 目前以下子域名已经启用
 * 提交一个 PR， 添加你想使用的的域名
 *
 *
 **** 说明
 * ***********
 *
 * KEY:         你提交的域名（如：`foo` 表示自定义子域名为 `foo.js.cool`）
 *
 * VALUE:       以 Github 为例，`foo.github.io` 表示用户/组织的主页，
 *              或 `foo.github.io/bar` 表示项目主页，也可以绑定 Gitee、 CODING.NET 等其它开源托管服务商。
 *
 * CLOUDFLARE:  目前 JS.COOL 使用的 DNS 服务商为 CloudFlare。默认情况下代理状态为自动（支持 SSL），
 *              通过 HTTPS 链接（如： https://foo.js.cool ）进行访问。
 *              但如果你不希望通过 CloudFlare 加速，可以选择 `仅限 DNS` 选项，
 *              只需要在你提交的代码后面添加 `// noCF` 注释即可。
 */
module.exports = {
  // Cloudflare CDN
  'github': 'cdn-github.willin.workers.dev', // github.com
  'fonts-gstatic': 'fonts-gstatic.willin.workers.dev', // fonts.gstatic.com
  // 请在此处区域内添加自定义域名
  "color-ui": "colorui-kit.github.io",
  "icns": "icnskit.github.io",
  "j2me_games": "waifu-project.github.io",
  'cnchar': 'theajack.github.io',
  'leader': 'willin.github.io',
  'codewars': 'js-cool.github.io',
  'dataloader': 'shiwangme.github.io',
  'hyperapp': 'willin.github.io',
  'anime': 'js-cool.github.io',
  'learn': 'hosting.gitbook.com',
  'vchart': 'willin.github.io',
  'graphql': 'willin.github.io',
  'speech': 'willin.github.io',
  'blockchain': 'willin.github.io',
  'antiadblock': 'js-cool.github.io',
  'noho': 'willin.github.io',
  //'jen': 'dirkhe1051931999.github.io',
  'uiw': 'uiwjs.github.io',
  'xrkffgg': 'xrkffgg.github.io',
  'interview': 'front-end-interview.netlify.app',
  'xiaomeiwu':'xiaomeiwu.github.io',
  'ip': 'ipip.vercel.app', // noCF
  'mingyan': 'lehs8n.coding-pages.com', //noCf
  'na': 'qq.mcust.cn',
  'rx': 'willin.github.io',
  'bbx': 'appser.gitee.io',
  'mengd': 'cname.vercel-dns.com',
  'kali': '551kdx.coding-pages.com',
  'zwt': 'zwtdyhm.github.io',
  'zwtdwz': 'zwtdzh.github.io',
  'zwtdwlzd': 'zwtdwlid.github.io',
  // 'histcat': 'jessejeson.github.io',
  'wangdabao-resume': 'wangdabaoqq.github.io',
  'wangdabao': 'wangdabaoqq.github.io',
  'resources': 'willin.github.io',
  'zwtdwzym': 'zwtduserid.github.io',
  'kaodan': 'kaodan.github.io',
  'gatsby-demo': 'whitematrix.github.io',
  'box': 'qikaile.github.io',
  'hualin': 'liaochenlanruo.github.io',
  'authing-next': 'cname.vercel-dns.com',
  // 请在此行之上新增一行并提交 Pull Request
  // 示例：
  // 'youarname': 'username.github.io' // noCF
  // 以下为已启用的保留域名，请勿修改
  '@': 'js-cool.github.io',
  'www': 'kv6xcc.coding-pages.com', // 国内镜像
  'logo': 'js-cool.github.io'
};
<|endoftext|>


<commit_before>import { select } from 'd3-selection';
import 'd3-selection-multi';

export default class List {
  constructor() {
    this._first = null;
    this._items = new Set();

    this._title = null;
    this._comment = null;

    this._root = select('body')
      .append('div')
      .remove()
      .classed('scola list static', true)
      .styles({
        'display': 'flex',
        'flex-direction': 'column',
        'padding-bottom': '3em'
      });

    this._body = this._root
      .append('div')
      .classed('scola body', true)
      .styles({
        'border-width': '1px 0',
        'border-color': '#CCC',
        'border-style': 'solid',
        'order': 2
      });

    this.first(false);
  }

  destroy() {
    this._items.forEach((item) => item.destroy());
    this._items.clear();

    this._root.dispatch('destroy');
    this._root.remove();
    this._root = null;
  }

  root() {
    return this._root;
  }

  append(item, action) {
    item.first(this._items.size === 0);

    if (action === true) {
      this._items.add(item);
      this._body.node().appendChild(item.root().node());
    } else if (action === false) {
      this._items.delete(item);
      item.root().remove();
    }

    return this;
  }

  comment(value) {
    if (typeof value === 'undefined') {
      return this._comment;
    }

    if (value === false) {
      return this._deleteComment();
    }

    if (this._comment) {
      return this._updateComment(value);
    }

    return this._insertComment(value);
  }

  title(value) {
    if (typeof value === 'undefined') {
      return this._title;
    }

    if (value === false) {
      return this._deleteTitle();
    }

    if (this._title) {
      return this._updateTitle(value);
    }

    return this._insertTitle(value);
  }

  inset() {
    this._root.style('margin', '0 1em');

    this._body.styles({
      'border-style': 'none',
      'border-radius': '0.5em',
      'overflow': 'hidden'
    });

    return this;
  }

  first(value) {
    if (value === this._first) {
      return this;
    }

    this._first = value;
    this._root.style('padding-top', value === true ? '3em' : '0px');

    return this;
  }

  _insertComment(comment) {
    this._comment = this._root
      .append('div')
      .classed('scola comment', true)
      .styles({
        'color': '#AAA',
        'font-size': '0.9em',
        'line-height': '1.5em',
        'order': 3,
        'padding': '0.75em 1.1em 0'
      })
      .text(comment);

    return this;
  }

  _updateComment(comment) {
    this._comment.text(comment);
    return this;
  }

  _deleteComment() {
    if (this._comment) {
      this._comment.remove();
      this._comment = null;
    }

    return this;
  }

  _insertTitle(title) {
    this._title = this._root
      .append('div')
      .classed('scola title', true)
      .styles({
        'color': '#AAA',
        'font-size': '0.9em',
        'order': 1,
        'padding': '0 1.1em 0.75em',
        'text-transform': 'uppercase'
      })
      .text(title);

    return this;
  }

  _updateTitle(title) {
    this._title.text(title);
    return this;
  }

  _deleteTitle() {
    if (this._title) {
      this._title.remove();
      this._title = null;
    }

    return this;
  }
}
<commit_msg>Handle inset by media<commit_after>import { select } from 'd3-selection';
import 'd3-selection-multi';
import '@scola/d3-media';

export default class List {
  constructor() {
    this._first = null;
    this._items = new Set();

    this._rootMedia = null;
    this._bodyMedia = null;
    this._title = null;
    this._comment = null;

    this._root = select('body')
      .append('div')
      .remove()
      .classed('scola list static', true)
      .styles({
        'display': 'flex',
        'flex-direction': 'column',
        'padding-bottom': '3em'
      });

    this._body = this._root
      .append('div')
      .classed('scola body', true)
      .styles({
        'border-color': '#CCC',
        'border-style': 'solid',
        'border-width': '1px 0',
        'order': 2
      });

    this.first(false);
  }

  destroy() {
    if (this._rootMedia) {
      this._rootMedia.destroy();
      this._rootMedia = null;
    }

    if (this._bodyMedia) {
      this._bodyMedia.destroy();
      this._bodyMedia = null;
    }

    this._items.forEach((item) => item.destroy());
    this._items.clear();

    this._root.dispatch('destroy');
    this._root.remove();
    this._root = null;
  }

  root() {
    return this._root;
  }

  append(item, action) {
    item.first(this._items.size === 0);

    if (action === true) {
      this._items.add(item);
      this._body.node().appendChild(item.root().node());
    } else if (action === false) {
      this._items.delete(item);
      item.root().remove();
    }

    return this;
  }

  comment(value) {
    if (typeof value === 'undefined') {
      return this._comment;
    }

    if (value === false) {
      return this._deleteComment();
    }

    if (this._comment) {
      return this._updateComment(value);
    }

    return this._insertComment(value);
  }

  title(value) {
    if (typeof value === 'undefined') {
      return this._title;
    }

    if (value === false) {
      return this._deleteTitle();
    }

    if (this._title) {
      return this._updateTitle(value);
    }

    return this._insertTitle(value);
  }

  inset(width = '48em') {
    if (width === false) {
      this._rootMedia.destroy();
      this._rootMedia = null;

      this._bodyedia.destroy();
      this._bodyMedia = null;

      return this;
    }

    this._rootMedia = this._root
      .media(`(min-width: ${width})`)
      .styles({
        'padding-left': '1em',
        'padding-right': '1em'
      })
      .start();

    this._bodyMedia = this._body
      .media(`(min-width: ${width})`)
      .styles({
        'border-radius': '0.5em',
        'border-style': 'none',
        'overflow': 'hidden'
      })
      .start();

    return this;
  }

  first(value) {
    if (value === this._first) {
      return this;
    }

    this._first = value;
    this._root.style('padding-top', value === true ? '3em' : '0px');

    return this;
  }

  _insertComment(comment) {
    this._comment = this._root
      .append('div')
      .classed('scola comment', true)
      .styles({
        'color': '#AAA',
        'font-size': '0.9em',
        'line-height': '1.5em',
        'order': 3,
        'padding': '0.75em 1.1em 0'
      })
      .text(comment);

    return this;
  }

  _updateComment(comment) {
    this._comment.text(comment);
    return this;
  }

  _deleteComment() {
    if (this._comment) {
      this._comment.remove();
      this._comment = null;
    }

    return this;
  }

  _insertTitle(title) {
    this._title = this._root
      .append('div')
      .classed('scola title', true)
      .styles({
        'color': '#AAA',
        'font-size': '0.9em',
        'order': 1,
        'padding': '0 1.1em 0.75em',
        'text-transform': 'uppercase'
      })
      .text(title);

    return this;
  }

  _updateTitle(title) {
    this._title.text(title);
    return this;
  }

  _deleteTitle() {
    if (this._title) {
      this._title.remove();
      this._title = null;
    }

    return this;
  }
}
<|endoftext|>


<commit_before>var toggleEmojiBookmarklet = function () {
  var SERVER_URL = 'http://localhost:8000';
  //var SERVER_URL = 'https://johannhof.github.io/emoji-helper/bookmarklet/';

  var container = document.createElement('div');
  var frame = document.createElement('iframe');
  frame.src = SERVER_URL;

  frame.style.height = '350px';
  frame.style.width = '510px';
  frame.style.border = '1px solid lightgray';

  container.style.height = '350px';
  container.style.width = '510px';
  container.style.boxShadow = '2px 2px 10px black';
  container.style.position = 'fixed';
  container.style.left = 'calc(50% - 255px)';
  container.style.top = '10%';

  var closeButton = document.createElement('button');
  closeButton.style.position = 'absolute';
  closeButton.style.height = '30px';
  closeButton.style.width = '30px';
  closeButton.style.right = '-15px';
  closeButton.style.top = '-15px';
  closeButton.style.border = '5px solid white';
  closeButton.style.borderRadius = '20px';
  closeButton.style.backgroundColor = 'white';
  closeButton.style.boxShadow = '0px 0px 1px black';
  closeButton.style.backgroundImage = 'url(' + SERVER_URL + '/img/emoji/heavy_multiplication_x.png)';
  closeButton.style.backgroundRepeat = 'no-repeat';
  closeButton.style.backgroundPosition = 'center';
  closeButton.style.backgroundSize = 'contain';
  closeButton.style.cursor = 'pointer';

  closeButton.onclick = function () {
    container.parentNode.removeChild(container);
  };

  container.appendChild(closeButton);
  container.appendChild(frame);
  document.body.appendChild(container);
};

toggleEmojiBookmarklet();
<commit_msg>change bookmarklet server url<commit_after>var toggleEmojiBookmarklet = function () {
  //var SERVER_URL = 'http://localhost:8000';
  var SERVER_URL = 'https://johannhof.github.io/emoji-helper/bookmarklet/';

  var container = document.createElement('div');
  var frame = document.createElement('iframe');
  frame.src = SERVER_URL;

  frame.style.height = '350px';
  frame.style.width = '510px';
  frame.style.border = '1px solid lightgray';

  container.style.height = '350px';
  container.style.width = '510px';
  container.style.boxShadow = '2px 2px 10px black';
  container.style.position = 'fixed';
  container.style.left = 'calc(50% - 255px)';
  container.style.top = '10%';

  var closeButton = document.createElement('button');
  closeButton.style.position = 'absolute';
  closeButton.style.height = '30px';
  closeButton.style.width = '30px';
  closeButton.style.right = '-15px';
  closeButton.style.top = '-15px';
  closeButton.style.border = '5px solid white';
  closeButton.style.borderRadius = '20px';
  closeButton.style.backgroundColor = 'white';
  closeButton.style.boxShadow = '0px 0px 1px black';
  closeButton.style.backgroundImage = 'url(' + SERVER_URL + '/img/emoji/heavy_multiplication_x.png)';
  closeButton.style.backgroundRepeat = 'no-repeat';
  closeButton.style.backgroundPosition = 'center';
  closeButton.style.backgroundSize = 'contain';
  closeButton.style.cursor = 'pointer';

  closeButton.onclick = function () {
    container.parentNode.removeChild(container);
  };

  container.appendChild(closeButton);
  container.appendChild(frame);
  document.body.appendChild(container);
};

toggleEmojiBookmarklet();
<|endoftext|>


<commit_before>import { uid } from 'quasar'

export default class Proton {
  static invoke (args) {
    external.invoke(JSON.stringify(args))
  }

  static transformCallback (callback) {
    const identifier = uid()
    window[identifier] = (result) => {
      delete window[identifier]
      callback(result)
    }
    return identifier
  }

  static promisified (args) {
    return new Promise((resolve, reject) => {
      this.invoke({
        callback: this.transformCallback(resolve),
        error: this.transformCallback(reject),
        ...args
      })
    })
  }

  static readTextFile (path) {
    return this.promisified({ cmd: 'readAsString', path })
  }

  static readBinaryFile (path) {
    return this.promisified({ cmd: 'readAsBinary', path })
  }

  static writeFile (cfg) {
    this.invoke({ cmd: 'write', file: cfg.file, contents: cfg.contents })
  }

  static listFiles (path) {
    return this.promisified({ cmd: 'list', path })
  }

  static listDirs (path) {
    return this.promisified({ cmd: 'read', path })
  }

  static setTitle (title) {
    this.invoke({ cmd: 'setTitle', title })
  }

  static execute (command, args) {
    return this.promisified({ cmd: 'call', command, args: typeof (args) === 'string' ? [args] : args })
  }
}
<commit_msg>feat(whitelist) introduce whitelisting<commit_after>/**
 * THIS FILE IS GENERATED AUTOMATICALLY.
 * DO NOT EDIT.
 *
 * Please whitelist these API functions in quasar.conf.js
 *
 **/

import { uid } from 'quasar'
<% if (ctx.dev) { %>
/**
 *
 * @param {String} func - function name to warn
 * @private
 */
const __whitelistWarning = function (func) {
  console.warn('%c[Proton] Danger \nproton.' + func + ' not whitelisted 💣\n%c\nAdd to quasar.conf.js: \n\nproton: \n  whitelist: { \n    ' + func + ': true \n\nReference: https://quasar.dev/quasar-cli/creating-proton-apps/api#' + func , 'background: red; color: white; font-weight: 800; padding: 2px; font-size:1.5em', ' ')
}
<% } %>

/**
 *
 * @type {Promise<any>}
 * @private
 */
const __reject = new Promise((reject) => { reject })

/**
 *
 * @param name
 * @returns {boolean|*}
 * @private
 */
const __whitelist = function (name) {
  // seems that this isn't available in lodash.template :(
  return proton.whitelist[name] === true;
}

export default class Proton {

<% if (ctx.dev) { %>
  /**
   *
   * @param {Object} args
   */
<% } %>
  static invoke (args) {
    external.invoke(JSON.stringify(args))
  }

<% if (ctx.dev) { %>
  /**
   *
   * @param callback
   * @returns {*}
   */
<% } %>
  static transformCallback (callback) {
    const identifier = uid()
    window[identifier] = (result) => {
      delete window[identifier]
      callback(result)
    }
    return identifier
  }

<% if (ctx.dev) { %>
  /**
   *
   * @param args
   * @returns {Promise<any>}
   */
<% } %>
  static promisified (args) {
    return new Promise((resolve, reject) => {
      this.invoke({
        callback: this.transformCallback(resolve),
        error: this.transformCallback(reject),
        ...args
      })
    })
  }

<% if (ctx.dev) { %>
  /**
   *
   * @param path
   * @returns {*|Promise<any>|Promise}
   */
<% } %>
  static readTextFile (path) {
  <% if (proton.whitelist.readTextFile === true) { %>
    return this.promisified({ cmd: 'readAsString', path })
  <% } %>
  }

<% if (ctx.dev) { %>
  /**
   *
   * @param path
   * @returns {*|Promise<any>|Promise}
   */
<% } %>
  static readBinaryFile (path) {
  <% if (proton.whitelist.readBinaryFile === true) { %>
    return this.promisified({ cmd: 'readAsBinary', path })
  <% } %>
  }

<% if (ctx.dev) { %>
  /**
   *
   * @param cfg
   */
<% } %>
  static writeFile (cfg) {
  <% if (proton.whitelist.writeFile === true) { %>
    this.invoke({ cmd: 'write', file: cfg.file, contents: cfg.contents })
  <% } %>
  }

<% if (ctx.dev) { %>
  /**
   *
   * @param path
   * @returns {*|Promise<any>|Promise}
   */
<% } %>
  static listFiles (path) {
  <% if (proton.whitelist.listFiles === true) { %>
    return this.promisified({ cmd: 'list', path })
  <% } %>
  }

<% if (ctx.dev) { %>
  /**
   *
   * @param path
   * @returns {*|Promise<any>|Promise}
   */
<% } %>
  static listDirs (path) {
  <% if (proton.whitelist.listDirs === true) { %>
    return this.promisified({ cmd: 'read', path })
  <% } %>
  }

<% if (ctx.dev) { %>
  /**
   *
   * @param title
   */
<% } %>
  static setTitle (title) {
    <% if (proton.whitelist.setTitle === true) { %>
      this.invoke({ cmd: 'setTitle', title })
    <% } %>
  }

<% if (ctx.dev) { %>
  /**
   *
   * @param command
   * @param args
   * @returns {*|Promise<any>|Promise}
   */
<% } %>
  static execute (command, args) {
    <% if (proton.whitelist.execute === true) { %>
    return this.promisified({ cmd: 'call', command, args: typeof (args) === 'string' ? [args] : args })
  <% } else { %>
  <% if (ctx.dev) { %>
    __whitelistWarning('execute')
    <% } %>
    return __reject
      <% } %>
  }

<% if (ctx.dev) { %>
  /**
   *
   * @param command
   * @param payload
   * @returns {*|Promise<any>|Promise}
   */
<% } %>
  static bridge (command, payload) {
<% if (proton.whitelist.bridge === true) { %>
    return this.promisified({ cmd: 'bridge', command, payload: typeof (payload) === 'object' ? [payload] : payload })
<% } else { %>
<% if (ctx.dev) { %>
    __whitelistWarning('bridge')
<% } %>
      return __reject
<% } %>
  }
}
<|endoftext|>


<commit_before>var _ = require('alloy/underscore')._,
	db;

var ALLOY_DB = '_alloy_';

function S4() {
   return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
};

function guid() {
   return (S4()+S4()+'-'+S4()+'-'+S4()+'-'+S4()+'-'+S4()+S4()+S4());
};

function InitAdapter(config) {
	if (!db) {
		if (Ti.Platform.osname === 'mobileweb' || typeof Ti.Database === 'undefined') {
			throw 'No support for Titanium.Database in MobileWeb environment.';
		}
		else {
			db = Ti.Database.open('_alloy_');
		}
		module.exports.db = db;

		// create the migration table in case it doesn't exist
		db.execute('CREATE TABLE IF NOT EXISTS migrations (latest TEXT, model TEXT)');
	}
	return {};
}

function GetMigrationFor(table) {
	var mid;
	// get the latest migratino
	var rs = db.execute('SELECT latest FROM migrations where model = ?', table);
	if (rs.isValidRow()) {
		mid = rs.field(0);
	}
	rs.close();
	return mid;
}

function SQLiteMigrateDB() {
	//TODO: normalize columns at compile time - https://jira.appcelerator.org/browse/ALOY-222
	this.column = function(name)
	{
		switch(name)
		{
			case 'string':
			case 'varchar':
			case 'text':
			{
				return 'TEXT';
			}
			case 'int':
			case 'tinyint':
			case 'smallint':
			case 'bigint':
			case 'integer':
			{
				return 'INTEGER';
			}
			case 'double':
			case 'float':
			case 'real':
			{
				return 'REAL';
			}
			case 'blob':
			{
				return 'BLOB';
			}
			case 'decimal':
			case 'number':
			case 'date':
			case 'datetime':
			case 'boolean':
			{
				return 'NUMERIC';
			}
			case 'null':
			{
				return 'NULL';
			}
		}
		return 'TEXT';
	};

	this.createTable = function(config) {
		Ti.API.info('create table migration called for '+config.adapter.collection_name);

		var self = this,
			columns = [];

		for (var k in config.columns) {
			columns.push(k+" "+self.column(config.columns[k]));
		}

		var sql = 'CREATE TABLE IF NOT EXISTS '+config.adapter.collection_name+' ( '+columns.join(',')+',id' + ' )';
		Ti.API.info(sql);

		db.execute(sql);
	};

	this.dropTable = function(name) {
		Ti.API.info('drop table migration called for '+name);
		db.execute('DROP TABLE IF EXISTS '+name);
	};
}

function Sync(model, method, opts) {
	var table =  model.config.adapter.collection_name,
		columns = model.config.columns,
		resp = null;

	switch (method) {
		case 'create':
			resp = (function(){
				// Use idAttribute to account for something other then "id"
				// being used for the model's id.
				if (!model.id) {
	                model.id = guid();
	                model.set(model.idAttribute, model.id);
	            }

	            // Create arrays for insert query
				var names = [], values = [], q = [];
				for (var k in columns) {
					names.push(k);
					values.push(model.get(k));
					q.push('?');
				}

				// Assemble create query
				var sql = "INSERT INTO " + table + " (" + names.join(",") + ",id) VALUES (" + q.join(",") + ",?)";

				// add id as the last value to the query
	            values.push(model.id);

	            // execute the query and return the response
	            db.execute(sql, values);
	            return model.toJSON();
			})();
			break;
		case 'read':
			var sql = 'SELECT * FROM '+table;
			var rs = db.execute(sql);
			var len = 0;
			var values = [];
			while(rs.isValidRow())
			{
				var o = {};
                var fc = 0;

                // Pre-3.0.0, Android supported fieldCount as a property, iOS
                // supported it as a function. Post-3.0.0, both are a property.
				fc = _.isFunction(rs.fieldCount) ? rs.fieldCount() : rs.fieldCount;

				_.times(fc,function(c){
					var fn = rs.fieldName(c);
					o[fn] = rs.fieldByName(fn);
				});
				values.push(o);
				len++;
				rs.next();
			}
			rs.close();
			model.length = len;
			len === 1 ? resp = values[0] : resp = values;
			break;

		case 'update':
			var names = [];
			var values = [];
			var q = [];
			for (var k in columns)
			{
				names.push(k+'=?');
				values.push(model.get(k));
				q.push('?');
			}
			var sql = 'UPDATE '+table+' SET '+names.join(',')+' WHERE id=?';

		    var e = sql +','+values.join(',')+','+model.id;
		    values.push(model.id);
			db.execute(sql,values);
			resp = model.toJSON();
			break;

		case 'delete':
			var sql = 'DELETE FROM '+table+' WHERE id=?';
			db.execute(sql, model.id);
			model.id = null;
			resp = model.toJSON();
			break;
	}

    // process success/error handlers, if present
	if (resp) {
        _.isFunction(opts.success) && opts.success(resp);
        method === "read" && model.trigger("fetch");
    } else {
    	_.isFunction(opts.error) && opts.error("Record not found");
    }

}

function GetMigrationForCached(t,m) {
	if (m[t]) {
		return m[t];
	}
	var v = GetMigrationFor(t);
	if (v) {
		m[t] = v;
	}
	return v;
}

function Migrate(migrations, config) {
	var prev;
	var sqlMigration = new SQLiteMigrateDB;
	var migrationIds = {}; // cache for latest mid by model name

	db.execute('BEGIN;');

	if (migrations.length) {
		// iterate through all our migrations and call up/down and the last migration should
		// have the up called but never the down -- the migrations come in pre sorted from
		// oldest to newest based on timestamp
		_.each(migrations,function(migration) {
			var mctx = {};
			migration(mctx);
			var mid = GetMigrationForCached(mctx.name,migrationIds);
			Ti.API.info('mid = '+mid+', name = '+mctx.name);
			if (!mid || mctx.id > mid) {
				Ti.API.info('Migration starting to '+mctx.id+' for '+mctx.name);
				if (prev && _.isFunction(prev.down)) {
					prev.down(sqlMigration);
				}
				if (_.isFunction(mctx.up)) {
					mctx.down(sqlMigration);
					mctx.up(sqlMigration);
				}
				prev = mctx;
			}
			else {
				Ti.API.info('skipping migration '+mctx.id+', already performed');
				prev = null;
			}
		});

		if (prev && prev.id) {
			db.execute('DELETE FROM migrations where model = ?', prev.name);
			db.execute('INSERT INTO migrations VALUES (?,?)', prev.id,prev.name);
		}
	} else {
		sqlMigration.createTable(config);
	}

	db.execute('COMMIT;');
}

module.exports.sync = Sync;

module.exports.beforeModelCreate = function(config) {
	config = config || {};

    InitAdapter(config);

	return config;
};

module.exports.afterModelCreate = function(Model) {
	Model = Model || {};

	Model.prototype.config.Model = Model; // needed for fetch operations to initialize the collection from persistent store

	Migrate(Model.migrations, Model.prototype.config);

	return Model;
};

<commit_msg>Add pre-loaded db support for sql adapter<commit_after>var _ = require('alloy/underscore')._,
	db;

var ALLOY_DB_DEFAULT = '_alloy_';

function S4() {
   return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
};

function guid() {
   return (S4()+S4()+'-'+S4()+'-'+S4()+'-'+S4()+'-'+S4()+S4()+S4());
};

function InitAdapter(config) {
	if (!db) {
		if (Ti.Platform.osname === 'mobileweb' || typeof Ti.Database === 'undefined') {
			throw 'No support for Titanium.Database in MobileWeb environment.';
		}
		else {
			var dbfile = config.adapter.db;
			if (dbfile) {
				var rx = /^(\/{0,1})(.+)\.(.+)$/;
				var match = dbfile.match(rx);
				if (match !== null) {
					var file = (match[1] || '/') + match[2] + '.' + match[3];
					var name = match[2];
					db = Ti.Database.install(file, name);
				} else {
					// invalid db file name
				}
			} else {
				db = Ti.Database.open(ALLOY_DB_DEFAULT);
			}
		}
		module.exports.db = db;

		// create the migration table in case it doesn't exist
		db.execute('CREATE TABLE IF NOT EXISTS migrations (latest TEXT, model TEXT)');
	}
	return {};
}

function GetMigrationFor(table) {
	var mid;
	// get the latest migratino
	var rs = db.execute('SELECT latest FROM migrations where model = ?', table);
	if (rs.isValidRow()) {
		mid = rs.field(0);
	}
	rs.close();
	return mid;
}

function SQLiteMigrateDB() {
	//TODO: normalize columns at compile time - https://jira.appcelerator.org/browse/ALOY-222
	this.column = function(name)
	{
		switch(name)
		{
			case 'string':
			case 'varchar':
			case 'text':
			{
				return 'TEXT';
			}
			case 'int':
			case 'tinyint':
			case 'smallint':
			case 'bigint':
			case 'integer':
			{
				return 'INTEGER';
			}
			case 'double':
			case 'float':
			case 'real':
			{
				return 'REAL';
			}
			case 'blob':
			{
				return 'BLOB';
			}
			case 'decimal':
			case 'number':
			case 'date':
			case 'datetime':
			case 'boolean':
			{
				return 'NUMERIC';
			}
			case 'null':
			{
				return 'NULL';
			}
		}
		return 'TEXT';
	};

	this.createTable = function(config) {
		Ti.API.info('create table migration called for '+config.adapter.collection_name);

		var self = this,
			columns = [];

		for (var k in config.columns) {
			columns.push(k+" "+self.column(config.columns[k]));
		}

		var sql = 'CREATE TABLE IF NOT EXISTS '+config.adapter.collection_name+' ( '+columns.join(',')+',id' + ' )';
		Ti.API.info(sql);

		db.execute(sql);
	};

	this.dropTable = function(name) {
		Ti.API.info('drop table migration called for '+name);
		db.execute('DROP TABLE IF EXISTS '+name);
	};
}

function Sync(model, method, opts) {
	var table =  model.config.adapter.collection_name,
		columns = model.config.columns,
		resp = null;

	switch (method) {
		case 'create':
			resp = (function(){
				// Use idAttribute to account for something other then "id"
				// being used for the model's id.
				if (!model.id) {
	                model.id = guid();
	                model.set(model.idAttribute, model.id);
	            }

	            // Create arrays for insert query
				var names = [], values = [], q = [];
				for (var k in columns) {
					names.push(k);
					values.push(model.get(k));
					q.push('?');
				}

				// Assemble create query
				var sql = "INSERT INTO " + table + " (" + names.join(",") + ",id) VALUES (" + q.join(",") + ",?)";

				// add id as the last value to the query
	            values.push(model.id);

	            // execute the query and return the response
	            db.execute(sql, values);
	            return model.toJSON();
			})();
			break;
		case 'read':
			var sql = 'SELECT * FROM '+table;
			var rs = db.execute(sql);
			var len = 0;
			var values = [];
			while(rs.isValidRow())
			{
				var o = {};
                var fc = 0;

                // Pre-3.0.0, Android supported fieldCount as a property, iOS
                // supported it as a function. Post-3.0.0, both are a property.
				fc = _.isFunction(rs.fieldCount) ? rs.fieldCount() : rs.fieldCount;

				_.times(fc,function(c){
					var fn = rs.fieldName(c);
					o[fn] = rs.fieldByName(fn);
				});
				values.push(o);
				len++;
				rs.next();
			}
			rs.close();
			model.length = len;
			len === 1 ? resp = values[0] : resp = values;
			break;

		case 'update':
			var names = [];
			var values = [];
			var q = [];
			for (var k in columns)
			{
				names.push(k+'=?');
				values.push(model.get(k));
				q.push('?');
			}
			var sql = 'UPDATE '+table+' SET '+names.join(',')+' WHERE id=?';

		    var e = sql +','+values.join(',')+','+model.id;
		    values.push(model.id);
			db.execute(sql,values);
			resp = model.toJSON();
			break;

		case 'delete':
			var sql = 'DELETE FROM '+table+' WHERE id=?';
			db.execute(sql, model.id);
			model.id = null;
			resp = model.toJSON();
			break;
	}

    // process success/error handlers, if present
	if (resp) {
        _.isFunction(opts.success) && opts.success(resp);
        method === "read" && model.trigger("fetch");
    } else {
    	_.isFunction(opts.error) && opts.error("Record not found");
    }

}

function GetMigrationForCached(t,m) {
	if (m[t]) {
		return m[t];
	}
	var v = GetMigrationFor(t);
	if (v) {
		m[t] = v;
	}
	return v;
}

function Migrate(migrations, config) {
	var prev;
	var sqlMigration = new SQLiteMigrateDB;
	var migrationIds = {}; // cache for latest mid by model name

	db.execute('BEGIN;');

	if (migrations.length) {
		// iterate through all our migrations and call up/down and the last migration should
		// have the up called but never the down -- the migrations come in pre sorted from
		// oldest to newest based on timestamp
		_.each(migrations,function(migration) {
			var mctx = {};
			migration(mctx);
			var mid = GetMigrationForCached(mctx.name,migrationIds);
			Ti.API.info('mid = '+mid+', name = '+mctx.name);
			if (!mid || mctx.id > mid) {
				Ti.API.info('Migration starting to '+mctx.id+' for '+mctx.name);
				if (prev && _.isFunction(prev.down)) {
					prev.down(sqlMigration);
				}
				if (_.isFunction(mctx.up)) {
					mctx.down(sqlMigration);
					mctx.up(sqlMigration);
				}
				prev = mctx;
			}
			else {
				Ti.API.info('skipping migration '+mctx.id+', already performed');
				prev = null;
			}
		});

		if (prev && prev.id) {
			db.execute('DELETE FROM migrations where model = ?', prev.name);
			db.execute('INSERT INTO migrations VALUES (?,?)', prev.id,prev.name);
		}
	} else {
		sqlMigration.createTable(config);
	}

	db.execute('COMMIT;');
}

module.exports.sync = Sync;

module.exports.beforeModelCreate = function(config) {
	config = config || {};

    InitAdapter(config);

	return config;
};

module.exports.afterModelCreate = function(Model) {
	Model = Model || {};

	Model.prototype.config.Model = Model; // needed for fetch operations to initialize the collection from persistent store

	Migrate(Model.migrations, Model.prototype.config);

	return Model;
};

<|endoftext|>


<commit_before>var _ = require('alloy/underscore')._,
	util = require('alloy/sync/util');

// The database name used when none is specified in the
// model configuration.
var ALLOY_DB_DEFAULT = '_alloy_';

// The sql-specific migration object, which is the main parameter
// to the up() and down() migration functions
function SQLiteMigrateDB(dbname, table) {
	this.dbname = dbname;
	this.table = table;

	//TODO: normalize columns at compile time - https://jira.appcelerator.org/browse/ALOY-222
	this.column = function(name) {
		// split into parts to keep additional column characteristics like
		// autoincrement, primary key, etc...
		var parts = name.split(/\s+/);
		var type = parts[0]
		switch(type.toLowerCase()) {
			case 'string':
			case 'varchar':
			case 'date':
			case 'datetime':
				Ti.API.warn('"' + type + '" is not a valid sqlite field, using TEXT instead');
			case 'text':
				type = 'TEXT';
				break;
			case 'int':
			case 'tinyint':
			case 'smallint':
			case 'bigint':
			case 'boolean':
				Ti.API.warn('"' + type + '" is not a valid sqlite field, using INTEGER instead');
			case 'integer':
				type = 'INTEGER';
				break;
			case 'double':
			case 'float':
			case 'decimal':
			case 'number':
				Ti.API.warn('"' + name + '" is not a valid sqlite field, using REAL instead');
			case 'real':
				type = 'REAL';
				break;
			case 'blob':
				type = 'BLOB';
				break;
			case 'null':
				type = 'NULL';
				break;
			default:
				type = 'TEXT';
				break;
		}
		parts[0] = type;
		return parts.join(' ');
	};

	this.createTable = function(config) {
		var columns = [];
		for (var k in config.columns) {
			columns.push(k+" "+this.column(config.columns[k]));
		}
		var fields = columns.join(',');
		var sql = 'CREATE TABLE IF NOT EXISTS ' + this.table + ' ( ' + fields + ',id)';

		// execute the create
		var db = Ti.Database.open(this.dbname);
		db.execute(sql);
		db.close();
	};

	this.dropTable = function(config) {
		var db = Ti.Database.open(this.dbname);
		db.execute('DROP TABLE IF EXISTS ' + this.table);
		db.close();
	};

	this.installDatabase = function(dbFile) {
		var db = Ti.Database.install(dbFile);
		db.close();
	}

	this.insert = function(columnValues) {;
		var columns = [];
		var values = [];
		var qs = [];

		// get arrays of column names, values, and value placeholders
		var found = false;
		for (var key in columnValues) {
			key === 'id' && (found = true);
			columns.push(key);
			values.push(columnValues[key]);
			qs.push('?');
		}

		// add the id field if it wasn't specified
		if (!found) {
			columns.push('id');
			values.push(util.guid());
			qs.push('?');
		}

		// construct and execute the query
		var db = Ti.Database.open(this.dbname);
		db.execute('INSERT INTO ' + this.table + ' (' + columns.join(',') + ') VALUES (' + qs.join(',') + ');', values);
		db.close();
	}
}

function Sync(model, method, opts) {
	var table =  model.config.adapter.collection_name,
		columns = model.config.columns,
		dbName = model.config.adapter.db_name || ALLOY_DB_DEFAULT,
		resp = null,
		db;

	switch (method) {
		case 'create':
			resp = (function(){
				// Use idAttribute to account for something other then "id"
				// being used for the model's id.
				if (!model.id) {
	                model.id = util.guid();
	                model.set(model.idAttribute, model.id);
	            }

	            // Create arrays for insert query
				var names = [], values = [], q = [];
				for (var k in columns) {
					names.push(k);
					values.push(model.get(k));
					q.push('?');
				}

				// Assemble create query
				var sql = "INSERT INTO " + table + " (" + names.join(",") + ",id) VALUES (" + q.join(",") + ",?)";
	            values.push(model.id);

	            // execute the query and return the response
	            db = Ti.Database.open(dbName);
	            db.execute(sql, values);
	            db.close();

	            return model.toJSON();
			})();
			break;
		case 'read':
			// TODO: Allow custom queries. https://jira.appcelerator.org/browse/ALOY-458
			var sql = 'SELECT * FROM '+table;

			// execute the select query
			db = Ti.Database.open(dbName);
			var rs = db.execute(sql);

			var len = 0;
			var values = [];

			// iterate through all queried rows
			while(rs.isValidRow())
			{
				var o = {};
                var fc = 0;

                // Pre-3.0.0, Android supported fieldCount as a property, iOS
                // supported it as a function. Post-3.0.0, both are a property.
                // TODO: https://jira.appcelerator.org/browse/ALOY-459
				fc = _.isFunction(rs.fieldCount) ? rs.fieldCount() : rs.fieldCount;

				// create list of rows returned from query
				_.times(fc,function(c){
					var fn = rs.fieldName(c);
					o[fn] = rs.fieldByName(fn);
				});
				values.push(o);

				len++;
				rs.next();
			}

			// close off db after read query
			rs.close();
			db.close();

			// shape response based on whether it's a model or collection
			model.length = len;
			len === 1 ? resp = values[0] : resp = values;
			break;

		case 'update':
			var names = [];
			var values = [];
			var q = [];

			// create the list of columns
			for (var k in columns)
			{
				names.push(k+'=?');
				values.push(model.get(k));
				q.push('?');
			}

			// compose the update query
			var sql = 'UPDATE '+table+' SET '+names.join(',')+' WHERE ' + model.idAttribute + '=?';
		    //var e = sql +','+values.join(',')+','+model.id;
		    values.push(model.id);

		    // execute the update
		    db = Ti.Database.open(dbName);
			db.execute(sql,values);
			db.close();

			resp = model.toJSON();
			break;

		case 'delete':
			var sql = 'DELETE FROM '+table+' WHERE ' + model.idAttribute + '=?';

			// execute the delete
			db = Ti.Database.open(dbName);
			db.execute(sql, model.id);
			db.close();

			model.id = null;
			resp = model.toJSON();
			break;
	}

    // process success/error handlers, if present
	if (resp) {
        _.isFunction(opts.success) && opts.success(resp);
        method === "read" && model.trigger("fetch");
    } else {
    	_.isFunction(opts.error) && opts.error("Record not found");
    }

}

// Gets the current saved migration
function GetMigrationFor(dbname, table) {
	var db = Ti.Database.open(dbname);
	db.execute('CREATE TABLE IF NOT EXISTS migrations (latest TEXT, model TEXT)');
	var rs = db.execute('SELECT latest FROM migrations where model = ?', table);
	if (rs.isValidRow()) {
		var mid = rs.field(0);
		rs.close();
		db.close()
		return mid + '';
	}
	db.close()
	return null;
}

function Migrate(Model) {
	// get list of migrations for this model
	var migrations = Model.migrations || [];

	// get a reference to the last migration
	var lastMigration = {};
	migrations.length && migrations[migrations.length-1](lastMigration);

	// Get config reference
	var config = Model.prototype.config;

	// Get the migration number from the config, or use the number of
	// the last migration if it's not present. If we still don't have a
	// migration number after that, that means there are none. There's
	// no migrations to perform.
	var targetNumber = typeof config.adapter.migration === 'undefined' ||
		config.adapter.migration === null ? lastMigration.id : config.adapter.migration;
	if (typeof targetNumber === 'undefined' || targetNumber === null) {
		return;
	}
	targetNumber = targetNumber + ''; // ensure that it's a string

	// Get the db name for this model and set up the sql migration obejct
	config.adapter.db_name || (config.adapter.db_name = ALLOY_DB_DEFAULT);
	var sqliteMigrationDb = new SQLiteMigrateDB(config.adapter.db_name, config.adapter.collection_name);

	// Create the migration tracking table if it doesn't already exist.
	// Get the current saved migration number.
	var currentNumber = GetMigrationFor(config.adapter.db_name, config.adapter.collection_name);

	// If the current and requested migrations match, the data structures
	// match and there is no need to run the migrations.
	var direction;
	if (currentNumber === targetNumber) {
		return;
	} else if (currentNumber && currentNumber > targetNumber) {
		direction = 0; // rollback
		migrations.reverse();
	} else {
		direction = 1;  // upgrade
	}

	// open db for our migration transaction
	db = Ti.Database.open(config.adapter.db_name);
	db.execute('BEGIN;');

	// iterate through all migrations based on the current and requested state,
	// applying all appropriate migrations, in order, to the database.
	if (migrations.length) {
		for (var i = 0; i < migrations.length; i++) {
			// create the migration context
			var migration = migrations[i];
			var context = {};
			migration(context);

			// if upgrading, skip migrations higher than the target
			// if rolling back, skip migrations lower than the target
			if (direction && context.id > targetNumber) { break; }
			if (!direction && context.id <= targetNumber) { break; }

			// execute the appropriate migration function
			var funcName = direction ? 'up' : 'down';
			if (_.isFunction(context[funcName])) {
				context[funcName](sqliteMigrationDb, db);
			}
		}
	} else {
		sqliteMigrationDb.createTable(config);
	}

	// update the saved migration in the db
	db.execute('DELETE FROM migrations where model = ?', config.adapter.collection_name);
	db.execute('INSERT INTO migrations VALUES (?,?)', targetNumber, config.adapter.collection_name);

	// end the migration transaction
	db.execute('COMMIT;');
	db.close();
}

module.exports.sync = Sync;

module.exports.beforeModelCreate = function(config) {
	// validate the current platform
	if (Ti.Platform.osname === 'mobileweb' || typeof Ti.Database === 'undefined') {
		throw 'No support for Titanium.Database in MobileWeb environment.';
	}
	return config;
};

module.exports.afterModelCreate = function(Model) {
	Model || (Model = {});

	// needed for fetch operations to initialize the collection from persistent store
	//Model.prototype.config.Model = Model;

	//Migrate(Model.migrations, Model.prototype.config);
	Migrate(Model);

	return Model;
};
<commit_msg>formatting and cleanup<commit_after>var _ = require('alloy/underscore')._,
	util = require('alloy/sync/util');

// The database name used when none is specified in the
// model configuration.
var ALLOY_DB_DEFAULT = '_alloy_';

// The sql-specific migration object, which is the main parameter
// to the up() and down() migration functions
function SQLiteMigrateDB(dbname, table) {
	this.dbname = dbname;
	this.table = table;

	//TODO: normalize columns at compile time - https://jira.appcelerator.org/browse/ALOY-222
	this.column = function(name) {
		// split into parts to keep additional column characteristics like
		// autoincrement, primary key, etc...
		var parts = name.split(/\s+/);
		var type = parts[0]
		switch(type.toLowerCase()) {
			case 'string':
			case 'varchar':
			case 'date':
			case 'datetime':
				Ti.API.warn('"' + type + '" is not a valid sqlite field, using TEXT instead');
			case 'text':
				type = 'TEXT';
				break;
			case 'int':
			case 'tinyint':
			case 'smallint':
			case 'bigint':
			case 'boolean':
				Ti.API.warn('"' + type + '" is not a valid sqlite field, using INTEGER instead');
			case 'integer':
				type = 'INTEGER';
				break;
			case 'double':
			case 'float':
			case 'decimal':
			case 'number':
				Ti.API.warn('"' + name + '" is not a valid sqlite field, using REAL instead');
			case 'real':
				type = 'REAL';
				break;
			case 'blob':
				type = 'BLOB';
				break;
			case 'null':
				type = 'NULL';
				break;
			default:
				type = 'TEXT';
				break;
		}
		parts[0] = type;
		return parts.join(' ');
	};

	this.createTable = function(config) {
		var columns = [];
		for (var k in config.columns) {
			columns.push(k+" "+this.column(config.columns[k]));
		}
		var fields = columns.join(',');
		var sql = 'CREATE TABLE IF NOT EXISTS ' + this.table + ' ( ' + fields + ',id)';

		// execute the create
		var db = Ti.Database.open(this.dbname);
		db.execute(sql);
		db.close();
	};

	this.dropTable = function(config) {
		var db = Ti.Database.open(this.dbname);
		db.execute('DROP TABLE IF EXISTS ' + this.table);
		db.close();
	};

	this.installDatabase = function(dbFile) {
		var db = Ti.Database.install(dbFile);
		db.close();
	}

	this.insert = function(columnValues) {;
		var columns = [];
		var values = [];
		var qs = [];

		// get arrays of column names, values, and value placeholders
		var found = false;
		for (var key in columnValues) {
			key === 'id' && (found = true);
			columns.push(key);
			values.push(columnValues[key]);
			qs.push('?');
		}

		// add the id field if it wasn't specified
		if (!found) {
			columns.push('id');
			values.push(util.guid());
			qs.push('?');
		}

		// construct and execute the query
		var db = Ti.Database.open(this.dbname);
		db.execute('INSERT INTO ' + this.table + ' (' + columns.join(',') + ') VALUES (' + qs.join(',') + ');', values);
		db.close();
	}
}

function Sync(model, method, opts) {
	var table =  model.config.adapter.collection_name,
		columns = model.config.columns,
		dbName = model.config.adapter.db_name || ALLOY_DB_DEFAULT,
		resp = null,
		db;

	switch (method) {
		case 'create':
			resp = (function(){
				// Use idAttribute to account for something other then "id"
				// being used for the model's id.
				if (!model.id) {
	                model.id = util.guid();
	                model.set(model.idAttribute, model.id);
	            }

	            // Create arrays for insert query
				var names = [], values = [], q = [];
				for (var k in columns) {
					names.push(k);
					values.push(model.get(k));
					q.push('?');
				}

				// Assemble create query
				var sql = "INSERT INTO " + table + " (" + names.join(",") + ",id) VALUES (" + q.join(",") + ",?)";
	            values.push(model.id);

	            // execute the query and return the response
	            db = Ti.Database.open(dbName);
	            db.execute(sql, values);
	            db.close();

	            return model.toJSON();
			})();
			break;
		case 'read':
			// TODO: Allow custom queries. https://jira.appcelerator.org/browse/ALOY-458
			var sql = 'SELECT * FROM '+table;

			// execute the select query
			db = Ti.Database.open(dbName);
			var rs = db.execute(sql);

			var len = 0;
			var values = [];

			// iterate through all queried rows
			while(rs.isValidRow())
			{
				var o = {};
                var fc = 0;

                // Pre-3.0.0, Android supported fieldCount as a property, iOS
                // supported it as a function. Post-3.0.0, both are a property.
                // TODO: https://jira.appcelerator.org/browse/ALOY-459
				fc = _.isFunction(rs.fieldCount) ? rs.fieldCount() : rs.fieldCount;

				// create list of rows returned from query
				_.times(fc,function(c){
					var fn = rs.fieldName(c);
					o[fn] = rs.fieldByName(fn);
				});
				values.push(o);

				len++;
				rs.next();
			}

			// close off db after read query
			rs.close();
			db.close();

			// shape response based on whether it's a model or collection
			model.length = len;
			len === 1 ? resp = values[0] : resp = values;
			break;

		case 'update':
			var names = [];
			var values = [];
			var q = [];

			// create the list of columns
			for (var k in columns)
			{
				names.push(k+'=?');
				values.push(model.get(k));
				q.push('?');
			}

			// compose the update query
			var sql = 'UPDATE '+table+' SET '+names.join(',')+' WHERE ' + model.idAttribute + '=?';
		    //var e = sql +','+values.join(',')+','+model.id;
		    values.push(model.id);

		    // execute the update
		    db = Ti.Database.open(dbName);
			db.execute(sql,values);
			db.close();

			resp = model.toJSON();
			break;

		case 'delete':
			var sql = 'DELETE FROM '+table+' WHERE ' + model.idAttribute + '=?';

			// execute the delete
			db = Ti.Database.open(dbName);
			db.execute(sql, model.id);
			db.close();

			model.id = null;
			resp = model.toJSON();
			break;
	}

    // process success/error handlers, if present
	if (resp) {
        _.isFunction(opts.success) && opts.success(resp);
        method === "read" && model.trigger("fetch");
    } else {
    	_.isFunction(opts.error) && opts.error("Record not found");
    }

}

// Gets the current saved migration
function GetMigrationFor(dbname, table) {
	var db = Ti.Database.open(dbname);
	db.execute('CREATE TABLE IF NOT EXISTS migrations (latest TEXT, model TEXT)');
	var rs = db.execute('SELECT latest FROM migrations where model = ?', table);
	if (rs.isValidRow()) {
		var mid = rs.field(0);
		rs.close();
		db.close()
		return mid + '';
	}
	db.close()
	return null;
}

function Migrate(Model) {
	// get list of migrations for this model
	var migrations = Model.migrations || [];

	// get a reference to the last migration
	var lastMigration = {};
	migrations.length && migrations[migrations.length-1](lastMigration);

	// Get config reference
	var config = Model.prototype.config;

	// Get the migration number from the config, or use the number of
	// the last migration if it's not present. If we still don't have a
	// migration number after that, that means there are none. There's
	// no migrations to perform.
	var targetNumber = typeof config.adapter.migration === 'undefined' ||
		config.adapter.migration === null ? lastMigration.id : config.adapter.migration;
	if (typeof targetNumber === 'undefined' || targetNumber === null) {
		return;
	}
	targetNumber = targetNumber + ''; // ensure that it's a string

	// Get the db name for this model and set up the sql migration obejct
	config.adapter.db_name || (config.adapter.db_name = ALLOY_DB_DEFAULT);
	var sqliteMigrationDb = new SQLiteMigrateDB(config.adapter.db_name, config.adapter.collection_name);

	// Create the migration tracking table if it doesn't already exist.
	// Get the current saved migration number.
	var currentNumber = GetMigrationFor(config.adapter.db_name, config.adapter.collection_name);

	// If the current and requested migrations match, the data structures
	// match and there is no need to run the migrations.
	var direction;
	if (currentNumber === targetNumber) {
		return;
	} else if (currentNumber && currentNumber > targetNumber) {
		direction = 0; // rollback
		migrations.reverse();
	} else {
		direction = 1;  // upgrade
	}

	// open db for our migration transaction
	db = Ti.Database.open(config.adapter.db_name);
	db.execute('BEGIN;');

	// iterate through all migrations based on the current and requested state,
	// applying all appropriate migrations, in order, to the database.
	if (migrations.length) {
		for (var i = 0; i < migrations.length; i++) {
			// create the migration context
			var migration = migrations[i];
			var context = {};
			migration(context);

			// if upgrading, skip migrations higher than the target
			// if rolling back, skip migrations lower than the target
			if (direction && context.id > targetNumber) { break; }
			if (!direction && context.id <= targetNumber) { break; }

			// execute the appropriate migration function
			var funcName = direction ? 'up' : 'down';
			if (_.isFunction(context[funcName])) {
				context[funcName](sqliteMigrationDb, db);
			}
		}
	} else {
		sqliteMigrationDb.createTable(config);
	}

	// update the saved migration in the db
	db.execute('DELETE FROM migrations where model = ?', config.adapter.collection_name);
	db.execute('INSERT INTO migrations VALUES (?,?)', targetNumber, config.adapter.collection_name);

	// end the migration transaction
	db.execute('COMMIT;');
	db.close();
}

module.exports.sync = Sync;

module.exports.beforeModelCreate = function(config) {
	// validate the current platform
	if (Ti.Platform.osname === 'mobileweb' || typeof Ti.Database === 'undefined') {
		throw 'No support for Titanium.Database in MobileWeb environment.';
	}
	return config;
};

module.exports.afterModelCreate = function(Model) {
	Model || (Model = {});
	Migrate(Model);

	return Model;
};
<|endoftext|>


<commit_before>/* ==========================================================
 * bootstrap-maxlength.js v1.4.2
 *
 * Copyright (c) 2013 Maurizio Napoleoni;
 *
 * Licensed under the terms of the MIT license.
 * See: https://github.com/mimo84/bootstrap-maxlength/blob/master/LICENSE
 * ========================================================== */
(function(e){"use strict";e.fn.extend({maxlength:function(t,n){function s(e){var t=e.val(),n=t.match(/\n/g),r=n?n.length:0;return e.val().length+r}function o(e,n,r){var i=true;if(!t.alwaysShow&&r-s(e)>n){i=false}return i}function u(e,t){var n=t-s(e);return n}function a(e){e.css({display:"block"})}function f(e){e.css({display:"none"})}function l(e,n){var r="";if(t.message){r=t.message.replace("%charsTyped%",n).replace("%charsRemaining%",e-n).replace("%charsTotal%",e)}else{if(t.preText){r+=t.preText}if(!t.showCharsTyped){r+=e-n}else{r+=n}if(t.showMaxLength){r+=t.separator+e}if(t.postText){r+=t.postText}}return r}function c(e,n,r,i){i.html(l(r,r-e));if(e>0){if(o(n,t.threshold,r)){a(i.removeClass(t.limitReachedClass).addClass(t.warningClass))}else{f(i)}}else{a(i.removeClass(t.warningClass).addClass(t.limitReachedClass))}}function h(t){var n=t[0];return e.extend({},typeof n.getBoundingClientRect==="function"?n.getBoundingClientRect():{width:n.offsetWidth,height:n.offsetHeight},t.offset())}function p(e,n){var r=h(e),i=e.outerWidth(),s=n.outerWidth(),o=n.width(),u=n.height();switch(t.placement){case"bottom":n.css({top:r.top+r.height,left:r.left+r.width/2-o/2});break;case"top":n.css({top:r.top-u,left:r.left+r.width/2-o/2});break;case"left":n.css({top:r.top+r.height/2-u/2,left:r.left-o});break;case"right":n.css({top:r.top+r.height/2-u/2,left:r.left+r.width});break;case"bottom-right":n.css({top:r.top+r.height,left:r.left+r.width});break;case"top-right":n.css({top:r.top-u,left:r.left+i});break;case"top-left":n.css({top:r.top-u,left:r.left-s});break;case"bottom-left":n.css({top:r.top+e.outerHeight(),left:r.left-s});break;case"centered-right":n.css({top:r.top+u/2,left:r.left+i-s-3});break}}function d(e){return e.attr("maxlength")||e.attr("size")}var r=e("body"),i={alwaysShow:false,threshold:10,warningClass:"label label-success",limitReachedClass:"label label-important",separator:" / ",preText:"",postText:"",message:"",showMaxLength:true,placement:"bottom",showCharsTyped:true,validate:false};if(e.isFunction(t)&&!n){n=t;t={}}t=e.extend(i,t);return this.each(function(){var n=e(this),i=d(n),s=e("").css({display:"none",position:"absolute",whiteSpace:"nowrap",zIndex:999}).html(l(i,"0"));if(n.is("textarea")){n.data("maxlenghtsizex",n.outerWidth());n.data("maxlenghtsizey",n.outerHeight());n.mouseup(function(){if(n.outerWidth()!==n.data("maxlenghtsizex")||n.outerHeight()!==n.data("maxlenghtsizey")){p(n,s)}n.data("maxlenghtsizex",n.outerWidth());n.data("maxlenghtsizey",n.outerHeight())})}r.append(s);n.focus(function(){var e=u(n,d(n));c(e,n,i,s);p(n,s)});e(window).resize(function(){p(n,s)});n.blur(function(){s.css("display","none")});n.keyup(function(e){var r=u(n,d(n)),o=true,a=e.keyCode||e.which;if(r===0&&a===9&&!e.shiftKey){n.attr("maxlength",d(n)+1).trigger({type:"keypress",which:9}).attr("maxlength",d(n)-1)}if(t.validate&&r<0){o=false}else{c(r,n,i,s)}return o})})}})})(jQuery)<commit_msg>Minified.<commit_after>/* ==========================================================
 * bootstrap-maxlength.js v1.4.2
 *
 * Copyright (c) 2013 Maurizio Napoleoni;
 *
 * Licensed under the terms of the MIT license.
 * See: https://github.com/mimo84/bootstrap-maxlength/blob/master/LICENSE
 * ========================================================== */
(function(e){"use strict";e.fn.extend({maxlength:function(t,n){function s(e){var n=e.val();var r=n.match(/\n/g);var i=0;var s=0;if(t.utf8){i=r?getUTF8Length(r):0;s=getUTF8Length(e.val())+i}else{i=r?r.length:0;s=e.val().length+i}return s}function o(e){var t=0;for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t++}else if(r>127&&r<2048){t=t+2}else{t=t+3}}return t}function u(e,n,r){var i=true;if(!t.alwaysShow&&r-s(e)>n){i=false}return i}function a(e,t){var n=t-s(e);return n}function f(e){e.css({display:"block"})}function l(e){e.css({display:"none"})}function c(e,n){var r="";if(t.message){r=t.message.replace("%charsTyped%",n).replace("%charsRemaining%",e-n).replace("%charsTotal%",e)}else{if(t.preText){r+=t.preText}if(!t.showCharsTyped){r+=e-n}else{r+=n}if(t.showMaxLength){r+=t.separator+e}if(t.postText){r+=t.postText}}return r}function h(e,n,r,i){i.html(c(r,r-e));if(e>0){if(u(n,t.threshold,r)){f(i.removeClass(t.limitReachedClass).addClass(t.warningClass))}else{l(i)}}else{f(i.removeClass(t.warningClass).addClass(t.limitReachedClass))}}function p(t){var n=t[0];return e.extend({},typeof n.getBoundingClientRect==="function"?n.getBoundingClientRect():{width:n.offsetWidth,height:n.offsetHeight},t.offset())}function d(e,n){var r=p(e),i=e.outerWidth(),s=n.outerWidth(),o=n.width(),u=n.height();switch(t.placement){case"bottom":n.css({top:r.top+r.height,left:r.left+r.width/2-o/2});break;case"top":n.css({top:r.top-u,left:r.left+r.width/2-o/2});break;case"left":n.css({top:r.top+r.height/2-u/2,left:r.left-o});break;case"right":n.css({top:r.top+r.height/2-u/2,left:r.left+r.width});break;case"bottom-right":n.css({top:r.top+r.height,left:r.left+r.width});break;case"top-right":n.css({top:r.top-u,left:r.left+i});break;case"top-left":n.css({top:r.top-u,left:r.left-s});break;case"bottom-left":n.css({top:r.top+e.outerHeight(),left:r.left-s});break;case"centered-right":n.css({top:r.top+u/2,left:r.left+i-s-3});break}}function v(e){return e.attr("maxlength")||e.attr("size")}var r=e("body"),i={alwaysShow:false,threshold:10,warningClass:"label label-success",limitReachedClass:"label label-important",separator:" / ",preText:"",postText:"",showMaxLength:true,placement:"bottom",showCharsTyped:true,validate:false,utf8:false};if(e.isFunction(t)&&!n){n=t;t={}}t=e.extend(i,t);return this.each(function(){var n=e(this),i=v(n),s=e("").css({display:"none",position:"absolute",whiteSpace:"nowrap",zIndex:999}).html(c(i,"0"));if(n.is("textarea")){n.data("maxlenghtsizex",n.outerWidth());n.data("maxlenghtsizey",n.outerHeight());n.mouseup(function(){if(n.outerWidth()!==n.data("maxlenghtsizex")||n.outerHeight()!==n.data("maxlenghtsizey")){d(n,s)}n.data("maxlenghtsizex",n.outerWidth());n.data("maxlenghtsizey",n.outerHeight())})}r.append(s);n.focus(function(){var e=a(n,v(n));h(e,n,i,s);d(n,s)});e(window).resize(function(){d(n,s)});n.blur(function(){s.css("display","none")});n.keyup(function(e){var r=a(n,v(n)),o=true,u=e.keyCode||e.which;if(r===0&&u===9&&!e.shiftKey){n.attr("maxlength",v(n)+1).trigger({type:"keypress",which:9}).attr("maxlength",v(n)-1)}if(t.validate&&r<0){o=false}else{h(r,n,i,s)}return o})})}})})(jQuery)
<|endoftext|>


<commit_before>import hooks from '../hooks';
<% if (database && (database !== 'Memory' && database !== 'NeDB')) { %>import User from '../models/user';<% } %>
<% if (database === 'Memory') { %>
import service from 'feathers-memory';
const User = {};
<% } %>
<% if (database === 'NeDB') { %>
import NeDB from 'feathers-nedb';
import service from 'feathers-nedb';
let User = new NeDB({
  filename: './data/users.db',
  autoload: true
});
<% } %><% if (database === 'MongoDB') { %>
import mongoose from 'mongoose';
import service from 'feathers-mongoose';
mongoose.connect('mongodb://localhost:27017/feathers');
mongoose.Promise = global.Promise;
<% } %>

export default function(){
  const app = this;
  /* * * Do any connection stuff here, if needed * * */

  /* * * Service Type * * */
  let options = {
    Model: User,
    paginate: {
      default: 5,
      max: 25
    }
  };

  app.use('/v1/users', service(options));

  // const service = this.service('v1/users');

  /* * * Before hooks * * */
  // service.before({
  //   all:   [hooks.requireAuthForPrivate()],
  //   before: [hooks.setUserID()]
  // });

  // /* * * After hooks * * */
  // service.after({
  //   all: [hooks.removeSomeField()]
  // });

  // /* * * Set up event filters * * */
  // service.created = service.updated = service.patched = service.removed = events.requireAuthForPrivate;
}<commit_msg>fixing initialization of nedb service<commit_after>import hooks from '../hooks';
<% if (database && (database !== 'Memory' && database !== 'NeDB')) { %>import User from '../models/user';<% } %>
<% if (database === 'Memory') { %>
import service from 'feathers-memory';
const User = {};
<% } %>
<% if (database === 'NeDB') { %>
import NeDB from 'nedb';
import service from 'feathers-nedb';
let User = new NeDB({
  filename: './data/users.db',
  autoload: true
});
<% } %><% if (database === 'MongoDB') { %>
import mongoose from 'mongoose';
import service from 'feathers-mongoose';
mongoose.connect('mongodb://localhost:27017/feathers');
mongoose.Promise = global.Promise;
<% } %>

export default function(){
  const app = this;
  /* * * Do any connection stuff here, if needed * * */

  /* * * Service Type * * */
  let options = {
    Model: User,
    paginate: {
      default: 5,
      max: 25
    }
  };

  app.use('/v1/users', service(options));

  // const service = this.service('v1/users');

  /* * * Before hooks * * */
  // service.before({
  //   all:   [hooks.requireAuthForPrivate()],
  //   before: [hooks.setUserID()]
  // });

  // /* * * After hooks * * */
  // service.after({
  //   all: [hooks.removeSomeField()]
  // });

  // /* * * Set up event filters * * */
  // service.created = service.updated = service.patched = service.removed = events.requireAuthForPrivate;
}<|endoftext|>


<commit_before>// Dependencies
var prompt = require('prompt'),
    request = require('request'),
    ProgressBar = require('progress'),
    RateLimiter = require('limiter').RateLimiter;

// Constructors
var limiter = new RateLimiter(1, 200),
    bar;

// Set prompt appearance
prompt.message = '> '.green;
prompt.delimiter = '';

// Define authentication values, and request parameters
var authProperties = [{
    name: 'tokenaccess',
    description: 'Will you be using token access (y/n)?'.green,
    pattern: /^[YNyn]{1}$/,
    message: 'You must enter \'y\' or \'n\'',
    required: true
}, {
    name: 'username',
    description: 'Enter your username for Zendesk:'.green,
    required: true
}, {
    name: 'password',
    description: 'Enter your password or API token:'.green,
    hidden: true,
    required: true
}, {
    name: 'subdomain',
    description: 'Enter your Zendesk subdomain:'.green,
    required: true
}, {
    name: 'totalOrgs',
    description: 'Enter the number of organizations you wish to create:'.green,
    required: true
}, {
    name: 'startingOrg',
    description: 'Enter the index number to start at:'.green,
    required: false
}];

prompt.start();

// Get authentication values and export filename
prompt.get(authProperties, function(err, result) {
    if (err) {
        return onErr(err);
    } else {

        // Create credentials from user input and pass on to getOrgs()
        var username = '';
        if (result.tokenaccess.toLowerCase() === 'n') {
            username = result.username;
        } else {
            username = result.username + '/token';
        }

        // Make space for request processing in console
        process.stdout.write("\n");

        // Begin posting data
        createOrgs(username, result.password, result.subdomain, parseInt(result.totalOrgs), parseInt(result.startingOrg));
    }

});

function onErr(err) {
    process.stdout.write("There was a problem.\n", err);
}

// Create the organizations
var createOrgs = function (user, pass, subdomain, totalOrgs, startingOrg) {

    var endingOrg = startingOrg + totalOrgs;
    process.stdout.write(totalOrgs + " organizations will be created.\n\n" );

    for (var i = startingOrg; i < endingOrg; i++) {

        var data = {"organization": {"name": "Sample Organization " + i}};
        createOrganization(user, pass, subdomain, data, totalOrgs);

    }

};

var createOrganization = function(user, pass, subdomain, data, totalOrgs) {
    limiter.removeTokens(1, function(err, remainingRequests){
        request(
        {
            method: 'POST',
            uri: 'https://' + subdomain + '.zendesk.com/api/v2/organizations.json',
            body: data,
            json: true
        },
        function(err, resp, body){
            if (err) {
                process.stdout.write("There was a problem.");
                return false;
            } else if (resp.statusCode == 429) {
                setTimeout(createOrganization(user, pass, subdomain, data, totalOrgs), response.headers["retry-after"]);
            } else if (resp.statusCode == 401 || resp.statusCode == 501 || resp.statusCode == 504) {
                throw new Error(resp.headers.status);
            } else if (resp.statusCode == 200 || resp.statusCode == 201) {
                bar = bar || new ProgressBar('Progress: [:bar] :percent (approximately :etas remaining)', {
                    complete: '=',
                    incomplete: ' ',
                    width: 50,
                    total: totalOrgs
                });

                // Update progress bar
                bar.tick(1);
            }
        }).auth(user, pass);
    });
};<commit_msg>Fixing response handling<commit_after>// Dependencies
var prompt = require('prompt'),
    request = require('request'),
    ProgressBar = require('progress'),
    RateLimiter = require('limiter').RateLimiter;

// Constructors
var limiter = new RateLimiter(1, 200),
    bar;

// Set prompt appearance
prompt.message = '> '.green;
prompt.delimiter = '';

// Define authentication values, and request parameters
var authProperties = [{
    name: 'tokenaccess',
    description: 'Will you be using token access (y/n)?'.green,
    pattern: /^[YNyn]{1}$/,
    message: 'You must enter \'y\' or \'n\'',
    required: true
}, {
    name: 'username',
    description: 'Enter your username for Zendesk:'.green,
    required: true
}, {
    name: 'password',
    description: 'Enter your password or API token:'.green,
    hidden: true,
    required: true
}, {
    name: 'subdomain',
    description: 'Enter your Zendesk subdomain:'.green,
    required: true
}, {
    name: 'totalOrgs',
    description: 'Enter the number of organizations you wish to create:'.green,
    required: true
}, {
    name: 'startingOrg',
    description: 'Enter the index number to start at:'.green,
    required: false
}];

prompt.start();

// Get authentication values and export filename
prompt.get(authProperties, function(err, result) {
    if (err) {
        return onErr(err);
    } else {

        // Create credentials from user input and pass on to getOrgs()
        var username = '';
        if (result.tokenaccess.toLowerCase() === 'n') {
            username = result.username;
        } else {
            username = result.username + '/token';
        }

        // Make space for request processing in console
        process.stdout.write("\n");

        // Begin posting data
        createOrgs(username, result.password, result.subdomain, parseInt(result.totalOrgs), parseInt(result.startingOrg));
    }

});

function onErr(err) {
    process.stdout.write("There was a problem.\n", err);
}

// Create the organizations
var createOrgs = function (user, pass, subdomain, totalOrgs, startingOrg) {

    var endingOrg = startingOrg + totalOrgs;
    process.stdout.write(totalOrgs + " organizations will be created.\n\n" );

    for (var i = startingOrg; i < endingOrg; i++) {

        var data = {"organization": {"name": "Sample Organization " + i}};
        createOrganization(user, pass, subdomain, data, totalOrgs);

    }

};

var createOrganization = function(user, pass, subdomain, data, totalOrgs) {
    limiter.removeTokens(1, function(err, remainingRequests){
        request(
        {
            method: 'POST',
            uri: 'https://' + subdomain + '.zendesk.com/api/v2/organizations.json',
            body: data,
            json: true
        },
        function(err, resp, body){
            if (err) {
                process.stdout.write("There was a problem.");
                return false;
            }  else if (resp.statusCode == 200 || resp.statusCode == 201) {
                bar = bar || new ProgressBar('Progress: [:bar] :percent (approximately :etas remaining)', {
                    complete: '=',
                    incomplete: ' ',
                    width: 50,
                    total: totalOrgs
                });

                // Update progress bar
                bar.tick(1);

            } else if (resp.statusCode == 429) {
                setTimeout(createOrganization(user, pass, subdomain, data, totalOrgs), response.headers["retry-after"]);
            } else {
                // Something else went wrong, exit the program with status response headers
                process.stdout.write(resp.headers.status + "\n\n");
                process.exit(1);
            }
        }).auth(user, pass);
    });
};<|endoftext|>


<commit_before> // @todo Build containers automatically at calculated dropoff spots.

var utilities = require('utilities');

StructureTower.prototype.runLogic = function () {
    var tower = this;

    // Emergency repairs.
    var closestDamagedStructure = tower.pos.findClosestByRange(FIND_STRUCTURES, {
        filter: (structure) => {
            if (structure.structureType == STRUCTURE_WALL) {
                return ((structure.pos.getRangeTo(tower) <= 5 && structure.hits < 10000) || structure.hits < 1000) && tower.energy > tower.energyCapacity * 0.7;
            }
            if (structure.structureType == STRUCTURE_RAMPART) {
                return ((structure.pos.getRangeTo(tower) <= 5 && structure.hits < 10000) || structure.hits < 1000) && tower.energy > tower.energyCapacity * 0.7 || structure.hits < 500;
            }
            return (structure.hits < structure.hitsMax - TOWER_POWER_REPAIR) && (structure.hits < structure.hitsMax * 0.2);
        }
    });
    if (closestDamagedStructure) {
        tower.repair(closestDamagedStructure);
    }

    // Attack enemies.
    var closestHostileHealer = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS, {
        filter: (creep) => {
            for (var i in creep.body) {
                if (creep.body[i].type == HEAL && creep.body[i].hits > 0) {
                    return true;
                }
            }
            return false;
        }
    });
    var closestHostile = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS, {
        filter: (creep) => creep.isDangerous()
    });
    if (closestHostileHealer) {
        tower.attack(closestHostileHealer);
    }
    else if (closestHostile) {
        tower.attack(closestHostile);
    }

    // Heal friendlies.
    var damaged = tower.pos.findClosestByRange(FIND_MY_CREEPS, {
        filter: (creep) => creep.hits < creep.hitsMax
    });
    if (damaged) {
        tower.heal(damaged);
    }
};

Room.prototype.manageLabs = function () {
    if (this.controller && this.controller.my && this.memory.canPerformReactions && this.memory.currentReaction) {
        var source1 = Game.getObjectById(this.memory.labs.source1);
        var source2 = Game.getObjectById(this.memory.labs.source2);
        var reactor = Game.getObjectById(this.memory.labs.reactor);

        if (source1 && source2 && reactor) {
            if (reactor.cooldown <= 0) {
                reactor.runReaction(source1, source2);
            }
        }
    }
};

var structureManager = {

    getRoomResourceStates: function () {
        var rooms = {};

        for (let roomId in Game.rooms) {
            let room = Game.rooms[roomId];

            let storage = room.storage;
            let terminal = room.terminal;

            if (!room.controller || !room.controller.my || !terminal || !storage) {
                continue;
            }

            let roomData = {
                totalResources: {},
                state: {},
            };

            for (let resourceType in storage.store) {
                roomData.totalResources[resourceType] = storage.store[resourceType];
            }
            for (let resourceType in terminal.store) {
                if (!roomData.totalResources[resourceType]) {
                    roomData.totalResources[resourceType] = 0;
                }
                roomData.totalResources[resourceType] += terminal.store[resourceType];
            }

            for (let resourceType in roomData.totalResources) {
                let amount = roomData.totalResources[resourceType];
                if (resourceType == RESOURCE_ENERGY) {
                    amount /= 3;
                }

                if (amount >= 50000) {
                    roomData.state[resourceType] = 'high';
                }
                else if (amount >= 10000) {
                    roomData.state[resourceType] = 'medium';
                }
                else {
                    roomData.state[resourceType] = 'low';
                }
            }

            rooms[room.name] = roomData;
        }

        return rooms;
    },

    getAvailableTransportRoutes: function (rooms) {
        var options = [];

        for (var roomName in rooms) {
            var roomState = rooms[roomName];
            for (var resourceType in roomState.state) {
                if (roomState.state[resourceType] == 'high') {
                    // Look for other rooms that are low on this resource.
                    for (var roomName2 in rooms) {
                        if (!rooms[roomName2].state[resourceType] || rooms[roomName2].state[resourceType] == 'low') {
                            // Make sure target has space left.
                            if (_.sum(Game.rooms[roomName2].terminal.store) > Game.rooms[roomName2].terminal.storeCapacity - 5000) {
                                continue;
                            }

                            var option = {
                                priority: 5,
                                weight: 0,
                                resourceType: resourceType,
                                source: roomName,
                                target: roomName2,
                            };

                            option.priority -= Game.map.getRoomLinearDistance(roomName, roomName2) * 0.5;

                            if (option.priority < 0) {
                                continue;
                            }

                            options.push(option);
                        }
                    }
                }
            }
        }

        return options;
    },

    getAvailableReactions: function (rooms) {
        var options = [];

        for (let roomName in rooms) {
            let room = Game.rooms[roomName];
            let roomData = rooms[roomName];

            if (room.memory.canPerformReactions) {
                // Try to find possible reactions where we have a good amount of resources.
                var bestReaction = null;
                var mostResources = null;
                for (var resourceType in roomData.totalResources) {
                    if (roomData.totalResources[resourceType] > 0 && REACTIONS[resourceType]) {
                        for (var resourceType2 in REACTIONS[resourceType]) {
                            if (roomData.totalResources[REACTIONS[resourceType][resourceType2]] > 10000) continue;

                            if (roomData.totalResources[resourceType2] && roomData.totalResources[resourceType2] > 0) {
                                //console.log(resourceType, '+', resourceType2, '=', REACTIONS[resourceType][resourceType2]);
                                var resourceAmount = Math.min(roomData.totalResources[resourceType2], roomData.totalResources[resourceType2]);
                                if (!mostResources || mostResources < resourceAmount) {
                                    mostResources = resourceAmount;
                                    bestReaction = [resourceType, resourceType2];
                                }
                            }
                        }
                    }
                }

                room.memory.currentReaction = bestReaction;
            }
        }

        return options;
    },

    manageResources: function () {
        let rooms = structureManager.getRoomResourceStates();
        let best = utilities.getBestOption(structureManager.getAvailableTransportRoutes(rooms));

        if (best) {
            let terminal = Game.rooms[best.source].terminal;
            let result = terminal.send(best.resourceType, 5000, best.target, "Resource equalizing");
            console.log("sending", best.resourceType, "from", best.source, "to", best.target, ":", result);
        }

        if (Game.time % 10 == 1) {
            let best = utilities.getBestOption(structureManager.getAvailableReactions(rooms));
        }
    },

    /**
     * Make sure there are roads between all major points in a room.
     */
    checkRoads: function (room) {
        if (!room.controller || !room.controller.my) {
            return;
        }

        // @todo Build roads around spawn, sources, controller and storage for easier access.
        console.log('---checking road structure in room', room.name);

        var controller = room.controller;
        var spawns = room.find(FIND_STRUCTURES, {
            filter: (structure) => structure.structureType == STRUCTURE_SPAWN
        });

        for (var i in spawns) {
            var spawn = spawns[i];

            structureManager.checkRoad(room, spawn.pos, controller.pos);

            for (var j in room.sources) {
                var source = room.sources[j];
                structureManager.checkRoad(room, spawn.pos, source.pos);

                var storagePosition = room.getStorageLocation();
                if (storagePosition) {
                    var sPos = room.getPositionAt(storagePosition.x, storagePosition.y);
                    structureManager.checkRoad(room, spawn.pos, sPos);
                    structureManager.checkRoad(room, source.pos, sPos);
                }
            }
        }
    },

    /**
     * Verify path between two positions and (re-)build roads accordingly.
     */
    checkRoad: function (room, source, target) {
        var path = source.findPathTo(target, {
            ignoreCreeps: true
        });

        for (var i in path) {
            var tile = path[i];

            var contents = room.lookAt(tile.x, tile.y);
            var buildRoad = true;
            for (var j in contents) {
                var content = contents[j];
                if (content.type == 'terrain') {
                    if (content.terrain != 'plain' && content.terrain != 'swamp') {
                        //console.log('invalid terrain:', content.terrain);
                        buildRoad = false;
                        break;
                    }
                }
                if (content.type == 'structure') {
                    if (content.structure.structureType != STRUCTURE_CONTAINER && content.structure.structureType != STRUCTURE_RAMPART) {
                        buildRoad = false;
                        break;
                    }
                }
                if (content.type == 'constructionSite') {
                    if (content.constructionSite.structureType != STRUCTURE_CONTAINER && content.constructionSite.structureType != STRUCTURE_RAMPART) {
                        buildRoad = false;
                        break;
                    }
                }
            }
            if (buildRoad) {
                room.createConstructionSite(tile.x, tile.y, STRUCTURE_ROAD);
            }
        }
    }

};

module.exports = structureManager;
<commit_msg>disabled tower repairs to save on cpu<commit_after> // @todo Build containers automatically at calculated dropoff spots.

var utilities = require('utilities');

StructureTower.prototype.runLogic = function () {
    var tower = this;

    // Emergency repairs.
    /*var closestDamagedStructure = tower.pos.findClosestByRange(FIND_STRUCTURES, {
        filter: (structure) => {
            if (structure.structureType == STRUCTURE_WALL) {
                return ((structure.pos.getRangeTo(tower) <= 5 && structure.hits < 10000) || structure.hits < 1000) && tower.energy > tower.energyCapacity * 0.7;
            }
            if (structure.structureType == STRUCTURE_RAMPART) {
                return ((structure.pos.getRangeTo(tower) <= 5 && structure.hits < 10000) || structure.hits < 1000) && tower.energy > tower.energyCapacity * 0.7 || structure.hits < 500;
            }
            return (structure.hits < structure.hitsMax - TOWER_POWER_REPAIR) && (structure.hits < structure.hitsMax * 0.2);
        }
    });
    if (closestDamagedStructure) {
        tower.repair(closestDamagedStructure);
    }//*/

    // Attack enemies.
    var closestHostileHealer = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS, {
        filter: (creep) => {
            for (var i in creep.body) {
                if (creep.body[i].type == HEAL && creep.body[i].hits > 0) {
                    return true;
                }
            }
            return false;
        }
    });
    var closestHostile = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS, {
        filter: (creep) => creep.isDangerous()
    });
    if (closestHostileHealer) {
        tower.attack(closestHostileHealer);
    }
    else if (closestHostile) {
        tower.attack(closestHostile);
    }

    // Heal friendlies.
    var damaged = tower.pos.findClosestByRange(FIND_MY_CREEPS, {
        filter: (creep) => creep.hits < creep.hitsMax
    });
    if (damaged) {
        tower.heal(damaged);
    }
};

Room.prototype.manageLabs = function () {
    if (this.controller && this.controller.my && this.memory.canPerformReactions && this.memory.currentReaction) {
        var source1 = Game.getObjectById(this.memory.labs.source1);
        var source2 = Game.getObjectById(this.memory.labs.source2);
        var reactor = Game.getObjectById(this.memory.labs.reactor);

        if (source1 && source2 && reactor) {
            if (reactor.cooldown <= 0) {
                reactor.runReaction(source1, source2);
            }
        }
    }
};

var structureManager = {

    getRoomResourceStates: function () {
        var rooms = {};

        for (let roomId in Game.rooms) {
            let room = Game.rooms[roomId];

            let storage = room.storage;
            let terminal = room.terminal;

            if (!room.controller || !room.controller.my || !terminal || !storage) {
                continue;
            }

            let roomData = {
                totalResources: {},
                state: {},
            };

            for (let resourceType in storage.store) {
                roomData.totalResources[resourceType] = storage.store[resourceType];
            }
            for (let resourceType in terminal.store) {
                if (!roomData.totalResources[resourceType]) {
                    roomData.totalResources[resourceType] = 0;
                }
                roomData.totalResources[resourceType] += terminal.store[resourceType];
            }

            for (let resourceType in roomData.totalResources) {
                let amount = roomData.totalResources[resourceType];
                if (resourceType == RESOURCE_ENERGY) {
                    amount /= 3;
                }

                if (amount >= 50000) {
                    roomData.state[resourceType] = 'high';
                }
                else if (amount >= 10000) {
                    roomData.state[resourceType] = 'medium';
                }
                else {
                    roomData.state[resourceType] = 'low';
                }
            }

            rooms[room.name] = roomData;
        }

        return rooms;
    },

    getAvailableTransportRoutes: function (rooms) {
        var options = [];

        for (var roomName in rooms) {
            var roomState = rooms[roomName];
            for (var resourceType in roomState.state) {
                if (roomState.state[resourceType] == 'high') {
                    // Look for other rooms that are low on this resource.
                    for (var roomName2 in rooms) {
                        if (!rooms[roomName2].state[resourceType] || rooms[roomName2].state[resourceType] == 'low') {
                            // Make sure target has space left.
                            if (_.sum(Game.rooms[roomName2].terminal.store) > Game.rooms[roomName2].terminal.storeCapacity - 5000) {
                                continue;
                            }

                            var option = {
                                priority: 5,
                                weight: 0,
                                resourceType: resourceType,
                                source: roomName,
                                target: roomName2,
                            };

                            option.priority -= Game.map.getRoomLinearDistance(roomName, roomName2) * 0.5;

                            if (option.priority < 0) {
                                continue;
                            }

                            options.push(option);
                        }
                    }
                }
            }
        }

        return options;
    },

    getAvailableReactions: function (rooms) {
        var options = [];

        for (let roomName in rooms) {
            let room = Game.rooms[roomName];
            let roomData = rooms[roomName];

            if (room.memory.canPerformReactions) {
                // Try to find possible reactions where we have a good amount of resources.
                var bestReaction = null;
                var mostResources = null;
                for (var resourceType in roomData.totalResources) {
                    if (roomData.totalResources[resourceType] > 0 && REACTIONS[resourceType]) {
                        for (var resourceType2 in REACTIONS[resourceType]) {
                            if (roomData.totalResources[REACTIONS[resourceType][resourceType2]] > 10000) continue;

                            if (roomData.totalResources[resourceType2] && roomData.totalResources[resourceType2] > 0) {
                                //console.log(resourceType, '+', resourceType2, '=', REACTIONS[resourceType][resourceType2]);
                                var resourceAmount = Math.min(roomData.totalResources[resourceType2], roomData.totalResources[resourceType2]);
                                if (!mostResources || mostResources < resourceAmount) {
                                    mostResources = resourceAmount;
                                    bestReaction = [resourceType, resourceType2];
                                }
                            }
                        }
                    }
                }

                room.memory.currentReaction = bestReaction;
            }
        }

        return options;
    },

    manageResources: function () {
        let rooms = structureManager.getRoomResourceStates();
        let best = utilities.getBestOption(structureManager.getAvailableTransportRoutes(rooms));

        if (best) {
            let terminal = Game.rooms[best.source].terminal;
            let result = terminal.send(best.resourceType, 5000, best.target, "Resource equalizing");
            console.log("sending", best.resourceType, "from", best.source, "to", best.target, ":", result);
        }

        if (Game.time % 10 == 1) {
            let best = utilities.getBestOption(structureManager.getAvailableReactions(rooms));
        }
    },

    /**
     * Make sure there are roads between all major points in a room.
     */
    checkRoads: function (room) {
        if (!room.controller || !room.controller.my) {
            return;
        }

        // @todo Build roads around spawn, sources, controller and storage for easier access.
        console.log('---checking road structure in room', room.name);

        var controller = room.controller;
        var spawns = room.find(FIND_STRUCTURES, {
            filter: (structure) => structure.structureType == STRUCTURE_SPAWN
        });

        for (var i in spawns) {
            var spawn = spawns[i];

            structureManager.checkRoad(room, spawn.pos, controller.pos);

            for (var j in room.sources) {
                var source = room.sources[j];
                structureManager.checkRoad(room, spawn.pos, source.pos);

                var storagePosition = room.getStorageLocation();
                if (storagePosition) {
                    var sPos = room.getPositionAt(storagePosition.x, storagePosition.y);
                    structureManager.checkRoad(room, spawn.pos, sPos);
                    structureManager.checkRoad(room, source.pos, sPos);
                }
            }
        }
    },

    /**
     * Verify path between two positions and (re-)build roads accordingly.
     */
    checkRoad: function (room, source, target) {
        var path = source.findPathTo(target, {
            ignoreCreeps: true
        });

        for (var i in path) {
            var tile = path[i];

            var contents = room.lookAt(tile.x, tile.y);
            var buildRoad = true;
            for (var j in contents) {
                var content = contents[j];
                if (content.type == 'terrain') {
                    if (content.terrain != 'plain' && content.terrain != 'swamp') {
                        //console.log('invalid terrain:', content.terrain);
                        buildRoad = false;
                        break;
                    }
                }
                if (content.type == 'structure') {
                    if (content.structure.structureType != STRUCTURE_CONTAINER && content.structure.structureType != STRUCTURE_RAMPART) {
                        buildRoad = false;
                        break;
                    }
                }
                if (content.type == 'constructionSite') {
                    if (content.constructionSite.structureType != STRUCTURE_CONTAINER && content.constructionSite.structureType != STRUCTURE_RAMPART) {
                        buildRoad = false;
                        break;
                    }
                }
            }
            if (buildRoad) {
                room.createConstructionSite(tile.x, tile.y, STRUCTURE_ROAD);
            }
        }
    }

};

module.exports = structureManager;
<|endoftext|>