<commit_before>// Enable expanding/folding folders in TracBrowser

(function($){
  var FOLDERID_COUNTER = 0;
  var SUBFOLDER_INDENT = 20;

  // enableExpandDir adds the capability to folder rows to be expanded and folded
  // It also teach the rows about their ancestors. It expects:
  //  - `parent_tr`, the logical parent row (`null` if there's no ancestor)
  //  - a `rows` jQuery object matching the newly created entry rows
  //  - `qargs`, additional parameters to send to the server when expanding

  window.enableExpandDir = function(parent_tr, rows, qargs) {
    // the ancestors folder ids are present in the parent_tr class attribute
    var ancestor_folderids = [];
    if (parent_tr)
      ancestor_folderids = $.grep(parent_tr.attr("class").split(" "),
                                  function(c) { return c.match(/^f\d+$/)});
    rows.each(function () {
      var a = $(this).find("a.dir");

      if (a.length) { // then the entry is a folder
        // create new folder id
        var folderid = "f" + FOLDERID_COUNTER++;
        this.id = folderid;
        $(this).addClass(folderid);

        // add the expander icon
        a.wrap('

');
        var expander = a.before(' ').prev();
        expander.attr("title", "Expand sub-directory in place")
          .click(function() { toggleDir($(this), qargs); });
      }

      // tie that row to ancestor folders
      if (parent_tr)
        $(this).addClass(ancestor_folderids.join(" "));
    });
  }

  // handler for click event on the expander icons
  window.toggleDir = function(expander, qargs) {
    var tr = expander.parents("tr");
    var folderid = tr.get(0).id;

    if ( tr.filter(".expanded").length ) { // then *fold*
      tr.removeClass("expanded").addClass("collapsed");
      tr.siblings("tr."+folderid).hide();
      expander.attr("title", "Re-expand directory");
      return;
    }

    if ( tr.filter(".collapsed").length ) { // then *expand*
      tr.removeClass("collapsed").addClass("expanded");
      tr.siblings("tr."+folderid).show();
      // Note that the above will show all the already fetched subtree,
      // so we have to fold again the folders which were already collapsed.
      tr.siblings("tr.collapsed").each(function() {
        tr.siblings("tr."+this.id).not(this).hide();
      });
    } else {                                // then *fetch*
      var td = expander.parents("td");
      var td_class = td.attr("class");
      var a = expander.next("a");
      var depth =
        parseFloat(td.css("padding-left").replace(/^(\d*\.\d*).*$/, "$1")) +
        SUBFOLDER_INDENT;

      tr.addClass("expanded");
      // insert "Loading ..." row
      tr.after('

');
      var loading_row = tr.next();
      loading_row.children("td").addClass(td_class)
        .attr("colspan", tr.children("td").length)
        .css("padding-left", depth);
      loading_row.find("span.loading").text("Loading " + a.text() + "...");

      // XHR for getting the rows corresponding to the folder entries
      $.ajax({
        type: "GET",
        url: a.attr("href"),
        data: qargs,
        dataType: "html",
        success: function(data) {
          // Safari 3.1.1 has some trouble reconstructing HTML snippets
          // bigger than 50k - splitting in rows before building DOM nodes
          var rows = data.replace(/^<!DOCTYPE[^>]+>/, "").split("
");
          if (rows.length) {
            // insert entry rows
            $(rows).each(function() {
              row = $(this+"
");
              row.children("td."+td_class).css("padding-left", depth);
              // make all entry rows collapsible but only subdir rows expandable
              enableExpandDir(tr, row, qargs);
              loading_row.before(row);
            });
            // remove "Loading ..." row
            loading_row.remove();
          } else {
            loading_row.find("span.loading").text("").append("(empty)")
              .removeClass("loading");
            // make the (empty) row collapsible
            enableExpandDir(tr, loading_row, qargs);
          }
        },
        error: function(req, err, exc) {
          loading_row.find("span.loading").text("").append("(error)")
            .removeClass("loading");
          enableExpandDir(tr, loading_row, qargs);
        }
      });
    }
    expander.attr("title", "Fold directory");
  }

})(jQuery);
<commit_msg>Make the directory expander javascript code work even when the directory listing table is embedded into another table. Fixes #7559.<commit_after>// Enable expanding/folding folders in TracBrowser

(function($){
  var FOLDERID_COUNTER = 0;
  var SUBFOLDER_INDENT = 20;

  // enableExpandDir adds the capability to folder rows to be expanded and folded
  // It also teach the rows about their ancestors. It expects:
  //  - `parent_tr`, the logical parent row (`null` if there's no ancestor)
  //  - a `rows` jQuery object matching the newly created entry rows
  //  - `qargs`, additional parameters to send to the server when expanding

  window.enableExpandDir = function(parent_tr, rows, qargs) {
    // the ancestors folder ids are present in the parent_tr class attribute
    var ancestor_folderids = [];
    if (parent_tr)
      ancestor_folderids = $.grep(parent_tr.attr("class").split(" "),
                                  function(c) { return c.match(/^f\d+$/)});
    rows.each(function () {
      var a = $(this).find("a.dir");

      if (a.length) { // then the entry is a folder
        // create new folder id
        var folderid = "f" + FOLDERID_COUNTER++;
        this.id = folderid;
        $(this).addClass(folderid);

        // add the expander icon
        a.wrap('

');
        var expander = a.before(' ').prev();
        expander.attr("title", "Expand sub-directory in place")
          .click(function() { toggleDir($(this), qargs); });
      }

      // tie that row to ancestor folders
      if (parent_tr)
        $(this).addClass(ancestor_folderids.join(" "));
    });
  }

  // handler for click event on the expander icons
  window.toggleDir = function(expander, qargs) {
    var tr = expander.parents("tr:first");
    var folderid = tr.get(0).id;

    if ( tr.filter(".expanded").length ) { // then *fold*
      tr.removeClass("expanded").addClass("collapsed");
      tr.siblings("tr."+folderid).hide();
      expander.attr("title", "Re-expand directory");
      return;
    }

    if ( tr.filter(".collapsed").length ) { // then *expand*
      tr.removeClass("collapsed").addClass("expanded");
      tr.siblings("tr."+folderid).show();
      // Note that the above will show all the already fetched subtree,
      // so we have to fold again the folders which were already collapsed.
      tr.siblings("tr.collapsed").each(function() {
        tr.siblings("tr."+this.id).not(this).hide();
      });
    } else {                                // then *fetch*
      var td = expander.parents("td");
      var td_class = td.attr("class");
      var a = expander.next("a");
      var depth =
        parseFloat(td.css("padding-left").replace(/^(\d*\.\d*).*$/, "$1")) +
        SUBFOLDER_INDENT;

      tr.addClass("expanded");
      // insert "Loading ..." row
      tr.after('

');
      var loading_row = tr.next();
      loading_row.children("td").addClass(td_class)
        .attr("colspan", tr.children("td").length)
        .css("padding-left", depth);
      loading_row.find("span.loading").text("Loading " + a.text() + "...");

      // XHR for getting the rows corresponding to the folder entries
      $.ajax({
        type: "GET",
        url: a.attr("href"),
        data: qargs,
        dataType: "html",
        success: function(data) {
          // Safari 3.1.1 has some trouble reconstructing HTML snippets
          // bigger than 50k - splitting in rows before building DOM nodes
          var rows = data.replace(/^<!DOCTYPE[^>]+>/, "").split("
");
          if (rows.length) {
            // insert entry rows
            $(rows).each(function() {
              row = $(this+"
");
              row.children("td."+td_class).css("padding-left", depth);
              // make all entry rows collapsible but only subdir rows expandable
              enableExpandDir(tr, row, qargs);
              loading_row.before(row);
            });
            // remove "Loading ..." row
            loading_row.remove();
          } else {
            loading_row.find("span.loading").text("").append("(empty)")
              .removeClass("loading");
            // make the (empty) row collapsible
            enableExpandDir(tr, loading_row, qargs);
          }
        },
        error: function(req, err, exc) {
          loading_row.find("span.loading").text("").append("(error)")
            .removeClass("loading");
          enableExpandDir(tr, loading_row, qargs);
        }
      });
    }
    expander.attr("title", "Fold directory");
  }

})(jQuery);
<|endoftext|>


<commit_before>module.exports = {
    UPLOAD_DIR: 'file_upload/uploads/',
    UPLOAD_URL: 'uploads/',
    PUBLIC_URL: 'http://demo.geomati.co/besobs/'
};
<commit_msg>Change photo upload url<commit_after>module.exports = {
    UPLOAD_DIR: 'file_upload/uploads/',
    UPLOAD_URL: 'uploads/',
    PUBLIC_URL: 'http://demo.fonts.cat/besobs/'
};
<|endoftext|>


<commit_before>import Link from "next/link";
import SingleColumn from "./SingleColumn";
import Section from "./Section";
import { contact } from "../lib/constants";

export default function Footer() {
  return (

      <SingleColumn>

Use Urbit

            <Link href="/getting-started">

                Getting Started

            </Link>
            <Link href="/using">

                User's Manual

            </Link>
            <Link href="https://github.com/urbit/port/releases">

                Urbit Client

            </Link>
            <Link href="https://github.com/urbit/urbit/releases">

                Urbit Binaries

            </Link>
            {
              //   <Link href="">
              //

              //     Urbit Apps
              //

              // </Link>
            }
            <Link href="/getting-started/planet/#hosting-providers">

                  Hosting Providers

            </Link>

About

            <Link href="/understanding-urbit">

                What's Urbit?

            </Link>
            <Link href="/understanding-urbit/urbit-id">

                Urbit ID

            </Link>
            <Link href="/understanding-urbit/urbit-os">

                Urbit OS

            </Link>

            <Link href="/faq">

                Security Audits

            </Link>

            <Link href="/faq">

                FAQ

            </Link>

News

            <Link href="/blog">

                Blog

            </Link>
            <Link href="/events">

                Events

            </Link>
            <Link href="/updates">

                Updates

            </Link>

Develop

            <Link href="/docs">

                Documentation

            </Link>
            <Link href="https://github.com/urbit">

                Github

            </Link>
            <Link href="https://github.com/urbit/awesome-urbit#http-apis-airlock">

                Airlock APIs

            </Link>

Contribute

            <Link href="https://github.com/urbit/urbit/issues">

                Issue Tracker

            </Link>
            <Link href="/grants">

                Urbit Grants

            </Link>

Community

            <Link href="https://groups.google.com/a/urbit.org/g/dev?pli=1">

                Dev Mailing List

            </Link>
            <Link href="https://github.com/urbit/azimuth">

                Governance

            </Link>
            <Link href="https://twitter.com/urbit">

                Twitter

            </Link>

            <Link href="/privacy">

                Privacy Policy

            </Link>

            <Link href="/terms-of-service">

                Terms of Service

            </Link>

                {contact.email}

      </SingleColumn>

  );
}
<commit_msg>add correct footer link for /audits<commit_after>import Link from "next/link";
import SingleColumn from "./SingleColumn";
import Section from "./Section";
import { contact } from "../lib/constants";

export default function Footer() {
  return (

      <SingleColumn>

Use Urbit

            <Link href="/getting-started">

                Getting Started

            </Link>
            <Link href="/using">

                User's Manual

            </Link>
            <Link href="https://github.com/urbit/port/releases">

                Urbit Client

            </Link>
            <Link href="https://github.com/urbit/urbit/releases">

                Urbit Binaries

            </Link>
            {
              //   <Link href="">
              //

              //     Urbit Apps
              //

              // </Link>
            }
            <Link href="/getting-started/planet/#hosting-providers">

                  Hosting Providers

            </Link>

About

            <Link href="/understanding-urbit">

                What's Urbit?

            </Link>
            <Link href="/understanding-urbit/urbit-id">

                Urbit ID

            </Link>
            <Link href="/understanding-urbit/urbit-os">

                Urbit OS

            </Link>
            <Link href="/audits">

                Security Audits

            </Link>
            <Link href="/faq">

                FAQ

            </Link>

News

            <Link href="/blog">

                Blog

            </Link>
            <Link href="/events">

                Events

            </Link>
            <Link href="/updates">

                Updates

            </Link>

Develop

            <Link href="/docs">

                Documentation

            </Link>
            <Link href="https://github.com/urbit">

                Github

            </Link>
            <Link href="https://github.com/urbit/awesome-urbit#http-apis-airlock">

                Airlock APIs

            </Link>

Contribute

            <Link href="https://github.com/urbit/urbit/issues">

                Issue Tracker

            </Link>
            <Link href="/grants">

                Urbit Grants

            </Link>

Community

            <Link href="https://groups.google.com/a/urbit.org/g/dev?pli=1">

                Dev Mailing List

            </Link>
            <Link href="https://github.com/urbit/azimuth">

                Governance

            </Link>
            <Link href="https://twitter.com/urbit">

                Twitter

            </Link>

            <Link href="/privacy">

                Privacy Policy

            </Link>

            <Link href="/terms-of-service">

                Terms of Service

            </Link>

                {contact.email}

      </SingleColumn>

  );
}
<|endoftext|>


<commit_before>/* global Vue */
import html from './button.html'

(function (v) {
  v.component('j-button', {
    props: ['action', 'type', 'width', 'height', 'round'],
    template: html,
    computed: {
      classObject: function () {
        return {
          'j-border-primary': !this.type || this.type === 'theme',
          'j-text-primary': !this.type,
          'j-bg-primary': this.type === 'theme',
          'j-font-primary': this.type === 'theme',
          'j-button-text': this.type === 'text',
          'j-click-button': !this.round && this.type !== 'disabled',
          'j-click-round-button': this.round && this.type !== 'disabled',
          'j-button-red': this.type === 'red',
          'j-button-green': this.type === 'green',
          'j-button-blue': this.type === 'blue',
          'j-button-yellow': this.type === 'yellow',
          'j-button-disabled': this.type === 'disabled'
        }
      },
      a: function () {
        return this.type === 'disabled' ? function () { return false } : (this.action || function () { return false })
      },
      w: function () {
        return this.width ? Number(this.width) + 'px' : 'auto'
      },
      h: function () {
        return this.height ? Number(this.height) + 'px' : '36px'
      },
      l: function () {
        return this.height ? Number(this.height) - 2 + 'px' : '34px'
      }
    }
  })
})(Vue)
<commit_msg>修改button插件，width属性带单位时无效的bug<commit_after>/* global Vue */
import html from './button.html'

(function (v) {
  v.component('j-button', {
    props: ['action', 'type', 'width', 'height', 'round'],
    template: html,
    computed: {
      classObject: function () {
        return {
          'j-border-primary': !this.type || this.type === 'theme',
          'j-text-primary': !this.type,
          'j-bg-primary': this.type === 'theme',
          'j-font-primary': this.type === 'theme',
          'j-button-text': this.type === 'text',
          'j-click-button': !this.round && this.type !== 'disabled',
          'j-click-round-button': this.round && this.type !== 'disabled',
          'j-button-red': this.type === 'red',
          'j-button-green': this.type === 'green',
          'j-button-blue': this.type === 'blue',
          'j-button-yellow': this.type === 'yellow',
          'j-button-disabled': this.type === 'disabled'
        }
      },
      a: function () {
        return this.type === 'disabled' ? function () { return false } : (this.action || function () { return false })
      },
      w: function () {
        return isNaN(Number(this.width)) ? this.width : Number(this.width) + 'px'
      },
      h: function () {
        return isNaN(Number(this.height)) ? this.width : Number(this.height) + 'px'
      },
      l: function () {
        return this.height ? Number(this.height) - 2 + 'px' : null
      }
    }
  })
})(Vue)
<|endoftext|>


<commit_before>var fs = require("fs");
var path = require("path");
var memery = require('../efront/memery');
var appname = memery.APP;
var {
    ENVS_PATH = "_envs",
    COMS_PATH = "./coms",
    PAGE_PATH = "./apps",
    PUBLIC_PATH = "./public"
} = memery;
function mkdirIfNotExists(dirname) {
    if (!fs.existsSync(dirname))
        fs.mkdirSync(dirname);
}
function throwMakeIfExists(dirname) {
    if (fs.existsSync(dirname))
        throw new Error(`${dirname} 已存在！`);
    else fs.mkdirSync(dirname);
}
function from(srcname = 'kugou', destname = appname) {
    if (!appname) throw `请先设置app名称！如：${/win\d/i.test(process.platform) ? 'set' : 'export'} app=abc`;
    var setupData = [
    ];
    if (destname) {
        setupData.push(`if not defined app set app=${destname}`);
        setupData.push(`set page=${destname}`);
    }
    setupData.push('set coms=' + destname + "," + srcname + (srcname !== "zimoli" ? ",zimoli" : ""));
    mkdirIfNotExists(ENVS_PATH);
    mkdirIfNotExists(PAGE_PATH);
    mkdirIfNotExists(COMS_PATH);
    mkdirIfNotExists(PUBLIC_PATH);
    mkdirIfNotExists(path.join(PAGE_PATH, `${destname}`));

    var jsondata = {
        "name": appname || srcname,
        "version": "1.0.0",
        "descriptions": "Efront 创建的项目",
        "scripts": {
            test: "efront live",
            build: "efront build"
        },
    };
    setupData = Buffer.from(setupData.join("\r\n"));
    if (destname) {
        fs.writeFileSync(path.join(ENVS_PATH, `app=${destname}.bat`), setupData);
    } else {
        fs.writeFileSync(path.join(ENVS_PATH, "setup.bat"), setupData);
    }
    var packagepath = path.join(PAGE_PATH, '../package.json');
    if (!fs.existsSync(packagepath)) {
        fs.writeFileSync(packagepath, JSON.stringify(jsondata, null, 4));
    }
    var hasindex = false;
    fs.readdirSync(path.join(__dirname, `../../apps/${srcname}`)).map(function (name) {
        hasindex = hasindex || /^index.html$/i.test(name);
        copy(path.join(__dirname, `../../apps/${srcname}/`, name), path.join(PAGE_PATH, `${destname}`, name));
    });
    if (!hasindex) copy(path.join(__dirname, "../../apps/index.html"), path.join(PAGE_PATH, `${destname}/index.html`));
}
module.exports = from;
function copy(path1, path2) {
    if (fs.existsSync(path2)) {
        console.error(`目标路径已存在：${path2}`);
    } else if (!fs.existsSync(path.dirname(path2))) {
        console.error("目标路径无法创建！");
    } else if (!fs.existsSync(path1)) {
        console.error(`源路径不存在：${path1}`);
    } else {
        fs.stat(path1, function (error, stats) {
            if (error) console.error(`无法读取源路径：${path1}`);
            else if (stats.isDirectory()) {
                fs.readdir(path1, function (error, names) {
                    if (error) console.error(`读取目录失败：${path1}`)
                    else fs.mkdir(path2, function (error) {
                        if (error) console.error(`创建目录失败：${path2}`);
                        else names.forEach(function (name) {
                            copy(path.join(path1, name), path.join(path2, name));
                        })
                    });
                });
            } else {
                fs.readFile(path1, function (error, data) {
                    if (error) console.error(`读取文件失败：${path1}`);
                    else fs.writeFile(path2, data, function (error) {
                        if (error) console.error(`写入文件失败：${path2}`);
                    });
                })
            }
        });
    }
}<commit_msg>修复无法从命令行创建项目的问题<commit_after>var fs = require("fs");
var path = require("path");
var memery = require('../efront/memery');
var appname = memery.APP;
var {
    ENVS_PATH = "_envs",
    COMS_PATH = "./coms",
    PAGE_PATH = "./apps",
    PUBLIC_PATH = "./public"
} = memery;
function getFirstPath(p) {
    return p.split(/[,;]/)[0];
}
ENVS_PATH = getFirstPath(ENVS_PATH);
COMS_PATH = getFirstPath(COMS_PATH);
PAGE_PATH = getFirstPath(PAGE_PATH);
PUBLIC_PATH = getFirstPath(PUBLIC_PATH);
function mkdirIfNotExists(dirname) {
    if (!fs.existsSync(dirname))
        fs.mkdirSync(dirname);
}
function throwMakeIfExists(dirname) {
    if (fs.existsSync(dirname))
        throw new Error(`${dirname} 已存在！`);
    else fs.mkdirSync(dirname);
}
function from(srcname = 'kugou', destname = appname) {
    if (!appname) throw `请先设置app名称！如：${/win\d/i.test(process.platform) ? 'set' : 'export'} app=abc`;
    var setupData = [
    ];
    if (destname) {
        setupData.push(`if not defined app set app=${destname}`);
        setupData.push(`set page=${destname}`);
    }
    setupData.push('set coms=' + destname + "," + srcname + (srcname !== "zimoli" ? ",zimoli" : ""));
    mkdirIfNotExists(ENVS_PATH);
    mkdirIfNotExists(PAGE_PATH);
    mkdirIfNotExists(COMS_PATH);
    mkdirIfNotExists(PUBLIC_PATH);
    mkdirIfNotExists(path.join(PAGE_PATH, `${destname}`));

    var jsondata = {
        "name": appname || srcname,
        "version": "1.0.0",
        "descriptions": "Efront 创建的项目",
        "scripts": {
            test: "efront live",
            build: "efront build"
        },
    };
    setupData = Buffer.from(setupData.join("\r\n"));
    if (destname) {
        fs.writeFileSync(path.join(ENVS_PATH, `app=${destname}.bat`), setupData);
    } else {
        fs.writeFileSync(path.join(ENVS_PATH, "setup.bat"), setupData);
    }
    var packagepath = path.join(PAGE_PATH, '../package.json');
    if (!fs.existsSync(packagepath)) {
        fs.writeFileSync(packagepath, JSON.stringify(jsondata, null, 4));
    }
    var hasindex = false;
    fs.readdirSync(path.join(__dirname, `../../apps/${srcname}`)).map(function (name) {
        hasindex = hasindex || /^index.html$/i.test(name);
        copy(path.join(__dirname, `../../apps/${srcname}/`, name), path.join(PAGE_PATH, `${destname}`, name));
    });
    if (!hasindex) copy(path.join(__dirname, "../../apps/index.html"), path.join(PAGE_PATH, `${destname}/index.html`));
}
module.exports = from;
function copy(path1, path2) {
    if (fs.existsSync(path2)) {
        console.error(`目标路径已存在：${path2}`);
    } else if (!fs.existsSync(path.dirname(path2))) {
        console.error("目标路径无法创建！");
    } else if (!fs.existsSync(path1)) {
        console.error(`源路径不存在：${path1}`);
    } else {
        fs.stat(path1, function (error, stats) {
            if (error) console.error(`无法读取源路径：${path1}`);
            else if (stats.isDirectory()) {
                fs.readdir(path1, function (error, names) {
                    if (error) console.error(`读取目录失败：${path1}`)
                    else fs.mkdir(path2, function (error) {
                        if (error) console.error(`创建目录失败：${path2}`);
                        else names.forEach(function (name) {
                            copy(path.join(path1, name), path.join(path2, name));
                        })
                    });
                });
            } else {
                fs.readFile(path1, function (error, data) {
                    if (error) console.error(`读取文件失败：${path1}`);
                    else fs.writeFile(path2, data, function (error) {
                        if (error) console.error(`写入文件失败：${path2}`);
                    });
                })
            }
        });
    }
}<|endoftext|>


<commit_before>var ec2 = require("ec2"), sys = require("sys");

var AMI = "ami-2d4aa444";
var VOLUME = "vol-d6bf23bf";

function createRequest() {
  return ec2.request(
  { key: process.env["AWS_ACCESS_KEY_ID"]
  , secret: process.env["AWS_SECRET_ACCESS_KEY"]
  });
}

function launch () {
  var state = {};
  var amazon = ec2.createClient(
  { key: process.env["AWS_ACCESS_KEY_ID"]
  , secret: process.env["AWS_SECRET_ACCESS_KEY"]
  });
  amazon.on("error", function (error, statusCode) {
    console.log(arguments);
    if (error.message) {
      console.log(sys.inspect(error.message, true, 100));
      console.log(sys.inspect(error.stack, true, 100));
    } else {
      console.log(sys.inspect(error, true, 100));
    }
  });
  amazon.call("DescribeVolumes", function (struct) {
    var volume = struct.volumeSet.filter(function (volume) { return volume.volumeId == VOLUME; })[0];
    if (/^in-use|attaching$/.test(volume.status)) {
      throw new Error("Volume is already attached.");
    }
  });
  amazon.call("RunInstances",
  { ImageId: AMI
  , KeyName: "backup_key"
  , MinCount: 1
  , MaxCount: 1
  , "Placement.AvailabilityZone": "us-east-1b"
  }, function (struct) {
    state.reservationId = struct.reservationId;
    state.instanceId = struct.instancesSet[0].instanceId;
  });
  amazon.poll("DescribeInstances", function (struct) {
    var reservation = struct.reservationSet.filter(function (reservation) {
      return reservation.reservationId == state.reservationId;
    })[0];
    var instance = reservation.instancesSet.filter(function (instance) {
      return instance.instanceId == state.instanceId;
    })[0];
    return instance.instanceState.name == "running";
  });
  amazon.call("AttachVolume",
  { VolumeId: VOLUME
  , InstanceId: function () { return state.instanceId; }
  , Device: "/dev/sdh"
  });
  amazon.poll("DescribeVolumes", { "VolumeId.1": VOLUME }, function (struct) {
    var attachment = struct.volumeSet[0].attachmentSet.filter(function (attachment) {
      return attachment.instanceId == state.instanceId;
    })[0];
    return attachment.status == "attached";
  });
  amazon.on("end", function () {
    console.log("Volume attached and running with instance: " + state.instanceId);
  });
  amazon.execute();
}

launch();

// vim: set ts=2 sw=2 et nowrap:
<commit_msg>Prettified launch.<commit_after>var ec2 = require("ec2"), sys = require("sys");

var AMI = "ami-2d4aa444";
var VOLUME = "vol-d6bf23bf";

function createRequest() {
  return ec2.request(
  { key: process.env["AWS_ACCESS_KEY_ID"]
  , secret: process.env["AWS_SECRET_ACCESS_KEY"]
  });
}

function launch () {
  var state = {};
  var amazon = ec2.createClient(
  { key: process.env["AWS_ACCESS_KEY_ID"]
  , secret: process.env["AWS_SECRET_ACCESS_KEY"]
  });
  amazon.on("error", function (error, statusCode) {
    console.log(arguments);
    if (error.message) {
      console.log(sys.inspect(error.message, true, 100));
      console.log(sys.inspect(error.stack, true, 100));
    } else {
      console.log(sys.inspect(error, true, 100));
    }
  });
  amazon.call("DescribeVolumes", function (struct) {
    var volume = struct.volumeSet.filter(function (volume) { return volume.volumeId == VOLUME; })[0];
    if (/^in-use|attaching$/.test(volume.status)) {
      throw new Error("Volume is already attached.");
    }
  });
  amazon.call("RunInstances",
  { ImageId: AMI
  , KeyName: "backup_key"
  , MinCount: 1
  , MaxCount: 1
  , "Placement.AvailabilityZone": "us-east-1b"
  }, function (struct) {
    state.reservationId = struct.reservationId;
    state.instanceId = struct.instancesSet[0].instanceId;
  });
  amazon.poll("DescribeInstances", function (struct) {
    var reservation = struct.reservationSet.filter(function (reservation) {
      return reservation.reservationId == state.reservationId;
    }).pop():
    var instance = reservation.instancesSet.filter(function (instance) {
      return instance.instanceId == state.instanceId;
    }).pop();
    return instance.instanceState.name == "running";
  });
  amazon.call("AttachVolume",
  { VolumeId: VOLUME
  , InstanceId: function () { return state.instanceId; }
  , Device: "/dev/sdh"
  });
  amazon.poll("DescribeVolumes", { "VolumeId.1": VOLUME }, function (struct) {
    var attachment = struct.volumeSet[0].attachmentSet.filter(function (attachment) {
      return attachment.instanceId == state.instanceId;
    })[0];
    return attachment.status == "attached";
  });
  amazon.on("end", function () {
    console.log("Volume attached and running with instance: " + state.instanceId);
  });
  amazon.execute();
}

launch();

// vim: set ts=2 sw=2 et nowrap:
<|endoftext|>


<commit_before>function Level() {
    this.name = "";
    this.waveLimits = [4, 6, 10];
    this.startingCalories = 0;
    this.caloriesPerWave = 2;
    this.grid = [[]];
    this.paths = [[],[],[]];
    this.towers = [];
    this.mines = [];
    this.farms = [];
    this.nests = [];
    this.cities = [];
    this.classType = 'Level';
}
/**
 * Casts an object with levelData into an instance of Level
 *
 * @param {Object} levelData  the data for the level
 * @return {Level}  the instantiated Level
 */
function createLevel(levelData) {
    return objectToInstance(levelData);
}

function initializeStructure(structureData) {
    var structure = objectToInstance(structureData);
    structure.mapX = structure.tileX * defaultTileSize;
    structure.mapY = structure.tileY * defaultTileSize;
    state.mapGrid[structure.tileY][structure.tileX] = structure;
    return structure;
}

function initializeTower(towerData) {
    /** @type Tower */
    var tower = initializeStructure(towerData);
    tower.type = towerTypes[tower.typeKey];
    tower.baseDamage = tower.type.baseDamage;
    tower.damageRange = tower.type.damageRange;
    tower.range = tower.type.range;
    tower.attacksPerSecond = tower.type.attacksPerSecond;
    return tower;
}

/**
 * @param {Level} level
 */
function startLevel(level) {
    state.currentLevel = level;
    state.humanGold = 0;
    state.waveNumber = 0;
    state.abilitiesUsedThisTurn = 0;
    state.step = 'cards';
    state.levelModifiers = {};
    state.waveModifiers = {};
    state.mapGrid = arrayToGrid(level.grid);
    state.calories = level.startingCalories;
    state.gold = 0;
    clearCardArea();
    state.dealtCards = [];
    state.discardedCards = [];
    state.deck = copy(testDeck);
    state.selectedElement = null;
    shuffleDeck();
    state.farms = level.farms.map(initializeStructure);
    state.mines = level.mines.map(initializeStructure);
    state.towers = level.towers.map(initializeTower);
    state.nests = level.nests.map(initializeStructure);
    state.cities = level.cities.map(initializeStructure);
    state.population = 0;
    for (var i = 0; i < state.cities.length; i++) {
        state.population += state.cities[i].population;
    }
    for (var i = 0; i < level.paths.length; i++) {
        state.paths[i].oldPoints = state.paths[i].points = level.paths[i];
        state.paths[i].complete = true;
    }
    //erase any animals currently in the timeline
    for (var i = 0; i < state.paths.length; i++) {
        for (var j = 0; j < state.paths[i].slots.length; j++) {
            state.paths[i].slots[j] = null;
        }
    }
    state.waveLimit = level.waveLimits[2];
    drawGrid(game.backgroundContext, state.mapGrid);
    selectPath(0);
    updateActionButton();
    startCardStep();
}

function arrayToGrid(arrayOfStrings) {
    var grid = [];
    $.each(arrayOfStrings, function (i, string) {
        var row = string.split('');
        grid.push(row);
        $.each(row, function (j, string) {
            if (string == 'C') {
                row[j] = new City();
            }
            if (string == 'F') {
                row[j] = new Farm();
            }
            if (string == 'M') {
                row[j] = new Mine();
            }
            if (string == 'N') {
                row[j] = new Nest();
            }
            if (string == 'T') {
                row[j] = getRandomTower();
            }
        });
    });
    return grid;
}

var levels = [createLevel({"name": "River City",
"waveLimits": [2,3,5],
"startingCalories": 3,
"caloriesPerWave": 2,
"grid": [
  "WWWWWWWWWWWWW0000",
  "WWWWWWWWWWWWWW110",
  "0WWWWWWWWWWWWWWW0",
  "0111WWWWWWWWWWWWW",
  "0111111111WWWWWWW",
  "011RRRRRRRRRRR1WW",
  "050R0555R1210R110",
  "030R5555R1212R110",
  "000RRRRRR1212R010",
  "005R1WW1R1212R000",
  "000RWWWWR1212R030",
  "030R2WW0R1212R500",
  "010RRRRRRRRRRR000",
  "00000500000000030",
  "00400000030450040",
  "00003004000004000",
  "00000000000000000"
],
"paths": [[[8,12],[8,11],[8,10],[8,9],[8,8],[8,7],[8,6],[8,5],[9,5],[10,5],[11,5],[12,5],[13,5],[13,6],[13,7],[13,8],[13,9],[13,10],[13,11],[13,12],[12,12],[11,12],[10,12],[9,12],[8,12]],[[8,12],[7,12],[6,12],[5,12],[4,12],[3,12],[3,11],[3,10],[3,9],[3,8],[3,7],[3,6],[3,5],[4,5],[5,5],[6,5],[7,5],[8,5],[8,6],[8,7],[8,8],[8,9],[8,10],[8,11],[8,12]],[[8,12],[8,11],[8,10],[8,9],[8,8],[8,7],[8,6],[8,5],[7,5],[6,5],[5,5],[4,5],[3,5],[3,6],[3,7],[3,8],[4,8],[5,8],[6,8],[7,8],[8,8],[8,9],[8,10],[8,11],[8,12]]],
"towers": [{"classType":"Tower","tileX":4,"tileY":6,"typeKey":"basic"},{"classType":"Tower","tileX":12,"tileY":6,"typeKey":"lightning"}],
"mines": [],
"farms": [],
"nests": [{"classType":"Nest","tileX":8,"tileY":12}],
"cities": [{"classType":"City","tileX":8,"tileY":5,"population":20,"productivity":0}],
"classType": "Level"
}),
createLevel({"name": "Dead Treeville",
"waveLimits": [3,5,8],
"startingCalories": 10,
"caloriesPerWave": 2,
"grid": [
  "00000000000000000",
  "00004051100100510",
  "00RRRRR1500115110",
  "04R000R0000004000",
  "05R000R000RRRRR10",
  "01R000RRRRR405R50",
  "01RRRRR000R000R00",
  "011R000000R000R00",
  "051R500000R000R00",
  "000R000000R000R00",
  "00RRRRRRRRRRRRR10",
  "03R4030R0001515WW",
  "02R3200R005WWWWWW",
  "04R5300R01WWWWWWW",
  "02RRRRRR00WWWWWWW",
  "035020400WWWWWWWW",
  "000000000WWWWWWWW"
],
"paths": [[[2,14],[2,13],[2,12],[2,11],[2,10],[3,10],[4,10],[5,10],[6,10],[7,10],[8,10],[9,10],[10,10],[10,9],[10,8],[10,7],[10,6],[10,5],[10,4],[11,4],[12,4],[13,4],[14,4],[14,5],[14,6],[14,7],[14,8],[14,9],[14,10],[13,10],[12,10],[11,10],[10,10],[9,10],[8,10],[7,10],[6,10],[5,10],[4,10],[3,10],[2,10],[2,11],[2,12],[2,13],[2,14]],[[2,14],[2,13],[2,12],[2,11],[2,10],[3,10],[3,9],[3,8],[3,7],[3,6],[2,6],[2,5],[2,4],[2,3],[2,2],[3,2],[4,2],[5,2],[6,2],[6,3],[6,4],[6,5],[6,6],[5,6],[4,6],[3,6],[3,7],[3,8],[3,9],[3,10],[2,10],[2,11],[2,12],[2,13],[2,14]],[[2,14],[2,13],[2,12],[2,11],[2,10],[3,10],[3,9],[3,8],[3,7],[3,6],[2,6],[2,5],[2,4],[2,3],[2,2],[3,2],[4,2],[5,2],[6,2],[6,3],[6,4],[6,5],[7,5],[8,5],[9,5],[10,5],[10,4],[11,4],[12,4],[13,4],[14,4],[14,5],[14,6],[14,7],[14,8],[14,9],[14,10],[13,10],[12,10],[11,10],[10,10],[9,10],[8,10],[7,10],[7,11],[7,12],[7,13],[7,14],[6,14],[5,14],[4,14],[3,14],[2,14]]],
"towers": [{"classType":"Tower","tileX":9,"tileY":6,"typeKey":"lightning"},{"classType":"Tower","tileX":3,"tileY":3,"typeKey":"lightning"},{"classType":"Tower","tileX":8,"tileY":9,"typeKey":"basic"}],
"mines": [],
"farms": [{"classType":"Farm","tileX":6,"tileY":6,"calories":10}],
"nests": [{"classType":"Nest","tileX":2,"tileY":14}],
"cities": [{"classType":"City","tileX":2,"tileY":2,"population":30,"productivity":0.2},{"classType":"City","tileX":10,"tileY":5,"population":30,"productivity":0.2}],
"classType": "Level"
}),
createLevel({"name": "Onette",
"waveLimits": [4,6,10],
"startingCalories": 5,
"caloriesPerWave": 2,
"grid": [
  "0WWW0000000000000",
  "01WBBRRR0131RRR00",
  "031BWWWR1RRRR1R10",
  "010RWWWR2R11R1R30",
  "000R0WWB1R20R1R10",
  "000R12WBBRRRR1R00",
  "0RRRRR2BWWWR22R00",
  "0R010RRBWWWBW1R00",
  "0R131R120WWBBBRR0",
  "0R010R01211RWWWR0",
  "0R00RRR0110RWWWBW",
  "0RRRR0R1310R2BBBW",
  "000R00RRRRRRRRWWW",
  "00RR0131R0100RRWW",
  "00R31010R13100R2W",
  "00RRRRRRRRRRRRR10",
  "00000000000000000"
],
"paths": [[[2,15],[2,14],[2,13],[3,13],[3,12],[3,11],[4,11],[4,10],[5,10],[5,9],[5,8],[5,7],[5,6],[4,6],[3,6],[3,5],[3,4],[3,3],[3,2],[3,1],[4,1],[5,1],[6,1],[7,1],[7,2],[7,3],[7,4],[7,5],[8,5],[9,5],[10,5],[11,5],[11,6],[11,7],[11,8],[12,8],[13,8],[14,8],[15,8]],[[2,15],[3,15],[4,15],[5,15],[6,15],[7,15],[8,15],[9,15],[10,15],[11,15],[12,15],[13,15],[14,15],[14,14],[14,13],[13,13],[13,12],[13,11],[14,11],[15,11],[15,10],[15,9],[15,8]],[[15,8],[14,8],[13,8],[12,8],[11,8],[11,7],[11,6],[11,5],[10,5],[9,5],[8,5],[7,5],[7,6],[7,7],[6,7],[5,7],[5,8],[5,9],[5,10],[6,10],[6,11],[6,12],[7,12],[8,12],[9,12],[10,12],[11,12],[12,12],[13,12],[13,11],[14,11],[15,11],[15,10],[15,9],[15,8]]],
"towers": [{"classType":"Tower","tileX":4,"tileY":4,"typeKey":"lightning"},{"classType":"Tower","tileX":11,"tileY":4,"typeKey":"artillery"},{"classType":"Tower","tileX":8,"tileY":8,"typeKey":"artillery"},{"classType":"Tower","tileX":12,"tileY":13,"typeKey":"basic"}],
"mines": [{"classType":"Mine","tileX":14,"tileY":14,"gold":10}],
"farms": [{"classType":"Farm","tileX":3,"tileY":3,"calories":10}],
"nests": [{"classType":"Nest","tileX":15,"tileY":8},{"classType":"Nest","tileX":2,"tileY":15}],
"cities": [{"classType":"City","tileX":9,"tileY":5,"population":100,"productivity":0.1},{"classType":"City","tileX":5,"tileY":7,"population":100,"productivity":0.1}],
"classType": "Level"
})];
<commit_msg>Fix starting calories for first level.<commit_after>function Level() {
    this.name = "";
    this.waveLimits = [4, 6, 10];
    this.startingCalories = 0;
    this.caloriesPerWave = 2;
    this.grid = [[]];
    this.paths = [[],[],[]];
    this.towers = [];
    this.mines = [];
    this.farms = [];
    this.nests = [];
    this.cities = [];
    this.classType = 'Level';
}
/**
 * Casts an object with levelData into an instance of Level
 *
 * @param {Object} levelData  the data for the level
 * @return {Level}  the instantiated Level
 */
function createLevel(levelData) {
    return objectToInstance(levelData);
}

function initializeStructure(structureData) {
    var structure = objectToInstance(structureData);
    structure.mapX = structure.tileX * defaultTileSize;
    structure.mapY = structure.tileY * defaultTileSize;
    state.mapGrid[structure.tileY][structure.tileX] = structure;
    return structure;
}

function initializeTower(towerData) {
    /** @type Tower */
    var tower = initializeStructure(towerData);
    tower.type = towerTypes[tower.typeKey];
    tower.baseDamage = tower.type.baseDamage;
    tower.damageRange = tower.type.damageRange;
    tower.range = tower.type.range;
    tower.attacksPerSecond = tower.type.attacksPerSecond;
    return tower;
}

/**
 * @param {Level} level
 */
function startLevel(level) {
    state.currentLevel = level;
    state.humanGold = 0;
    state.waveNumber = 0;
    state.abilitiesUsedThisTurn = 0;
    state.step = 'cards';
    state.levelModifiers = {};
    state.waveModifiers = {};
    state.mapGrid = arrayToGrid(level.grid);
    state.calories = level.startingCalories;
    state.gold = 0;
    clearCardArea();
    state.dealtCards = [];
    state.discardedCards = [];
    state.deck = copy(testDeck);
    state.selectedElement = null;
    shuffleDeck();
    state.farms = level.farms.map(initializeStructure);
    state.mines = level.mines.map(initializeStructure);
    state.towers = level.towers.map(initializeTower);
    state.nests = level.nests.map(initializeStructure);
    state.cities = level.cities.map(initializeStructure);
    state.population = 0;
    for (var i = 0; i < state.cities.length; i++) {
        state.population += state.cities[i].population;
    }
    for (var i = 0; i < level.paths.length; i++) {
        state.paths[i].oldPoints = state.paths[i].points = level.paths[i];
        state.paths[i].complete = true;
    }
    //erase any animals currently in the timeline
    for (var i = 0; i < state.paths.length; i++) {
        for (var j = 0; j < state.paths[i].slots.length; j++) {
            state.paths[i].slots[j] = null;
        }
    }
    state.waveLimit = level.waveLimits[2];
    drawGrid(game.backgroundContext, state.mapGrid);
    selectPath(0);
    updateActionButton();
    startCardStep();
}

function arrayToGrid(arrayOfStrings) {
    var grid = [];
    $.each(arrayOfStrings, function (i, string) {
        var row = string.split('');
        grid.push(row);
        $.each(row, function (j, string) {
            if (string == 'C') {
                row[j] = new City();
            }
            if (string == 'F') {
                row[j] = new Farm();
            }
            if (string == 'M') {
                row[j] = new Mine();
            }
            if (string == 'N') {
                row[j] = new Nest();
            }
            if (string == 'T') {
                row[j] = getRandomTower();
            }
        });
    });
    return grid;
}

var levels = [createLevel({"name": "River City",
"waveLimits": [2,3,5],
"startingCalories": 10,
"caloriesPerWave": 2,
"grid": [
  "WWWWWWWWWWWWW0000",
  "WWWWWWWWWWWWWW110",
  "0WWWWWWWWWWWWWWW0",
  "0111WWWWWWWWWWWWW",
  "0111111111WWWWWWW",
  "011RRRRRRRRRRR1WW",
  "050R0555R1210R110",
  "030R5555R1212R110",
  "000RRRRRR1212R010",
  "005R1WW1R1212R000",
  "000RWWWWR1212R030",
  "030R2WW0R1212R500",
  "010RRRRRRRRRRR000",
  "00000500000000030",
  "00400000030450040",
  "00003004000004000",
  "00000000000000000"
],
"paths": [[[8,12],[8,11],[8,10],[8,9],[8,8],[8,7],[8,6],[8,5],[9,5],[10,5],[11,5],[12,5],[13,5],[13,6],[13,7],[13,8],[13,9],[13,10],[13,11],[13,12],[12,12],[11,12],[10,12],[9,12],[8,12]],[[8,12],[7,12],[6,12],[5,12],[4,12],[3,12],[3,11],[3,10],[3,9],[3,8],[3,7],[3,6],[3,5],[4,5],[5,5],[6,5],[7,5],[8,5],[8,6],[8,7],[8,8],[8,9],[8,10],[8,11],[8,12]],[[8,12],[8,11],[8,10],[8,9],[8,8],[8,7],[8,6],[8,5],[7,5],[6,5],[5,5],[4,5],[3,5],[3,6],[3,7],[3,8],[4,8],[5,8],[6,8],[7,8],[8,8],[8,9],[8,10],[8,11],[8,12]]],
"towers": [{"classType":"Tower","tileX":4,"tileY":6,"typeKey":"basic"},{"classType":"Tower","tileX":12,"tileY":6,"typeKey":"lightning"}],
"mines": [],
"farms": [],
"nests": [{"classType":"Nest","tileX":8,"tileY":12}],
"cities": [{"classType":"City","tileX":8,"tileY":5,"population":20,"productivity":0}],
"classType": "Level"
}),
createLevel({"name": "Dead Treeville",
"waveLimits": [3,5,8],
"startingCalories": 10,
"caloriesPerWave": 2,
"grid": [
  "00000000000000000",
  "00004051100100510",
  "00RRRRR1500115110",
  "04R000R0000004000",
  "05R000R000RRRRR10",
  "01R000RRRRR405R50",
  "01RRRRR000R000R00",
  "011R000000R000R00",
  "051R500000R000R00",
  "000R000000R000R00",
  "00RRRRRRRRRRRRR10",
  "03R4030R0001515WW",
  "02R3200R005WWWWWW",
  "04R5300R01WWWWWWW",
  "02RRRRRR00WWWWWWW",
  "035020400WWWWWWWW",
  "000000000WWWWWWWW"
],
"paths": [[[2,14],[2,13],[2,12],[2,11],[2,10],[3,10],[4,10],[5,10],[6,10],[7,10],[8,10],[9,10],[10,10],[10,9],[10,8],[10,7],[10,6],[10,5],[10,4],[11,4],[12,4],[13,4],[14,4],[14,5],[14,6],[14,7],[14,8],[14,9],[14,10],[13,10],[12,10],[11,10],[10,10],[9,10],[8,10],[7,10],[6,10],[5,10],[4,10],[3,10],[2,10],[2,11],[2,12],[2,13],[2,14]],[[2,14],[2,13],[2,12],[2,11],[2,10],[3,10],[3,9],[3,8],[3,7],[3,6],[2,6],[2,5],[2,4],[2,3],[2,2],[3,2],[4,2],[5,2],[6,2],[6,3],[6,4],[6,5],[6,6],[5,6],[4,6],[3,6],[3,7],[3,8],[3,9],[3,10],[2,10],[2,11],[2,12],[2,13],[2,14]],[[2,14],[2,13],[2,12],[2,11],[2,10],[3,10],[3,9],[3,8],[3,7],[3,6],[2,6],[2,5],[2,4],[2,3],[2,2],[3,2],[4,2],[5,2],[6,2],[6,3],[6,4],[6,5],[7,5],[8,5],[9,5],[10,5],[10,4],[11,4],[12,4],[13,4],[14,4],[14,5],[14,6],[14,7],[14,8],[14,9],[14,10],[13,10],[12,10],[11,10],[10,10],[9,10],[8,10],[7,10],[7,11],[7,12],[7,13],[7,14],[6,14],[5,14],[4,14],[3,14],[2,14]]],
"towers": [{"classType":"Tower","tileX":9,"tileY":6,"typeKey":"lightning"},{"classType":"Tower","tileX":3,"tileY":3,"typeKey":"lightning"},{"classType":"Tower","tileX":8,"tileY":9,"typeKey":"basic"}],
"mines": [],
"farms": [{"classType":"Farm","tileX":6,"tileY":6,"calories":10}],
"nests": [{"classType":"Nest","tileX":2,"tileY":14}],
"cities": [{"classType":"City","tileX":2,"tileY":2,"population":30,"productivity":0.2},{"classType":"City","tileX":10,"tileY":5,"population":30,"productivity":0.2}],
"classType": "Level"
}),
createLevel({"name": "Onette",
"waveLimits": [4,6,10],
"startingCalories": 5,
"caloriesPerWave": 2,
"grid": [
  "0WWW0000000000000",
  "01WBBRRR0131RRR00",
  "031BWWWR1RRRR1R10",
  "010RWWWR2R11R1R30",
  "000R0WWB1R20R1R10",
  "000R12WBBRRRR1R00",
  "0RRRRR2BWWWR22R00",
  "0R010RRBWWWBW1R00",
  "0R131R120WWBBBRR0",
  "0R010R01211RWWWR0",
  "0R00RRR0110RWWWBW",
  "0RRRR0R1310R2BBBW",
  "000R00RRRRRRRRWWW",
  "00RR0131R0100RRWW",
  "00R31010R13100R2W",
  "00RRRRRRRRRRRRR10",
  "00000000000000000"
],
"paths": [[[2,15],[2,14],[2,13],[3,13],[3,12],[3,11],[4,11],[4,10],[5,10],[5,9],[5,8],[5,7],[5,6],[4,6],[3,6],[3,5],[3,4],[3,3],[3,2],[3,1],[4,1],[5,1],[6,1],[7,1],[7,2],[7,3],[7,4],[7,5],[8,5],[9,5],[10,5],[11,5],[11,6],[11,7],[11,8],[12,8],[13,8],[14,8],[15,8]],[[2,15],[3,15],[4,15],[5,15],[6,15],[7,15],[8,15],[9,15],[10,15],[11,15],[12,15],[13,15],[14,15],[14,14],[14,13],[13,13],[13,12],[13,11],[14,11],[15,11],[15,10],[15,9],[15,8]],[[15,8],[14,8],[13,8],[12,8],[11,8],[11,7],[11,6],[11,5],[10,5],[9,5],[8,5],[7,5],[7,6],[7,7],[6,7],[5,7],[5,8],[5,9],[5,10],[6,10],[6,11],[6,12],[7,12],[8,12],[9,12],[10,12],[11,12],[12,12],[13,12],[13,11],[14,11],[15,11],[15,10],[15,9],[15,8]]],
"towers": [{"classType":"Tower","tileX":4,"tileY":4,"typeKey":"lightning"},{"classType":"Tower","tileX":11,"tileY":4,"typeKey":"artillery"},{"classType":"Tower","tileX":8,"tileY":8,"typeKey":"artillery"},{"classType":"Tower","tileX":12,"tileY":13,"typeKey":"basic"}],
"mines": [{"classType":"Mine","tileX":14,"tileY":14,"gold":10}],
"farms": [{"classType":"Farm","tileX":3,"tileY":3,"calories":10}],
"nests": [{"classType":"Nest","tileX":15,"tileY":8},{"classType":"Nest","tileX":2,"tileY":15}],
"cities": [{"classType":"City","tileX":9,"tileY":5,"population":100,"productivity":0.1},{"classType":"City","tileX":5,"tileY":7,"population":100,"productivity":0.1}],
"classType": "Level"
})];
<|endoftext|>


<commit_before>/**
 * 2w - Simple 2-way data binding
 * Copyright (c) 2014 Nicolás Arias
 * MIT Licensed
 */

(function (window) {
    'use strict';

    /**
     * Document reference
     */
    var doc = window.document;

    /**
     * Controllers store
     * @type {Object}
     */
    var _controllers = {};

    /**
     * Controller callbacks go here. They're executed after DOM load
     * @type {Array}
     */
    var _bootstrap = [];

    /**
     * Prevents digest overlapping (see digest())
     * @type {Boolean}
     */
    var _clear = true;

    /**
     * Default configuration
     * @type {Object}
     */
    var _cfg = {
        controllerAttr:  'data-controller',
        formModelAttr:   'data-model',
        expressionStart: '{{',
        expressionEnd:   '}}',
        interval:        50,
        manual:          false
    };

    /**
     * Typeof dictionary
     * @type {Object}
     */
    var types = {
        object: 'object',
        array: 'object',
        func: 'function',
        undef: 'undefined'
    };

    /**
     * toString dictionary
     * @type {Object}
     */
    var strTypes = {
        object: '[object Object]',
        array: '[object Array]',
        func: '[object Function]'
    };

    /**
     * Helper shortcuts
     */
    var toString = Object.prototype.toString;

    /**
     * Library
     * @type {Function}
     */
    var $2w = function (){};

    /**
     * Initializes $2w. It loops through the dom (see traverse()), then apply controller callbacks
     * and finally starts observing (see digest())
     */
    $2w.prototype.initialize = function () {
        var self = this,_e = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g; // http://stackoverflow.com/a/6969486/772002
        _cfg._expre = new RegExp(_cfg.expressionStart.replace(_e, "\\$&")+'(.*?)'+_cfg.expressionEnd.replace(_e, "\\$&"));

        self.traverse(doc.documentElement);

        _bootstrap.forEach(function (bootstrap) {
            var cb = bootstrap.shift();
            cb.apply(null, bootstrap.map(function (c) {
                return self._controller(c).$scope;
            }));
        });

        self.digest();
    };

    /**
     * Loops through the DOM *once* and attach corresponding controllers to their DOM elements (see attachController())
     * @param  {DOMElement} node    root element to start traversing
     */
    $2w.prototype.traverse = function (node) {
        var self = this, i, l, ctrl;

        if (node.nodeType === 1 && node.hasAttribute(_cfg.controllerAttr)) {
            ctrl = node.getAttribute(_cfg.controllerAttr);
            _controllers[ctrl] = self._attachController(node, ctrl);
        }

        if (node.hasChildNodes()) {
            for (i = 0, l = node.childNodes.length; i < l; i++) {
                self.traverse(node.childNodes[i]);
            }
        }
    };

    /**
     * (1) Returns a controller (it creates one if it doesn't exist), or (2) bootstraps a callback
     * @param  {String}     id  Controller id/name
     * @param  {Function}   cb  Controller callback
     * @return {Object}         (1) Controller or (2) $2w
     */
    $2w.prototype._controller = function (id, cb) {
        var controllers;

        if (typeof cb === types.undef) {
            return _controllers[id] || (_controllers[id] = {
                _scope: {},
                $scope: {},
                dic: {},
                org: {},
                tmp: {}
            });
        }

        controllers = id.split(/\s+/);
        controllers.unshift(cb);
        _bootstrap.push(controllers);

        return $2w;
    };

    /**
     * Public version - (1) Returns a controller's *scope*, or (2) bootstraps a callback
     * @param  {String}     id  Controller id/name
     * @param  {Function}   cb  Controller callback
     * @return {Object}         (1) Controller's scope or (2) $2w
     */
    $2w.prototype.controller = function (id, cb){
        return typeof cb === types.undef ? this._controller(id).$scope : this._controller(id, cb);
    };

    /**
     * Stores a reference to this element, its childs and its attributes, in a controller's dictionary
     * @param  {DOMElement} node    Element to store
     * @param  {Mixed}      ctrl    Controller object or name string
     * @param  {Boolean}    force   Marks that it should be processed (see digest()) as soon as it is attached.
     *                              This lets attach a controller dynamically and see the results immediately.
     * @return {Object}             Controller
     */
    $2w.prototype._attachController = function (node, ctrl, force) {
        var self = this, i, l, id, matches;

        if (typeof ctrl !== types.object) {
            ctrl = self._controller(ctrl);
        }

        if (force) ctrl.force = true;

        // DOM Element with attributes -> attach controller to attributes
        if (node.nodeType === 1 && node.hasAttributes()) {
            for (i = 0, l = node.attributes.length; i < l; i++) {
                self._attachController(node.attributes[i], ctrl);
            }
        }

        // DOM Element with child nodes -> attach controller to child nodes
        if (node.hasChildNodes()) {
            for (i = 0, l = node.childNodes.length; i < l; i++) {
                self._attachController(node.childNodes[i], ctrl);
            }
        }

        // Input or textarea elements -> attach controller and add change listeners
        // TODO less hardcode
        else if (node.nodeType === 1 && (node.nodeName === 'INPUT' || node.nodeName === 'TEXTAREA')) {
            if (node.hasAttribute(_cfg.formModelAttr)) {
                id = Math.random();
                ctrl.dic[id] = node;
                self.addInputListener(node, ctrl);
            }
        }

        // DOM Attribute -> attach controller
        else if (node.nodeType === 2) {
            matches = node.value.search(_cfg._expre);
            if (matches !== -1) {
                id = Math.random();
                ctrl.org[id] = node.value;
                ctrl.dic[id] = node;
            }
        }

        // Finally, text node -> attach controller
        else if (node.nodeType === 3) {
            matches = node.nodeValue.search(_cfg._expre);
            if (matches !== -1) {
                id = Math.random();
                ctrl.org[id] = node.textContent || node.nodeValue;
                ctrl.dic[id] = node;
            }
        }

        return ctrl;
    };

    /**
     * Public version - DOM Element to a controller and process it (see attachController's @force)
     * @param  {DOMElement} node    Element to attach controller to
     * @param  {String}     ctrl    Controller id/name
     * @return {Object}             Controller's scope
     */
    $2w.prototype.attachController = function (node, ctrl) {
        return this._attachController(node, ctrl, true).$scope;
    };

    $2w.prototype.render = function (ctrl) {
        var self = this, node, key;

        for (key in ctrl.dic) {
            node = ctrl.dic[key];

            // For input and textareas, skip if it's focused or reflect changes directly in their 'value'
            // TODO less hardcode
            if (node.nodeType === 1 && (node.nodeName === 'INPUT' || node.nodeName === 'TEXTAREA')) {
                if (node === doc.activeElement) continue;
                node.value = self.expression.call(ctrl, node.getAttribute(_cfg.formModelAttr));
            }

            // Otherwise apply changes consecutively in a temporal (ctrl.tmp) variable
            else if (node.nodeType === 2 || node.nodeType === 3) {
                if (!ctrl.tmp[key]) ctrl.tmp[key] = ctrl.org[key];
                while (ctrl.tmp[key].search(_cfg._expre) !== -1) {
                    ctrl.tmp[key] = ctrl.tmp[key].replace(_cfg._expre, function (str, exp) {
                        return self.expression.call(ctrl, exp);
                    });
                }
            }
        }

        // Once changes have been processed, apply them in the elements content
        for (key in ctrl.dic) {
            node = ctrl.dic[key];

            if (node.nodeType === 2) {
                node.value = ctrl.tmp[key];
            }

            else if (node.nodeType === 3) {
                if (node.textContent) { node.textContent = ctrl.tmp[key]; }
                else { node.nodeValue = ctrl.tmp[key]; }
            }
        }

        ctrl.tmp = {};
        return ctrl;
    };

    /**
     * Waits for content changes in controller-attached-elements and reflects those changes everywhere
     */
    $2w.prototype.digest = function () {
        var self = this, node, key, ctrl;

        if (!_clear) return;
        _clear = false;

        for (key in _controllers) {
            ctrl = _controllers[key];

            // Do stuff only if things have changed
            if (ctrl.force || !equals(ctrl.$scope, ctrl._scope)) {
                self.render(ctrl);
                ctrl._scope = clone(ctrl.$scope); // Keep a backup of the current state
                ctrl.force = false;
            }
        }

        // Re check
        if (!_cfg.manual) setTimeout(function (){
            self.digest();
        }, _cfg.interval);
        _clear = true;
    };

    /**
     * Evaluates a js expression within a scope and returns its result
     * @param  {String} exp JavaScript expression
     * @return {String}     Hopefully a value, or '' in case of error
     */
    $2w.prototype.expression = function (exp, ctx) {
        var result, f;

        try {
            //f = eval('with (this.$scope) { ' + exp + ' });
            f = new Function ('with (this.$scope) { return (' + exp + '); }');
            result = f.call(ctx || this);
            if (result === null || typeof result === types.undef) result = '';
        } catch(e) {
            result = '';
        };

        return result;
    };

    /**
     * Adds event listeners to input/textarea elements so their values are reflected on their models
     * TODO there must be a better approach
     * @param {DOMElement}  node    Input/textarea element
     * @param {Object}      ctrl    Controller object (parent of the @node's model)
     */
    $2w.prototype.addInputListener = function (node, ctrl) {
        var cb = function (evt) {
            var el = (evt.srcElement || this);
            ctrl.$scope[el.getAttribute(_cfg.formModelAttr)] = el.value;
        };
        if (node.addEventListener) {
            node.addEventListener('keypress', cb, false);
            node.addEventListener('keyup', cb, false);
        } else {
            node.attachEvent('onkeypress', cb);
            node.attachEvent('onkeyup', cb);
        }
    };

    /**
     * Expose prototype
     */
    $2w.prototype.fn = $2w.prototype;

    /**
     * Expose configuration
     */
    $2w.prototype.config = _cfg;

    /**
     * Expose lib
     */
    window.$2w = new $2w;

    /**
     * Run
     */
    function init() { if (!_cfg.manual) window.$2w.initialize(); }
    doc.addEventListener && doc.addEventListener("DOMContentLoaded", init, false);
    doc.attachEvent && doc.attachEvent("onreadystatechange", function () { doc.readyState === "complete" && init(); });

    /**
     * Checks for 'deep' equality
     * @param  {Object}     a   Object to compare
     * @param  {Object}     b   Object to compare
     * @return {Boolean}        Equality
     */
    function equals(a, b) {
        var idx, len, lenb, key, ta, tb;

        // Equal primitives
        if (a === b) {
            return true;
        }

        ta = typeof a;
        tb = typeof b;

        // Unequal primitives
        if (ta !== tb ||
            ta !== types.func && ta !== types.object &&
            tb !== types.func && tb !== types.object && a !== b) {
            return false;
        }

        ta = toString.call(a);
        tb = toString.call(b);

        // Array vs object
        if (ta !== tb) {
            return false;
        }

        // Array elements comparison
        else if (ta === strTypes.array) {
            if ((len = a.length) !== b.length) {
                return false;
            }

            for (idx = 0; idx < len; idx++) {
                if (!equals(a[idx], b[idx])) {
                    return false;
                }
            }
        }

        // Object elements comparison
        else if (ta === strTypes.object) {
            len = 0;
            for (key in a) {
                len++;
                if (!equals(a[key], b[key])) {
                    return false;
                }
            }

            lenb = 0;
            for (key in b) {
                lenb++;
            }

            if (len !== lenb) {
                return false;
            }
        }

        return true;
    };

    /**
     * 'Deep' cloning
     * @param  {Mixed} a    Value to clone
     * @return {Mixed}      Cloned value :)
     */
    function clone(a) {
        var idx, key, len, type, result;

        type = typeof a;

        if (a === null || type !== types.object) {
            return a;
        }

        type = toString.call(a);

        if (type === strTypes.array) {
            result = [];
            for (idx = 0, len = a.length; idx < len; idx++) {
                result.push(clone(a[idx]));
            }
        }

        else if (type === strTypes.object) {
            result = {};
            for (key in a) {
                result[key] = clone(a[key]);
            }
        }

        return result;
    };

    /**
     * Quick forEach polyfill (just functionality needed in this lib)
     * @param  {Function}   cb  Callback
     * @param  {Mixed}      th  this argument for callback
     */
    !Array.prototype.forEach && (Array.prototype.forEach = function (cb, th) {
        var i, l;
        for (i = 0, l = this.length; i < l; i++) {
            if (cb.call(th, this[i], i, this));
        }
    });

    /**
     * Quick map polyfill (just functionality needed in this lib)
     * @param  {Function}   cb  Callback
     * @param  {Mixed}      th  this argument for callback
     */
    !Array.prototype.map && (Array.prototype.map = function (cb, th) {
        var result = [];
        this.forEach(function(e, i){
            result.push(cb.call(th, e, i));
        })
        return result;
    });

})(window);<commit_msg>Bootrapped controllers can be reinit'd<commit_after>/**
 * 2w - Simple 2-way data binding
 * Copyright (c) 2014 Nicolás Arias
 * MIT Licensed
 */

(function (window) {
    'use strict';

    /**
     * Document reference
     */
    var doc = window.document;

    /**
     * Controllers store
     * @type {Object}
     */
    var _controllers = {};

    /**
     * Controller callbacks go here. They're executed after DOM load
     * @type {Array}
     */
    var _bootstrap = [];

    /**
     * Prevents digest overlapping (see digest())
     * @type {Boolean}
     */
    var _clear = true;

    /**
     * Default configuration
     * @type {Object}
     */
    var _cfg = {
        controllerAttr:  'data-controller',
        formModelAttr:   'data-model',
        expressionStart: '{{',
        expressionEnd:   '}}',
        interval:        50,
        manual:          false
    };

    /**
     * Typeof dictionary
     * @type {Object}
     */
    var types = {
        object: 'object',
        array: 'object',
        func: 'function',
        undef: 'undefined'
    };

    /**
     * toString dictionary
     * @type {Object}
     */
    var strTypes = {
        object: '[object Object]',
        array: '[object Array]',
        func: '[object Function]'
    };

    /**
     * Helper shortcuts
     */
    var toString = Object.prototype.toString;

    /**
     * Library
     * @type {Function}
     */
    var $2w = function (){};

    /**
     * Initializes $2w. It loops through the dom (see traverse()), then apply controller callbacks
     * and finally starts observing (see digest())
     */
    $2w.prototype.initialize = function () {
        var self = this,_e = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g; // http://stackoverflow.com/a/6969486/772002
        _cfg._expre = new RegExp(_cfg.expressionStart.replace(_e, "\\$&")+'(.*?)'+_cfg.expressionEnd.replace(_e, "\\$&"));

        self.traverse(doc.documentElement);

        _bootstrap.forEach(function (bootstrap) {
            var cb = bootstrap[0];
            cb.apply(null, bootstrap.slice(1).map(function (c) {
                return self._controller(c).$scope;
            }));
        });

        self.digest();
    };

    /**
     * Loops through the DOM *once* and attach corresponding controllers to their DOM elements (see attachController())
     * @param  {DOMElement} node    root element to start traversing
     */
    $2w.prototype.traverse = function (node) {
        var self = this, i, l, ctrl;

        if (node.nodeType === 1 && node.hasAttribute(_cfg.controllerAttr)) {
            ctrl = node.getAttribute(_cfg.controllerAttr);
            _controllers[ctrl] = self._attachController(node, ctrl);
        }

        if (node.hasChildNodes()) {
            for (i = 0, l = node.childNodes.length; i < l; i++) {
                self.traverse(node.childNodes[i]);
            }
        }
    };

    /**
     * (1) Returns a controller (it creates one if it doesn't exist), or (2) bootstraps a callback
     * @param  {String}     id  Controller id/name
     * @param  {Function}   cb  Controller callback
     * @return {Object}         (1) Controller or (2) $2w
     */
    $2w.prototype._controller = function (id, cb) {
        var controllers;

        if (typeof cb === types.undef) {
            return _controllers[id] || (_controllers[id] = {
                _scope: {},
                $scope: {},
                dic: {},
                org: {},
                tmp: {}
            });
        }

        controllers = id.split(/\s+/);
        controllers.unshift(cb);
        _bootstrap.push(controllers);

        return $2w;
    };

    /**
     * Public version - (1) Returns a controller's *scope*, or (2) bootstraps a callback
     * @param  {String}     id  Controller id/name
     * @param  {Function}   cb  Controller callback
     * @return {Object}         (1) Controller's scope or (2) $2w
     */
    $2w.prototype.controller = function (id, cb){
        return typeof cb === types.undef ? this._controller(id).$scope : this._controller(id, cb);
    };

    /**
     * Stores a reference to this element, its childs and its attributes, in a controller's dictionary
     * @param  {DOMElement} node    Element to store
     * @param  {Mixed}      ctrl    Controller object or name string
     * @param  {Boolean}    force   Marks that it should be processed (see digest()) as soon as it is attached.
     *                              This lets attach a controller dynamically and see the results immediately.
     * @return {Object}             Controller
     */
    $2w.prototype._attachController = function (node, ctrl, force) {
        var self = this, i, l, id, matches;

        if (typeof ctrl !== types.object) {
            ctrl = self._controller(ctrl);
        }

        if (force) ctrl.force = true;

        // DOM Element with attributes -> attach controller to attributes
        if (node.nodeType === 1 && node.hasAttributes()) {
            for (i = 0, l = node.attributes.length; i < l; i++) {
                self._attachController(node.attributes[i], ctrl);
            }
        }

        // DOM Element with child nodes -> attach controller to child nodes
        if (node.hasChildNodes()) {
            for (i = 0, l = node.childNodes.length; i < l; i++) {
                self._attachController(node.childNodes[i], ctrl);
            }
        }

        // Input or textarea elements -> attach controller and add change listeners
        // TODO less hardcode
        else if (node.nodeType === 1 && (node.nodeName === 'INPUT' || node.nodeName === 'TEXTAREA')) {
            if (node.hasAttribute(_cfg.formModelAttr)) {
                id = Math.random();
                ctrl.dic[id] = node;
                self.addInputListener(node, ctrl);
            }
        }

        // DOM Attribute -> attach controller
        else if (node.nodeType === 2) {
            matches = node.value.search(_cfg._expre);
            if (matches !== -1) {
                id = Math.random();
                ctrl.org[id] = node.value;
                ctrl.dic[id] = node;
            }
        }

        // Finally, text node -> attach controller
        else if (node.nodeType === 3) {
            matches = node.nodeValue.search(_cfg._expre);
            if (matches !== -1) {
                id = Math.random();
                ctrl.org[id] = node.textContent || node.nodeValue;
                ctrl.dic[id] = node;
            }
        }

        return ctrl;
    };

    /**
     * Public version - DOM Element to a controller and process it (see attachController's @force)
     * @param  {DOMElement} node    Element to attach controller to
     * @param  {String}     ctrl    Controller id/name
     * @return {Object}             Controller's scope
     */
    $2w.prototype.attachController = function (node, ctrl) {
        return this._attachController(node, ctrl, true).$scope;
    };

    $2w.prototype.render = function (ctrl) {
        var self = this, node, key;

        for (key in ctrl.dic) {
            node = ctrl.dic[key];

            // For input and textareas, skip if it's focused or reflect changes directly in their 'value'
            // TODO less hardcode
            if (node.nodeType === 1 && (node.nodeName === 'INPUT' || node.nodeName === 'TEXTAREA')) {
                if (node === doc.activeElement) continue;
                node.value = self.expression.call(ctrl, node.getAttribute(_cfg.formModelAttr));
            }

            // Otherwise apply changes consecutively in a temporal (ctrl.tmp) variable
            else if (node.nodeType === 2 || node.nodeType === 3) {
                if (!ctrl.tmp[key]) ctrl.tmp[key] = ctrl.org[key];
                while (ctrl.tmp[key].search(_cfg._expre) !== -1) {
                    ctrl.tmp[key] = ctrl.tmp[key].replace(_cfg._expre, function (str, exp) {
                        return self.expression.call(ctrl, exp);
                    });
                }
            }
        }

        // Once changes have been processed, apply them in the elements content
        for (key in ctrl.dic) {
            node = ctrl.dic[key];

            if (node.nodeType === 2) {
                node.value = ctrl.tmp[key];
            }

            else if (node.nodeType === 3) {
                if (node.textContent) { node.textContent = ctrl.tmp[key]; }
                else { node.nodeValue = ctrl.tmp[key]; }
            }
        }

        ctrl.tmp = {};
        return ctrl;
    };

    /**
     * Waits for content changes in controller-attached-elements and reflects those changes everywhere
     */
    $2w.prototype.digest = function () {
        var self = this, node, key, ctrl;

        if (!_clear) return;
        _clear = false;

        for (key in _controllers) {
            ctrl = _controllers[key];

            // Do stuff only if things have changed
            if (ctrl.force || !equals(ctrl.$scope, ctrl._scope)) {
                self.render(ctrl);
                ctrl._scope = clone(ctrl.$scope); // Keep a backup of the current state
                ctrl.force = false;
            }
        }

        // Re check
        if (!_cfg.manual) setTimeout(function (){
            self.digest();
        }, _cfg.interval);
        _clear = true;
    };

    /**
     * Evaluates a js expression within a scope and returns its result
     * @param  {String} exp JavaScript expression
     * @return {String}     Hopefully a value, or '' in case of error
     */
    $2w.prototype.expression = function (exp, ctx) {
        var result, f;

        try {
            //f = eval('with (this.$scope) { ' + exp + ' });
            f = new Function ('with (this.$scope) { return (' + exp + '); }');
            result = f.call(ctx || this);
            if (result === null || typeof result === types.undef) result = '';
        } catch(e) {
            result = '';
        };

        return result;
    };

    /**
     * Adds event listeners to input/textarea elements so their values are reflected on their models
     * TODO there must be a better approach
     * @param {DOMElement}  node    Input/textarea element
     * @param {Object}      ctrl    Controller object (parent of the @node's model)
     */
    $2w.prototype.addInputListener = function (node, ctrl) {
        var cb = function (evt) {
            var el = (evt.srcElement || this);
            ctrl.$scope[el.getAttribute(_cfg.formModelAttr)] = el.value;
        };
        if (node.addEventListener) {
            node.addEventListener('keypress', cb, false);
            node.addEventListener('keyup', cb, false);
        } else {
            node.attachEvent('onkeypress', cb);
            node.attachEvent('onkeyup', cb);
        }
    };

    /**
     * Expose prototype
     */
    $2w.prototype.fn = $2w.prototype;

    /**
     * Expose configuration
     */
    $2w.prototype.config = _cfg;

    /**
     * Expose lib
     */
    window.$2w = new $2w;

    /**
     * Run
     */
    function init() { if (!_cfg.manual) window.$2w.initialize(); }
    doc.addEventListener && doc.addEventListener("DOMContentLoaded", init, false);
    doc.attachEvent && doc.attachEvent("onreadystatechange", function () { doc.readyState === "complete" && init(); });

    /**
     * Checks for 'deep' equality
     * @param  {Object}     a   Object to compare
     * @param  {Object}     b   Object to compare
     * @return {Boolean}        Equality
     */
    function equals(a, b) {
        var idx, len, lenb, key, ta, tb;

        // Equal primitives
        if (a === b) {
            return true;
        }

        ta = typeof a;
        tb = typeof b;

        // Unequal primitives
        if (ta !== tb ||
            ta !== types.func && ta !== types.object &&
            tb !== types.func && tb !== types.object && a !== b) {
            return false;
        }

        ta = toString.call(a);
        tb = toString.call(b);

        // Array vs object
        if (ta !== tb) {
            return false;
        }

        // Array elements comparison
        else if (ta === strTypes.array) {
            if ((len = a.length) !== b.length) {
                return false;
            }

            for (idx = 0; idx < len; idx++) {
                if (!equals(a[idx], b[idx])) {
                    return false;
                }
            }
        }

        // Object elements comparison
        else if (ta === strTypes.object) {
            len = 0;
            for (key in a) {
                len++;
                if (!equals(a[key], b[key])) {
                    return false;
                }
            }

            lenb = 0;
            for (key in b) {
                lenb++;
            }

            if (len !== lenb) {
                return false;
            }
        }

        return true;
    };

    /**
     * 'Deep' cloning
     * @param  {Mixed} a    Value to clone
     * @return {Mixed}      Cloned value :)
     */
    function clone(a) {
        var idx, key, len, type, result;

        type = typeof a;

        if (a === null || type !== types.object) {
            return a;
        }

        type = toString.call(a);

        if (type === strTypes.array) {
            result = [];
            for (idx = 0, len = a.length; idx < len; idx++) {
                result.push(clone(a[idx]));
            }
        }

        else if (type === strTypes.object) {
            result = {};
            for (key in a) {
                result[key] = clone(a[key]);
            }
        }

        return result;
    };

    /**
     * Quick forEach polyfill (just functionality needed in this lib)
     * @param  {Function}   cb  Callback
     * @param  {Mixed}      th  this argument for callback
     */
    !Array.prototype.forEach && (Array.prototype.forEach = function (cb, th) {
        var i, l;
        for (i = 0, l = this.length; i < l; i++) {
            if (cb.call(th, this[i], i, this));
        }
    });

    /**
     * Quick map polyfill (just functionality needed in this lib)
     * @param  {Function}   cb  Callback
     * @param  {Mixed}      th  this argument for callback
     */
    !Array.prototype.map && (Array.prototype.map = function (cb, th) {
        var result = [];
        this.forEach(function(e, i){
            result.push(cb.call(th, e, i));
        })
        return result;
    });

})(window);<|endoftext|>


<commit_before>/* eslint-env node */
'use strict';

const AddonDocsConfig = require('../lib/config');

module.exports = class extends AddonDocsConfig {
  shouldDeploy() {
    let env = process.env;
    if (env.CI) {
      // If in CI, deploy whenever we do a build on master in the default ember-try scenario
      return env.TRAVIS_BRANCH === 'master' && env.EMBER_TRY_SCENARIO === 'ember-default';
    } else {
      // Always deploy when `ember deploy` is manually run
      return true;
    }
  }
}
<commit_msg>Fix deploys with new Travis setup<commit_after>/* eslint-env node */
'use strict';

const AddonDocsConfig = require('../lib/config');

module.exports = class extends AddonDocsConfig {

}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;
var parallel = require('run-parallel');

var errors = require('./errors');
var OutArgStream = require('./argstream').OutArgStream;

var emptyBuffer = Buffer(0);

var States = Object.create(null);
States.Initial = 0;
States.Streaming = 1;
States.Done = 2;
States.Error = 3;

function TChannelOutgoingRequest(id, options) {
    options = options || {};
    if (!options.sendFrame) {
        throw new Error('missing sendFrame');
    }
    var self = this;
    EventEmitter.call(self);
    self.logger = options.logger;
    self.random = options.random;
    self.timers = options.timers;

    self.start = 0;
    self.end = 0;
    self.remoteAddr = options.remoteAddr;
    self.state = States.Initial;
    self.id = id || 0;
    self.ttl = options.ttl || 0;
    self.tracing = options.tracing || null;
    self.service = options.service || '';
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.checksum = options.checksum || null;

    self.sendFrame = options.sendFrame;
    if (options.streamed) {
        self.streamed = true;
        self._argstream = OutArgStream();
        self.arg1 = self._argstream.arg1;
        self.arg2 = self._argstream.arg2;
        self.arg3 = self._argstream.arg3;
        self._argstream.on('error', function passError(err) {
            self.emit('error', err);
        });
        self._argstream.on('frame', function onFrame(parts, isLast) {
            self.sendParts(parts, isLast);
        });
        self._argstream.on('finish', function onFinish() {
            self.emit('finish');
        });
    } else {
        self.streamed = false;
        self._argstream = null;
        self.arg1 = null;
        self.arg2 = null;
        self.arg3 = null;
    }

    if (options.tracer) {
        // new span with new ids
        self.span = options.tracer.setupNewSpan({
            outgoing: true,
            parentSpan: options.parentSpan,
            topLevelRequest: options.topLevelRequest,
            spanid: null,
            traceid: null,
            parentid: null,
            flags: options.trace? 1 : 0,
            hostPort: self.remoteAddr,
            serviceName: self.service,
            name: '' // fill this in later
        });

        self.tracing = self.span.getTracing();
    } else {
        self.span = null;
    }

    self.err = null;
    self.res = null;
    self.start = self.timers.now();
    self.timedOut = false;
}

inherits(TChannelOutgoingRequest, EventEmitter);

TChannelOutgoingRequest.prototype.type = 'tchannel.outgoing-request';

TChannelOutgoingRequest.prototype.sendParts = function sendParts(parts, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.start = self.timers.now();
            self.sendCallRequestFrame(parts, isLast);
            break;
        case States.Streaming:
            self.sendCallRequestContFrame(parts, isLast);
            break;
        case States.Done:
            // TODO: could probably happen normally, like say if a
            // streaming request is canceled
            throw new Error('got frame in done state'); // TODO: typed error
        case States.Error:
            // TODO: log warn
            break;
    }
};

TChannelOutgoingRequest.prototype.sendCallRequestFrame = function sendCallRequestFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            if (self.span) {
                self.span.annotate('cs');
            }
            self.sendFrame.callRequest(args, isLast);
            if (isLast) self.state = States.Done;
            else self.state = States.Streaming;
            break;
        case States.Streaming:
            throw new Error('first request frame already sent'); // TODO: typed error
        case States.Done:
            throw new Error('request already done'); // TODO: typed error
    }
};

TChannelOutgoingRequest.prototype.sendCallRequestContFrame = function sendCallRequestContFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            throw new Error('first request frame not sent'); // TODO: typed error
        case States.Streaming:
            self.sendFrame.callRequestCont(args, isLast);
            if (isLast) self.state = States.Done;
            break;
        case States.Done:
            throw new Error('request already done'); // TODO: typed error
    }
};

TChannelOutgoingRequest.prototype.send = function send(arg1, arg2, arg3, callback) {
    var self = this;

    if (self.span) {
        self.span.name = String(arg1);
    }
    if (callback) self.hookupCallback(callback);
    if (self.streamed) {
        self.arg1.end(arg1);
        self.arg2.end(arg2);
        self.arg3.end(arg3);
    } else {
        self.sendCallRequestFrame([
            arg1 ? Buffer(arg1) : emptyBuffer,
            arg2 ? Buffer(arg2) : emptyBuffer,
            arg3 ? Buffer(arg3) : emptyBuffer
        ], true);
        self.emit('finish');
    }
    return self;
};

TChannelOutgoingRequest.prototype.hookupStreamCallback = function hookupCallback(callback) {
    var self = this;
    var called = false;
    self.on('error', onError);
    self.on('response', onResponse);

    function onError(err) {
        if (called) return;
        called = true;
        self.err = err;
        if (!self.end) self.end = self.timers.now();
        callback(err, null, null);
    }

    function onResponse(res) {
        if (called) return;
        called = true;
        self.res = res;
        if (!self.end) self.end = self.timers.now();
        callback(null, self, res);
    }

    return self;
};

TChannelOutgoingRequest.prototype.hookupCallback = function hookupCallback(callback) {
    var self = this;
    if (callback.canStream) {
        return self.hookupStreamCallback(callback);
    }
    var called = false;

    self.on('error', onError);
    self.on('response', onResponse);

    function onError(err) {
        if (called) return;
        called = true;
        self.err = err;
        if (!self.end) self.end = self.timers.now();
        callback(err, null, null);
    }

    function onResponse(res) {
        if (called) return;
        called = true;
        self.res = res;
        if (!res.streamed) {
            if (!self.end) self.end = self.timers.now();
            callback(null, res, res.arg2, res.arg3);
            return;
        }
        parallel({
            arg2: res.arg2.onValueReady,
            arg3: res.arg3.onValueReady
        }, compatCall);
        function compatCall(err, args) {
            if (!self.end) self.end = self.timers.now();
            callback(err, res, args.arg2, args.arg3);
        }
    }

    return self;
};

TChannelOutgoingRequest.prototype.checkTimeout = function checkTimeout() {
    var self = this;
    if (!self.timedOut) {
        var now = self.timers.now();
        var elapsed = now - self.start;
        if (elapsed > self.ttl) {
            self.end = now;
            self.timedOut = true;
            process.nextTick(function deferOutReqTimeoutErrorEmit() {
                self.emit('error', errors.TimeoutError({
                    id: self.id,
                    start: self.start,
                    elapsed: elapsed,
                    timeout: self.ttl
                }));
            });
        }
    }
    return self.timedOut;
};

TChannelOutgoingRequest.States = States;

module.exports = TChannelOutgoingRequest;
<commit_msg>out req: decouple self.err/.res setting<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;
var parallel = require('run-parallel');

var errors = require('./errors');
var OutArgStream = require('./argstream').OutArgStream;

var emptyBuffer = Buffer(0);

var States = Object.create(null);
States.Initial = 0;
States.Streaming = 1;
States.Done = 2;
States.Error = 3;

function TChannelOutgoingRequest(id, options) {
    options = options || {};
    if (!options.sendFrame) {
        throw new Error('missing sendFrame');
    }
    var self = this;
    EventEmitter.call(self);
    self.logger = options.logger;
    self.random = options.random;
    self.timers = options.timers;

    self.start = 0;
    self.end = 0;
    self.remoteAddr = options.remoteAddr;
    self.state = States.Initial;
    self.id = id || 0;
    self.ttl = options.ttl || 0;
    self.tracing = options.tracing || null;
    self.service = options.service || '';
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.checksum = options.checksum || null;

    self.sendFrame = options.sendFrame;
    if (options.streamed) {
        self.streamed = true;
        self._argstream = OutArgStream();
        self.arg1 = self._argstream.arg1;
        self.arg2 = self._argstream.arg2;
        self.arg3 = self._argstream.arg3;
        self._argstream.on('error', function passError(err) {
            self.emit('error', err);
        });
        self._argstream.on('frame', function onFrame(parts, isLast) {
            self.sendParts(parts, isLast);
        });
        self._argstream.on('finish', function onFinish() {
            self.emit('finish');
        });
    } else {
        self.streamed = false;
        self._argstream = null;
        self.arg1 = null;
        self.arg2 = null;
        self.arg3 = null;
    }

    if (options.tracer) {
        // new span with new ids
        self.span = options.tracer.setupNewSpan({
            outgoing: true,
            parentSpan: options.parentSpan,
            topLevelRequest: options.topLevelRequest,
            spanid: null,
            traceid: null,
            parentid: null,
            flags: options.trace? 1 : 0,
            hostPort: self.remoteAddr,
            serviceName: self.service,
            name: '' // fill this in later
        });

        self.tracing = self.span.getTracing();
    } else {
        self.span = null;
    }

    self.err = null;
    self.res = null;
    self.start = self.timers.now();
    self.timedOut = false;

    self.on('error', self.onError);
    self.on('response', self.onResponse);

}

inherits(TChannelOutgoingRequest, EventEmitter);

TChannelOutgoingRequest.prototype.type = 'tchannel.outgoing-request';

TChannelOutgoingRequest.prototype.onError = function onError(err) {
    var self = this;
    self.err = err;
};

TChannelOutgoingRequest.prototype.onResponse = function onResponse(res) {
    var self = this;
    self.res = res;
};

TChannelOutgoingRequest.prototype.sendParts = function sendParts(parts, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.start = self.timers.now();
            self.sendCallRequestFrame(parts, isLast);
            break;
        case States.Streaming:
            self.sendCallRequestContFrame(parts, isLast);
            break;
        case States.Done:
            // TODO: could probably happen normally, like say if a
            // streaming request is canceled
            throw new Error('got frame in done state'); // TODO: typed error
        case States.Error:
            // TODO: log warn
            break;
    }
};

TChannelOutgoingRequest.prototype.sendCallRequestFrame = function sendCallRequestFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            if (self.span) {
                self.span.annotate('cs');
            }
            self.sendFrame.callRequest(args, isLast);
            if (isLast) self.state = States.Done;
            else self.state = States.Streaming;
            break;
        case States.Streaming:
            throw new Error('first request frame already sent'); // TODO: typed error
        case States.Done:
            throw new Error('request already done'); // TODO: typed error
    }
};

TChannelOutgoingRequest.prototype.sendCallRequestContFrame = function sendCallRequestContFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            throw new Error('first request frame not sent'); // TODO: typed error
        case States.Streaming:
            self.sendFrame.callRequestCont(args, isLast);
            if (isLast) self.state = States.Done;
            break;
        case States.Done:
            throw new Error('request already done'); // TODO: typed error
    }
};

TChannelOutgoingRequest.prototype.send = function send(arg1, arg2, arg3, callback) {
    var self = this;

    if (self.span) {
        self.span.name = String(arg1);
    }
    if (callback) self.hookupCallback(callback);
    if (self.streamed) {
        self.arg1.end(arg1);
        self.arg2.end(arg2);
        self.arg3.end(arg3);
    } else {
        self.sendCallRequestFrame([
            arg1 ? Buffer(arg1) : emptyBuffer,
            arg2 ? Buffer(arg2) : emptyBuffer,
            arg3 ? Buffer(arg3) : emptyBuffer
        ], true);
        self.emit('finish');
    }
    return self;
};

TChannelOutgoingRequest.prototype.hookupStreamCallback = function hookupCallback(callback) {
    var self = this;
    var called = false;

    self.on('error', onError);
    self.on('response', onResponse);

    function onError(err) {
        if (called) return;
        called = true;
        if (!self.end) self.end = self.timers.now();
        callback(err, null, null);
    }

    function onResponse(res) {
        if (called) return;
        called = true;
        if (!self.end) self.end = self.timers.now();
        callback(null, self, res);
    }

    return self;
};

TChannelOutgoingRequest.prototype.hookupCallback = function hookupCallback(callback) {
    var self = this;
    if (callback.canStream) {
        return self.hookupStreamCallback(callback);
    }
    var called = false;

    self.on('error', onError);
    self.on('response', onResponse);

    function onError(err) {
        if (called) return;
        called = true;
        if (!self.end) self.end = self.timers.now();
        callback(err, null, null);
    }

    function onResponse(res) {
        if (called) return;
        called = true;
        if (!res.streamed) {
            if (!self.end) self.end = self.timers.now();
            callback(null, res, res.arg2, res.arg3);
            return;
        }
        parallel({
            arg2: res.arg2.onValueReady,
            arg3: res.arg3.onValueReady
        }, compatCall);
        function compatCall(err, args) {
            if (!self.end) self.end = self.timers.now();
            callback(err, res, args.arg2, args.arg3);
        }
    }

    return self;
};

TChannelOutgoingRequest.prototype.checkTimeout = function checkTimeout() {
    var self = this;
    if (!self.timedOut) {
        var now = self.timers.now();
        var elapsed = now - self.start;
        if (elapsed > self.ttl) {
            self.end = now;
            self.timedOut = true;
            process.nextTick(function deferOutReqTimeoutErrorEmit() {
                self.emit('error', errors.TimeoutError({
                    id: self.id,
                    start: self.start,
                    elapsed: elapsed,
                    timeout: self.ttl
                }));
            });
        }
    }
    return self.timedOut;
};

TChannelOutgoingRequest.States = States;

module.exports = TChannelOutgoingRequest;
<|endoftext|>