<commit_before>/** kate-script
 * name: Ruby
 * license: LGPL
 * author: Robin Pedersen <robin.pedersen@runbox.com>
 * version: 1
 * kate-version: 3.0
 * type: indentation
 *
 * This file is part of the Kate Project.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License version 2 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

//BEGIN USER CONFIGURATION
//END USER CONFIGURATION

// specifies the characters which should trigger indent, beside the default '\n'
var triggerCharacters = "cdefhilnrsuw}]";

// Indent after lines that match this regexp
var rxIndent = /^\s*(def|if|unless|for|while|until|class|module|else|elsif|case|when|begin|rescue|ensure|catch)\b/;

// Unindent lines that match this regexp
var rxUnindent = /^\s*((end|when|else|elsif|rescue|ensure)\b|[\]\}])(.*)$/;

function assert(cond)
{
  if (!cond)
    throw "assertion failure";
}

function isComment(attr)
{
  return (attr == 30 || attr == 31);
}

function isString(attr)
{
  return (attr == 13 || attr == 14);
}

function isCommentAttr(line, column)
{
  var attr = document.attribute(line, column);
  return isComment(attr);
}

// Return the closest non-empty line, ignoring comments
// (result <= line). Return -1 if the document
function findPrevNonCommentLine(line)
{
  line = document.prevNonEmptyLine(line);
  while (line >= 0 && isCommentAttr(line, document.firstColumn(line))) {
    line = document.prevNonEmptyLine(line - 1);
  }
  return line;
}

function isLineContinuing(line)
{
  return /\\$/.test(document.line(line));
}

// Look for a pattern at the end of the statement.
//
// Returns true if the pattern is found, in a position
// that is not inside a string or a comment, and the position +
// the length of the matching part is either the end of the
// statement, or a comment.
//
// The regexp must be global, and the search is continued until
// a match is found, or the end of the string is reached.
function testAtEnd(stmt, rx)
{
  assert(rx.global);

  var cnt = stmt.content();
  var res;
  while (res = rx.exec(cnt)) {
    var start = res.index;
    var end = rx.lastIndex;
    var attr = stmt.attribute(start);
    if (!isString(attr) && !isComment(attr)) {
      if (end == cnt.length)
        return true;
      if (isComment(stmt.attribute(end)))
        return true;
    }
  }
  return false;
}

function isStmtContinuing(line)
{
  // TODO: Continuing if line ends with / operator, but not /regexp/
  //       Ignoring / for now, because it's probably far less common
  //       to have lines ending with division than regexp

  var stmt = new Statement(line, line);
  var rx = /((\+|\-|\*|\=|&&|\|\||\band\b|\bor\b|,)\s*)/g;

  return testAtEnd(stmt, rx);
}

// Return the first line that is not preceeded by a "continuing" line.
// Return currLine if currLine <= 0
function findStmtStart(currLine)
{
  var p, l = currLine;
  do {
    if (l <= 0) return l;
    p = l;
    l = findPrevNonCommentLine(l - 1);
  } while ((l == p-1 && isLineContinuing(l)) || isStmtContinuing(l));
  return p;
}

// Statement class
function Statement(start, end)
{
  this.start = start;
  this.end = end;

  // Convert to string for debugging
  this.toString = function() {
    return "{" + this.start + "," + this.end + "}";
  }

  // Return document.attribute at the given offset in a statement
  this.attribute = function(offset) {
    var line = this.start;
    while (line < this.end && document.lineLength(line) < offset) {
      offset -= document.lineLength(line++) + 1;
    }
    return document.attribute(line, offset);
  }

  this.indent = function() {
    return document.firstVirtualColumn(this.start)
  }

  // Return the content of the statement from the document
  this.content = function() {
    var cnt = "";
    for (var l = this.start; l <= this.end; l++) {
      cnt += document.line(l).replace(/\\$/, " ");
      if (l < this.end)
        cnt += " ";
    }
    return cnt;
  }
}

// Returns a tuple that contains the first and last line of the
// previous statement before line.
function findPrevStmt(line)
{
  var stmtEnd = findPrevNonCommentLine(line);
  var stmtStart = findStmtStart(stmtEnd);

  return new Statement(stmtStart, stmtEnd);
}

function isBlockStart(stmt)
{
  var cnt = stmt.content();
  var len = cnt.length;

  if (rxIndent.test(cnt))
    return true;

  var rx = /((\bdo\b|\{)(\s*\|.*\|)?\s*)/g;

  return testAtEnd(stmt, rx);
}

function isBlockEnd(stmt)
{
  var cnt = stmt.content();

  return rxUnindent.test(cnt);
}

function findBlockStart(line)
{
  var nested = 0;
  var stmt = new Statement(line, line);
  while (true) {
    if (stmt.start < 0) return stmt;

    stmt = findPrevStmt(stmt.start - 1);
    if (isBlockEnd(stmt)) {
      nested++;
    }
    if (isBlockStart(stmt)) {
      if (nested == 0)
        return stmt;
      else
        nested--;
    }
  }
}

// check if the trigger characters are in the right context,
// otherwise running the indenter might be annoying to the user
function isValidTrigger(line, ch)
{
  if (ch == "" || ch == "\n")
    return true; // Explicit align or new line

  var res = rxUnindent.exec(document.line(line));
  if (res) {
    if (res[3] == "")
      return true; // Exact match
  }
  return false;
}

// indent gets three arguments: line, indentwidth in spaces,
// typed character indent
function indent(line, indentWidth, ch)
{
  if (!isValidTrigger(line, ch))
    return -2;

  var prevStmt = findPrevStmt(line - 1);
  if (prevStmt.end < 0)
    return -2; // Can't indent the first line

  var prevStmtCnt = prevStmt.content();
  var prevStmtInd = prevStmt.indent();

  // Handle indenting of multiline statements.
  // Manually indenting to be able to force spaces.
  if ((prevStmt.end == line-1 && isLineContinuing(prevStmt.end)) || isStmtContinuing(prevStmt.end)) {
    var len = document.firstColumn(prevStmt.end);
    var str = document.line(prevStmt.end).substring(0, len);
    if (!document.startsWith(line, str, false)) {
      document.removeText(line, 0, line, document.firstColumn(line));
      if (prevStmt.start == prevStmt.end)
        str += "    ";
      document.insertText(line, 0, str);
    }
    return -2;
  }

  if (rxUnindent.test(document.line(line))) {
    var startStmt = findBlockStart(line);
    if (startStmt.start >= 0)
      return startStmt.indent();
    else
      return -2;
  }

  if (isBlockStart(prevStmt)) {
    return prevStmtInd + indentWidth;
  } else if (prevStmtCnt.search(/[\[\{]\s*$/) != -1) {
    return prevStmtInd + indentWidth;
  }

  // Keep current
  return prevStmtInd;
}

// kate: indent-width 2; indent-spaces on;
<commit_msg>Included division operator at the end of line in detector for "continuing" statements.<commit_after>/** kate-script
 * name: Ruby
 * license: LGPL
 * author: Robin Pedersen <robin.pedersen@runbox.com>
 * version: 1
 * kate-version: 3.0
 * type: indentation
 *
 * This file is part of the Kate Project.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License version 2 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

//BEGIN USER CONFIGURATION
//END USER CONFIGURATION

// specifies the characters which should trigger indent, beside the default '\n'
var triggerCharacters = "cdefhilnrsuw}]";

// Indent after lines that match this regexp
var rxIndent = /^\s*(def|if|unless|for|while|until|class|module|else|elsif|case|when|begin|rescue|ensure|catch)\b/;

// Unindent lines that match this regexp
var rxUnindent = /^\s*((end|when|else|elsif|rescue|ensure)\b|[\]\}])(.*)$/;

function assert(cond)
{
  if (!cond)
    throw "assertion failure";
}

function isComment(attr)
{
  return (attr == 30 || attr == 31);
}

function isString(attr)
{
  return (attr == 13 || attr == 14);
}

function isCommentAttr(line, column)
{
  var attr = document.attribute(line, column);
  return isComment(attr);
}

// Return the closest non-empty line, ignoring comments
// (result <= line). Return -1 if the document
function findPrevNonCommentLine(line)
{
  line = document.prevNonEmptyLine(line);
  while (line >= 0 && isCommentAttr(line, document.firstColumn(line))) {
    line = document.prevNonEmptyLine(line - 1);
  }
  return line;
}

function isLineContinuing(line)
{
  return /\\$/.test(document.line(line));
}

// Look for a pattern at the end of the statement.
//
// Returns true if the pattern is found, in a position
// that is not inside a string or a comment, and the position +
// the length of the matching part is either the end of the
// statement, or a comment.
//
// The regexp must be global, and the search is continued until
// a match is found, or the end of the string is reached.
function testAtEnd(stmt, rx)
{
  assert(rx.global);

  var cnt = stmt.content();
  var res;
  while (res = rx.exec(cnt)) {
    var start = res.index;
    var end = rx.lastIndex;
    if (stmt.isCode(start)) {
      if (end == cnt.length)
        return true;
      if (isComment(stmt.attribute(end)))
        return true;
    }
  }
  return false;
}

function isStmtContinuing(line)
{
  var stmt = new Statement(line, line);
  var rx = /((\+|\-|\*|\/|\=|&&|\|\||\band\b|\bor\b|,)\s*)/g;

  return testAtEnd(stmt, rx);
}

// Return the first line that is not preceeded by a "continuing" line.
// Return currLine if currLine <= 0
function findStmtStart(currLine)
{
  var p, l = currLine;
  do {
    if (l <= 0) return l;
    p = l;
    l = findPrevNonCommentLine(l - 1);
  } while ((l == p-1 && isLineContinuing(l)) || isStmtContinuing(l));
  return p;
}

// Statement class
function Statement(start, end)
{
  this.start = start;
  this.end = end;

  // Convert to string for debugging
  this.toString = function() {
    return "{" + this.start + "," + this.end + "}";
  }

  // Return document.attribute at the given offset in a statement
  this.attribute = function(offset) {
    var line = this.start;
    while (line < this.end && document.lineLength(line) < offset) {
      offset -= document.lineLength(line++) + 1;
    }
    return document.attribute(line, offset);
  }

  // Return document.isCode at the given offset in a statement
  this.isCode = function(offset) {
    var line = this.start;
    while (line < this.end && document.lineLength(line) < offset) {
      offset -= document.lineLength(line++) + 1;
    }
    return document.isCode(line, offset);
  }

  this.indent = function() {
    return document.firstVirtualColumn(this.start)
  }

  // Return the content of the statement from the document
  this.content = function() {
    var cnt = "";
    for (var l = this.start; l <= this.end; l++) {
      cnt += document.line(l).replace(/\\$/, " ");
      if (l < this.end)
        cnt += " ";
    }
    return cnt;
  }
}

// Returns a tuple that contains the first and last line of the
// previous statement before line.
function findPrevStmt(line)
{
  var stmtEnd = findPrevNonCommentLine(line);
  var stmtStart = findStmtStart(stmtEnd);

  return new Statement(stmtStart, stmtEnd);
}

function isBlockStart(stmt)
{
  var cnt = stmt.content();
  var len = cnt.length;

  if (rxIndent.test(cnt))
    return true;

  var rx = /((\bdo\b|\{)(\s*\|.*\|)?\s*)/g;

  return testAtEnd(stmt, rx);
}

function isBlockEnd(stmt)
{
  var cnt = stmt.content();

  return rxUnindent.test(cnt);
}

function findBlockStart(line)
{
  var nested = 0;
  var stmt = new Statement(line, line);
  while (true) {
    if (stmt.start < 0) return stmt;

    stmt = findPrevStmt(stmt.start - 1);
    if (isBlockEnd(stmt)) {
      nested++;
    }
    if (isBlockStart(stmt)) {
      if (nested == 0)
        return stmt;
      else
        nested--;
    }
  }
}

// check if the trigger characters are in the right context,
// otherwise running the indenter might be annoying to the user
function isValidTrigger(line, ch)
{
  if (ch == "" || ch == "\n")
    return true; // Explicit align or new line

  var res = rxUnindent.exec(document.line(line));
  if (res) {
    if (res[3] == "")
      return true; // Exact match
  }
  return false;
}

// indent gets three arguments: line, indentwidth in spaces,
// typed character indent
function indent(line, indentWidth, ch)
{
  if (!isValidTrigger(line, ch))
    return -2;

  var prevStmt = findPrevStmt(line - 1);
  if (prevStmt.end < 0)
    return -2; // Can't indent the first line

  var prevStmtCnt = prevStmt.content();
  var prevStmtInd = prevStmt.indent();

  // Handle indenting of multiline statements.
  // Manually indenting to be able to force spaces.
  if ((prevStmt.end == line-1 && isLineContinuing(prevStmt.end)) || isStmtContinuing(prevStmt.end)) {
    var len = document.firstColumn(prevStmt.end);
    var str = document.line(prevStmt.end).substring(0, len);
    if (!document.startsWith(line, str, false)) {
      document.removeText(line, 0, line, document.firstColumn(line));
      if (prevStmt.start == prevStmt.end)
        str += "    ";
      document.insertText(line, 0, str);
    }
    return -2;
  }

  if (rxUnindent.test(document.line(line))) {
    var startStmt = findBlockStart(line);
    if (startStmt.start >= 0)
      return startStmt.indent();
    else
      return -2;
  }

  if (isBlockStart(prevStmt)) {
    return prevStmtInd + indentWidth;
  } else if (prevStmtCnt.search(/[\[\{]\s*$/) != -1) {
    return prevStmtInd + indentWidth;
  }

  // Keep current
  return prevStmtInd;
}

// kate: indent-width 2; indent-spaces on;
<|endoftext|>


<commit_before>// Copyright (c) 2016 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.

import React from 'react';

import {
  XYPlot,
  XAxis,
  YAxis,
  VerticalGridLines,
  HorizontalGridLines,
  MarkSeries} from '../../';

export default class Example extends React.Component {
  render() {
    return (
      <XYPlot
        width={300}
        height={300}>
        <VerticalGridLines />
        <HorizontalGridLines />
        <XAxis />
        <YAxis />
        <MarkSeries
          data={[
            {x: 1, y: 10, size: 30},
            {x: 2, y: 5, size: 1},
            {x: 3, y: 15, size: 20}
          ]}/>
      </XYPlot>
    );
  }
}
<commit_msg>More circles to scatteplot. Adding more circles to scatterplot to make it visually appealing.<commit_after>// Copyright (c) 2016 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.

import React from 'react';

import {
  XYPlot,
  XAxis,
  YAxis,
  VerticalGridLines,
  HorizontalGridLines,
  MarkSeries} from '../../';

export default class Example extends React.Component {
  render() {
    return (
      <XYPlot
        width={300}
        height={300}>
        <VerticalGridLines />
        <HorizontalGridLines />
        <XAxis />
        <YAxis />
        <MarkSeries
          sizeRange={[5, 15]}
          data={[
            {x: 1, y: 10, size: 30},
            {x: 1.7, y: 12, size: 10},
            {x: 2, y: 5, size: 1},
            {x: 3, y: 15, size: 12},
            {x: 2.5, y: 7, size: 4}
          ]}/>
      </XYPlot>
    );
  }
}
<|endoftext|>


<commit_before>/**
 * StopFlash
 *
 * https://github.com/JWhile/StopFlash
 *
 * content_script.js
 */

// function isFlash(HTMLElement element):boolean
var isFlash = function(element)
{
    return (element.nodeName === 'OBJECT' || element.nodeName === 'EMBED');
};

// class FlashCollection
function FlashCollection()
{
    this.flashElements = [];
}
// function add(NodeList elements)
FlashCollection.prototype.add = function(elements)
{
    for(var i = 0, e; i < elements.length; ++i)
    {
        e = elements[i];

        if(isFlash(e))
        {
            var parent = e;

            while(parent = parent.parentNode)
            {
                if(isFlash(parent))
                {
                    e = parent;
                }
            }

            var f = this.get(e);

            if(f == null)
            {
                f = new FlashElement(e);

                this.flashElements.push(f);
            }

            f.block();
        }
    }
};
// function remove(NodeList elements)
FlashCollection.prototype.remove = function(elements)
{
    for(var i = 0, f; i < elements.length; ++i)
    {
        f = this.get(elements[i]);

        if(f != null)
        {
            f.remove();
        }
    }
};
// function get(HTMLElement element)
FlashCollection.prototype.get = function(element)
{
    for(var i = 0; i < this.flashElements.length; ++i)
    {
        if(element == this.flashElements[i].element)
        {
            return this.flashElements[i];
        }
    }

    return null;
};

var styles = [
    'float', 'clear',
    'position', 'top', 'left',
    'width', 'height',
    'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
    'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
    'border-top', 'border-right', 'border-bottom', 'border-left'
]; // :Array<String>

// class FlashElement
function FlashElement(element)
{
    this.element = element; // :HTMLElement
    this.parent = element.parentNode; // :HTMLElement
    this.nextSibling = element.nextSibling; // :HTMLElement

    var self = this;

    var replacement = new Builder('div')
        .css('display', 'block')
        .css('cursor', 'pointer')
        .css('min-width', '64px')
        .css('min-height', '64px')
        .css('background', '#333 url("'+ chrome.extension.getURL('icons/stopflash_64.png') +'") center center no-repeat')
        .event('click', function()
        {
            self.unblock();
        });

    for(var i = 0; i < styles.length; ++i)
    {
        replacement.css(styles[i], Builder.getStyle(element, styles[i]));
    }

    this.replacement = replacement.node;
}
// function block():void
FlashElement.prototype.block = function()
{
    this.parent.removeChild(this.element);

    if(this.nextSibling != null)
    {
        this.parent.insertBefore(this.replacement, this.nextSibling);
    }
    else
    {
        this.parent.appendChild(this.replacement);
    }
};
// function unblock():void
FlashElement.prototype.unblock = function()
{
    this.parent.removeChild(this.replacement);

    if(this.nextSibling != null)
    {
        this.parent.insertBefore(this.element, this.nextSibling);
    }
    else
    {
        this.parent.appendChild(this.element);
    }
};
// function remove():void
FlashElement.prototype.remove = function()
{
    this.parent.removeChild(this.replacement);

    this.parent.removeChild(this.element);
};

// main
var main = function()
{
    var finder = new FlashCollection();

    finder.add(document.getElementsByTagName('OBJECT'));
    finder.add(document.getElementsByTagName('EMBED'));

    var observer = new MutationObserver(function(changes)
    {
        for(var i = 0, c; i < changes.length; ++i)
        {
            c = changes[i];

            if(c.addedNodes != null)
            {
                finder.add(c.addedNodes);
            }

            if(c.removedNodes != null)
            {
                finder.remove(c.removedNodes);
            }
        }
    });

    observer.observe(document, {childList: true, subtree: true});
};

document.addEventListener('DOMContentLoaded', main, false);
<commit_msg>Rename var finder -> elements in main<commit_after>/**
 * StopFlash
 *
 * https://github.com/JWhile/StopFlash
 *
 * content_script.js
 */

// function isFlash(HTMLElement element):boolean
var isFlash = function(element)
{
    return (element.nodeName === 'OBJECT' || element.nodeName === 'EMBED');
};

// class FlashCollection
function FlashCollection()
{
    this.flashElements = [];
}
// function add(NodeList elements)
FlashCollection.prototype.add = function(elements)
{
    for(var i = 0, e; i < elements.length; ++i)
    {
        e = elements[i];

        if(isFlash(e))
        {
            var parent = e;

            while(parent = parent.parentNode)
            {
                if(isFlash(parent))
                {
                    e = parent;
                }
            }

            var f = this.get(e);

            if(f == null)
            {
                f = new FlashElement(e);

                this.flashElements.push(f);
            }

            f.block();
        }
    }
};
// function remove(NodeList elements)
FlashCollection.prototype.remove = function(elements)
{
    for(var i = 0, f; i < elements.length; ++i)
    {
        f = this.get(elements[i]);

        if(f != null)
        {
            f.remove();
        }
    }
};
// function get(HTMLElement element)
FlashCollection.prototype.get = function(element)
{
    for(var i = 0; i < this.flashElements.length; ++i)
    {
        if(element == this.flashElements[i].element)
        {
            return this.flashElements[i];
        }
    }

    return null;
};

var styles = [
    'float', 'clear',
    'position', 'top', 'left',
    'width', 'height',
    'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
    'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
    'border-top', 'border-right', 'border-bottom', 'border-left'
]; // :Array<String>

// class FlashElement
function FlashElement(element)
{
    this.element = element; // :HTMLElement
    this.parent = element.parentNode; // :HTMLElement
    this.nextSibling = element.nextSibling; // :HTMLElement

    var self = this;

    var replacement = new Builder('div')
        .css('display', 'block')
        .css('cursor', 'pointer')
        .css('min-width', '64px')
        .css('min-height', '64px')
        .css('background', '#333 url("'+ chrome.extension.getURL('icons/stopflash_64.png') +'") center center no-repeat')
        .event('click', function()
        {
            self.unblock();
        });

    for(var i = 0; i < styles.length; ++i)
    {
        replacement.css(styles[i], Builder.getStyle(element, styles[i]));
    }

    this.replacement = replacement.node;
}
// function block():void
FlashElement.prototype.block = function()
{
    this.parent.removeChild(this.element);

    if(this.nextSibling != null)
    {
        this.parent.insertBefore(this.replacement, this.nextSibling);
    }
    else
    {
        this.parent.appendChild(this.replacement);
    }
};
// function unblock():void
FlashElement.prototype.unblock = function()
{
    this.parent.removeChild(this.replacement);

    if(this.nextSibling != null)
    {
        this.parent.insertBefore(this.element, this.nextSibling);
    }
    else
    {
        this.parent.appendChild(this.element);
    }
};
// function remove():void
FlashElement.prototype.remove = function()
{
    this.parent.removeChild(this.replacement);

    this.parent.removeChild(this.element);
};

// main
var main = function()
{
    var elements = new FlashCollection();

    elements.add(document.getElementsByTagName('OBJECT'));
    elements.add(document.getElementsByTagName('EMBED'));

    var observer = new MutationObserver(function(changes)
    {
        for(var i = 0, c; i < changes.length; ++i)
        {
            c = changes[i];

            if(c.addedNodes != null)
            {
                elements.add(c.addedNodes);
            }

            if(c.removedNodes != null)
            {
                elements.remove(c.removedNodes);
            }
        }
    });

    observer.observe(document, {childList: true, subtree: true});
};

document.addEventListener('DOMContentLoaded', main, false);
<|endoftext|>


<commit_before>var fs = require("fs");
var https = require("https");
var http = require("http");
var express = require("express");
var console = require("console");

var app = express();

try
{
    var settings = JSON.parse(fs.readFileSync("settings.json"));
}
catch(e)
{
    console.log("Error: Configuration file settings.json couldn't be parsed.\nSee Troubleshooting section in README.md for instructions.");
    process.exit(1);
}

if(settings.Server.enable_https)
{
    try
    {
	var privateKey  = fs.readFileSync(settings.Server.ssl_key_file).toString();
    }
    catch(e)
    {
	console.log("Error: unable to load SSL key. Please edit setting.json and put the correct path to your SSL private key file into \"ssl_key_file.\"");
	process.exit(1);
    }
    try
    {
	var certificate = fs.readFileSync(settings.Server.ssl_certificate_file).toString();
    }
    catch(e)
    {
	console.log("Error: unable to load SSL certificate. Please edit setting.json and put the correct path to your SSL certificate file into \"ssl_certificate_file.\"");
	process.exit(1);
    }
    var credentials = {key: privateKey, cert: certificate};
}

maxCallsPerMinute = {};
maxCallsPerMinutePerIP = {};
callsRemaining = {};
perIPCounter = {};
droppedCallsCounter = {};

var invalidRequestCounter = 0;
var forbiddenCallCounter = 0;
var connectionErrorMessageDisplayed = false;

settings.CallLimits.forEach(function(x) {
    maxCallsPerMinute[x.name] = x.maxPerMinute;
    maxCallsPerMinutePerIP[x.name] = x.maxPerMinutePerIP;
    callsRemaining[x.name] = x.maxPerMinute;
    droppedCallsCounter[x.name] = 0;
});

CounterInstance = function()
{
    this.overLimit=0;
    this.invalidRequests=0;
    this.forbiddenCalls=0;
    this.callsRemaining={};
    for (x in maxCallsPerMinutePerIP)
    {
      if(maxCallsPerMinutePerIP[x]!==null)
	  this.callsRemaining[x]=maxCallsPerMinutePerIP[x];
    }
}

require("log-timestamp");

app.get("*", function(request, response)
{
    if(settings.Server.enable_https&&request.protocol=="http")
    {
	if(settings.Server.https_port==443)
	    secureUrl="https://"+request.host+request.path;
	else
	    secureUrl="https://"+request.host+":"+settings.Server.https_port+request.path;
	response.writeHead(302, {"Location": secureUrl});
	response.end();
	return;
    }

    var webProxy = http.request({host: settings.RPC.host, port: settings.RPC.port, method: request.method, path: request.path, headers: request.headers}, function (proxy_res)
    {
	proxy_res.pipe(response, {end: true});
    });

    webProxy.on("error", function(error)
    {
	if(!connectionErrorMessageDisplayed)
	{
	    console.log("Error: cannot connect to twisterd.\nSee Troubleshooting section in README.md for instructions.");
	    connectionErrorMessageDisplayed=true;
	}
	response.send(502);
    });

    request.pipe(webProxy, {end: true});
});

app.post("/", function(request, response)
{
    request.rawBody = "";
    request.setEncoding("utf8");

    request.addListener("data", function(chunk)
    {
        request.rawBody += chunk;
    });

    request.addListener("end", function()
    {
	var remoteIP = request.connection.remoteAddress;

	if(perIPCounter[remoteIP]===undefined)
	{
	    perIPCounter[remoteIP]=new CounterInstance();
	}
	try
	{
	    bodyJson=JSON.parse(request.rawBody);
	    rpcMethod=bodyJson.method;
	}
	catch(e)
	{
	    perIPCounter[remoteIP].invalidRequests++;
	    invalidRequestCounter++;
	    return;
	}
	if(maxCallsPerMinute[rpcMethod]===undefined)
	{
	    perIPCounter[remoteIP].forbiddenCalls++;
	    forbiddenCallCounter++;
	    return;
	}
	if(maxCallsPerMinute[rpcMethod]!==null)
	{
	    if(callsRemaining[rpcMethod]<1)
	    {
	        droppedCallsCounter[rpcMethod]++;
		return;
	    }
	    else
	    {
		callsRemaining[rpcMethod]--;
	    }
	}

	if(maxCallsPerMinutePerIP[rpcMethod]!==null)
	{
	    if(perIPCounter[remoteIP].callsRemaining[rpcMethod]<1)
	    {
		perIPCounter[remoteIP].overLimit++;
		return;
	    }
	    else
	    {
		perIPCounter[remoteIP].callsRemaining[rpcMethod]--;
	    }
	}

	var rpcProxy = http.request({host: settings.RPC.host, port: settings.RPC.port, method: request.method, headers: request.headers}, function(proxy_res)
	{
	    proxy_res.on("data", function(chunk)
	    {
		response.write(chunk, "binary");
	    });

	    proxy_res.on("end", function(chunk)
	    {
		response.end();
	    });

	    proxy_res.on("error", function(error)
	    {
		if(!connectionErrorMessageDisplayed)
		{
		    console.log("Error: cannot connect to twisterd.\nSee Troubleshooting section in README.md for instructions.");
		    connectionErrorMessageDisplayed=true;
		}
		response.send(502);
	    });

	    response.writeHead(proxy_res.statusCode, proxy_res.headers);
	});

	rpcProxy.write(request.rawBody, "binary");
	rpcProxy.end();
    });
});

if(settings.Server.enable_https)
{
    https.createServer(credentials, app).listen(settings.Server.https_port);
}

http.createServer(app).listen(settings.Server.http_port);

setInterval(function()
{
    for(method in maxCallsPerMinute)
    {
	callsRemaining[method] = maxCallsPerMinute[method];
	if(droppedCallsCounter[method]!==0)
	{
	    console.log("Dropped "+droppedCallsCounter[method]+" calls to "+method+" over the limit of "+maxCallsPerMinute[method]);
	    droppedCallsCounter[method] = 0;
	}
    };
    if(invalidRequestCounter!==0)
    {
	console.log("Received "+invalidRequestCounter+" invalid POST requests.");
	invalidRequestCounter = 0;
    }
    if(forbiddenCallCounter!==0)
    {
	console.log("Denied "+forbiddenCallCounter+" attempts to access forbidden API calls.");
	forbiddenCallCounter = 0;
    }

    for(ip in perIPCounter)
    {
	if(perIPCounter[ip].overLimit>=settings.LogAsAttackThreshold.callsOverLimits)
	{
	    console.log("IP "+ip+" tried to send "+perIPCounter[ip].overLimit+" calls more than the limits allow.");
	};
	if(perIPCounter[ip].invalidRequests>=settings.LogAsAttackThreshold.invalidRequests)
	{
	    console.log("IP "+ip+" sent "+perIPCounter[ip].invalidRequests+" invalid request that couldn't be parsed.");
	};
	if(perIPCounter[ip].forbiddenCalls>=settings.LogAsAttackThreshold.forbiddenCalls)
	{
	    console.log("IP "+ip+" tried to send "+perIPCounter[ip].forbiddenCalls+" calls to forbidden functions.");
	};
    }

    perIPCounter = {};
    connectionErrorMessageDisplayed = false;

}, 60000);
<commit_msg>Fix #4 - missing auth header<commit_after>var fs = require("fs");
var https = require("https");
var http = require("http");
var express = require("express");
var console = require("console");

var app = express();

try
{
    var settings = JSON.parse(fs.readFileSync("settings.json"));
}
catch(e)
{
    console.log("Error: Configuration file settings.json couldn't be parsed.\nSee Troubleshooting section in README.md for instructions.");
    process.exit(1);
}

if(settings.Server.enable_https)
{
    try
    {
	var privateKey  = fs.readFileSync(settings.Server.ssl_key_file).toString();
    }
    catch(e)
    {
	console.log("Error: unable to load SSL key. Please edit setting.json and put the correct path to your SSL private key file into \"ssl_key_file.\"");
	process.exit(1);
    }
    try
    {
	var certificate = fs.readFileSync(settings.Server.ssl_certificate_file).toString();
    }
    catch(e)
    {
	console.log("Error: unable to load SSL certificate. Please edit setting.json and put the correct path to your SSL certificate file into \"ssl_certificate_file.\"");
	process.exit(1);
    }
    var credentials = {key: privateKey, cert: certificate};
}

maxCallsPerMinute = {};
maxCallsPerMinutePerIP = {};
callsRemaining = {};
perIPCounter = {};
droppedCallsCounter = {};

var invalidRequestCounter = 0;
var forbiddenCallCounter = 0;
var connectionErrorMessageDisplayed = false;

var auth = "Basic " + new Buffer(settings.RPC.user + ":" + settings.RPC.password).toString("base64");

settings.CallLimits.forEach(function(x) {
    maxCallsPerMinute[x.name] = x.maxPerMinute;
    maxCallsPerMinutePerIP[x.name] = x.maxPerMinutePerIP;
    callsRemaining[x.name] = x.maxPerMinute;
    droppedCallsCounter[x.name] = 0;
});

CounterInstance = function()
{
    this.overLimit=0;
    this.invalidRequests=0;
    this.forbiddenCalls=0;
    this.callsRemaining={};
    for (x in maxCallsPerMinutePerIP)
    {
      if(maxCallsPerMinutePerIP[x]!==null)
	  this.callsRemaining[x]=maxCallsPerMinutePerIP[x];
    }
}

require("log-timestamp");

app.get("*", function(request, response)
{
    if(settings.Server.enable_https&&request.protocol=="http")
    {
	if(settings.Server.https_port==443)
	    secureUrl="https://"+request.host+request.path;
	else
	    secureUrl="https://"+request.host+":"+settings.Server.https_port+request.path;
	response.writeHead(302, {"Location": secureUrl});
	response.end();
	return;
    }

    request.headers.Authorization = auth;

    var webProxy = http.request({host: settings.RPC.host, port: settings.RPC.port, method: request.method, path: request.path, headers: request.headers}, function (proxy_res)
    {
	proxy_res.pipe(response, {end: true});
    });

    webProxy.on("error", function(error)
    {
	if(!connectionErrorMessageDisplayed)
	{
	    console.log("Error: cannot connect to twisterd.\nSee Troubleshooting section in README.md for instructions.");
	    connectionErrorMessageDisplayed=true;
	}
	response.send(502);
    });

    request.pipe(webProxy, {end: true});
});

app.post("/", function(request, response)
{
    request.rawBody = "";
    request.setEncoding("utf8");
    request.headers.Authorization = auth;

    request.addListener("data", function(chunk)
    {
        request.rawBody += chunk;
    });

    request.addListener("end", function()
    {
	var remoteIP = request.connection.remoteAddress;

	if(perIPCounter[remoteIP]===undefined)
	{
	    perIPCounter[remoteIP]=new CounterInstance();
	}
	try
	{
	    bodyJson=JSON.parse(request.rawBody);
	    rpcMethod=bodyJson.method;
	}
	catch(e)
	{
	    perIPCounter[remoteIP].invalidRequests++;
	    invalidRequestCounter++;
	    return;
	}
	if(maxCallsPerMinute[rpcMethod]===undefined)
	{
	    perIPCounter[remoteIP].forbiddenCalls++;
	    forbiddenCallCounter++;
	    return;
	}
	if(maxCallsPerMinute[rpcMethod]!==null)
	{
	    if(callsRemaining[rpcMethod]<1)
	    {
	        droppedCallsCounter[rpcMethod]++;
		return;
	    }
	    else
	    {
		callsRemaining[rpcMethod]--;
	    }
	}

	if(maxCallsPerMinutePerIP[rpcMethod]!==null)
	{
	    if(perIPCounter[remoteIP].callsRemaining[rpcMethod]<1)
	    {
		perIPCounter[remoteIP].overLimit++;
		return;
	    }
	    else
	    {
		perIPCounter[remoteIP].callsRemaining[rpcMethod]--;
	    }
	}

	var rpcProxy = http.request({host: settings.RPC.host, port: settings.RPC.port, method: request.method, headers: request.headers}, function(proxy_res)
	{
	    proxy_res.on("data", function(chunk)
	    {
		response.write(chunk, "binary");
	    });

	    proxy_res.on("end", function(chunk)
	    {
		response.end();
	    });

	    proxy_res.on("error", function(error)
	    {
		if(!connectionErrorMessageDisplayed)
		{
		    console.log("Error: cannot connect to twisterd.\nSee Troubleshooting section in README.md for instructions.");
		    connectionErrorMessageDisplayed=true;
		}
		response.send(502);
	    });

	    response.writeHead(proxy_res.statusCode, proxy_res.headers);
	});

	rpcProxy.write(request.rawBody, "binary");
	rpcProxy.end();
    });
});

if(settings.Server.enable_https)
{
    https.createServer(credentials, app).listen(settings.Server.https_port);
}

http.createServer(app).listen(settings.Server.http_port);

setInterval(function()
{
    for(method in maxCallsPerMinute)
    {
	callsRemaining[method] = maxCallsPerMinute[method];
	if(droppedCallsCounter[method]!==0)
	{
	    console.log("Dropped "+droppedCallsCounter[method]+" calls to "+method+" over the limit of "+maxCallsPerMinute[method]);
	    droppedCallsCounter[method] = 0;
	}
    };
    if(invalidRequestCounter!==0)
    {
	console.log("Received "+invalidRequestCounter+" invalid POST requests.");
	invalidRequestCounter = 0;
    }
    if(forbiddenCallCounter!==0)
    {
	console.log("Denied "+forbiddenCallCounter+" attempts to access forbidden API calls.");
	forbiddenCallCounter = 0;
    }

    for(ip in perIPCounter)
    {
	if(perIPCounter[ip].overLimit>=settings.LogAsAttackThreshold.callsOverLimits)
	{
	    console.log("IP "+ip+" tried to send "+perIPCounter[ip].overLimit+" calls more than the limits allow.");
	};
	if(perIPCounter[ip].invalidRequests>=settings.LogAsAttackThreshold.invalidRequests)
	{
	    console.log("IP "+ip+" sent "+perIPCounter[ip].invalidRequests+" invalid request that couldn't be parsed.");
	};
	if(perIPCounter[ip].forbiddenCalls>=settings.LogAsAttackThreshold.forbiddenCalls)
	{
	    console.log("IP "+ip+" tried to send "+perIPCounter[ip].forbiddenCalls+" calls to forbidden functions.");
	};
    }

    perIPCounter = {};
    connectionErrorMessageDisplayed = false;

}, 60000);
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2018 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

 foam.CLASS({
   package: 'foam.graphics',
   name: 'TreeGraph',
   extends: 'foam.graphics.CView',

   exports: [
     'as graph',
     'formatNode',
     'nodeHeight',
     'nodeWidth',
     'padding',
     'relationship'
   ],

   properties: [
     [ 'nodeWidth',  155 ],
     [ 'nodeHeight',  60 ],
     [ 'padding',     30 ],
     {
       name: 'data'
     },
     {
       name: 'relationship'
     },
     'root',
     {
       name: 'formatNode',
       value: function() {}
     }
   ],

   methods: [
     function init() {
       this.SUPER();

       if ( this.data ) {
         this.root = this.Node.create({x:500, y: 50, data: this.data});
         this.children.push(this.root);
         this.doLayout();
       }
     },

     function initCView() {
       this.SUPER();

       // List for 'click' events to expand/collapse Nodes.
       this.canvas.on('click', function(e) {
         var x = e.clientX+this.nodeWidth/2, y = e.clientY;
         var c = this.root.findFirstChildAt(x, y);
         console.log('click', x,y, c);
         if ( ! c ) return;
         c.expanded = ! c.expanded;
         if ( ! c.expanded ) {
           for ( var i = 0 ; i < c.childNodes.length ; i++ ) {
             c.childNodes[i].y = this.nodeHeight;
             c.childNodes[i].x = 0;
           }
           c.maxLeft = c.maxRight = 0;
         }
         this.doLayout();
       }.bind(this));
     },

     function doLayout() {
       if ( this.root ) { this.root.layout(); this.root.doLayout(); }
       this.invalidate();
     }
   ],

   classes: [
     {
       name: 'Node',
       extends: 'foam.graphics.Box',

       requires: [
         'foam.graphics.Box',
         'foam.graphics.CView',
         'foam.graphics.Label',
         'foam.graphics.Line'
       ],

       imports: [
         'formatNode',
         'graph',
         'nodeHeight',
         'nodeWidth',
         'padding',
         'parentNode?',
         'relationship'
       ],
       exports: [ 'as parentNode' ],

       properties: [
         'data',
         { name: 'height', factory: function() { return this.nodeHeight; } },
         { name: 'width',  factory: function() { return this.nodeWidth; } },
         [ 'border', 'gray' ],
         {
           name: 'childNodes',
           factory: function() { return []; }
         },
         [ 'left',  0 ],
         [ 'right', 0 ],
         [ 'maxLeft',  0 ],
         [ 'maxRight', 0 ],
         {
           class: 'Boolean',
           name: 'expanded',
           value: true
         },
         [ 'color', 'white' ]
       ],

       methods: [
         function initCView() {
           this.SUPER();

           this.formatNode();

           if ( this.relationship ) {
             var data = this.data.clone(this.__subContext__);

             try {
               data[this.relationship.forwardName].select(function(data) {
                 this.addChildNode({data: data});
                }.bind(this));
              } catch(x) {}
              this.graph.doLayout();
            }
         },

         function paint(x) {
           if ( ! this.parentNode || this.parentNode.expanded ) this.SUPER(x);
         },

         function paintSelf(x) {
           x.translate(-this.width/2, 0);
           this.SUPER(x);
           x.translate(this.width/2, 0);

           this.paintConnectors(x);
         },

         function paintConnectors(x) {
           function line(x1, y1, x2, y2) {
             x.beginPath();
             x.moveTo(x1, y1);
             x.lineTo(x2, y2);
             x.stroke();
           }

           x.lineWidth   = 0.5; //this.borderWidth;
           x.strokeStyle = this.border;

           // Paint lines to childNodes
           if ( this.expanded && this.childNodes.length ) {
             var h = this.childNodes[0].y*3/4;
             line(0, this.height, 0, h);
             var l = this.childNodes.length;
             for ( var i = 0 ; i < l ; i++ ) {
               var c = this.childNodes[i];
               if ( i == 0 || i == l-1 ) {
                line(0, h, c.x, h);
               }
               line(c.x, h, c.x, c.y);
             }
           }

           x.lineWidth = this.borderWidth;
           // Paint expand/collapse arrow
           if ( this.childNodes.length ) {
             var d = this.expanded ? 5 : -5;
             var y = this.height - 8;
             line(-5, y, 0, y+d);
             line(0, y+d, 5, y);
           }
         },

         function addChildNode(args) {
           var node = this.cls_.create(args, this);
           this.add(node);
           this.childNodes.push(node);
           this.graph.doLayout();
           return this;
         },

         function layout() {
           this.left = this.right = 0;

           if ( ! this.expanded ) return false;

           var moved      = false;
           var childNodes = this.childNodes;
           var l          = childNodes.length;

           // Layout children
           for ( var i = 0 ; i < l ; i++ ) {
             var c = childNodes[i];
             if ( c.y < this.height*2 ) { moved = true; c.y += 2; }

             if ( c.layout() ) moved = true;
             this.left  = Math.min(this.left, c.x);
             this.right = Math.max(this.right, c.x);
           }

           // Move children away from each other if required
           var m = l/2;
           for ( var i = 0 ; i < l-1 ; i++ ) {
             var n1 = childNodes[i];
             var n2 = childNodes[i+1];
             var d  = n2.x-n1.x+n2.left-n1.right;
             if ( d != this.width + this.padding ) {
               moved = true;
               var w = Math.min(Math.abs(this.width+this.padding-d), 10);
               if ( d > this.width + this.padding ) w = -w;
               if ( i+1 == m ) {
                 n1.x -= w/2;
                 n2.x += w/2;
               } else if ( i < Math.floor(m) ) {
                 n1.x -= w;
               } else {
                 n2.x += w;
               }
             }
           }
           // TODO/BUG: I'm not sure why this is necessary, but without, center
           // nodes are a few pixels off.
           if ( l%2 == 1 ) childNodes[Math.floor(m)].x = 0;

           // Calculate maxLeft and maxRight
           this.maxLeft = this.maxRight = 0;
           for ( var i = 0 ; i < l ; i++ ) {
             var c = childNodes[i];
             this.maxLeft  = Math.min(c.x + c.maxLeft, this.maxLeft);
             this.maxRight = Math.max(c.x + c.maxRight, this.maxRight);
           }

           return moved;
         }
       ],

       listeners: [
         {
           name: 'doLayout',
           isFramed: true,
           documentation: 'Animate layout until positions stabilize',
           code: function() {
             var needsLayout = false;

             // Scale and translate the view to fit in the available window
             var gw = this.graph.width-100;
             var w = this.maxRight - this.maxLeft + 50;
             if ( w > gw ) {
               var scaleX = Math.min(1, gw / w);
               if ( scaleX != this.scaleX ) needsLayout = 1;
               /*this.scaleY = */this.scaleX = Math.min(1, (19*this.scaleX+scaleX)/20);
             }

             var x = (-this.maxLeft+25)/w * gw + 50;
             if ( x != this.x ) {
               this.x = (19*this.x + x)/20;
               needsLayout = true;
             }

             if ( this.layout() || needsLayout ) {
               this.doLayout();
             }
             this.graph.invalidate();
           }
         }
       ]
     }
   ]
 });
<commit_msg>Fix for TreeGraph using wrong x and y coordinates.<commit_after>/**
 * @license
 * Copyright 2018 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

 foam.CLASS({
   package: 'foam.graphics',
   name: 'TreeGraph',
   extends: 'foam.graphics.CView',

   exports: [
     'as graph',
     'formatNode',
     'nodeHeight',
     'nodeWidth',
     'padding',
     'relationship'
   ],

   properties: [
     [ 'nodeWidth',  155 ],
     [ 'nodeHeight',  60 ],
     [ 'padding',     30 ],
     {
       name: 'data'
     },
     {
       name: 'relationship'
     },
     'root',
     {
       name: 'formatNode',
       value: function() {}
     }
   ],

   methods: [
     function init() {
       this.SUPER();

       if ( this.data ) {
         this.root = this.Node.create({x:500, y: 50, data: this.data});
         this.children.push(this.root);
         this.doLayout();
       }
     },

     function initCView() {
       this.SUPER();

       // List for 'click' events to expand/collapse Nodes.
       this.canvas.on('click', function(e) {
         var x = e.layerX+this.nodeWidth/2, y = e.layerY;
         var c = this.root.findFirstChildAt(x, y);
         if ( ! c ) return;
         c.expanded = ! c.expanded;
         if ( ! c.expanded ) {
           for ( var i = 0 ; i < c.childNodes.length ; i++ ) {
             c.childNodes[i].y = this.nodeHeight;
             c.childNodes[i].x = 0;
           }
           c.maxLeft = c.maxRight = 0;
         }
         this.doLayout();
       }.bind(this));
     },

     function doLayout() {
       if ( this.root ) { this.root.layout(); this.root.doLayout(); }
       this.invalidate();
     }
   ],

   classes: [
     {
       name: 'Node',
       extends: 'foam.graphics.Box',

       requires: [
         'foam.graphics.Box',
         'foam.graphics.CView',
         'foam.graphics.Label',
         'foam.graphics.Line'
       ],

       imports: [
         'formatNode',
         'graph',
         'nodeHeight',
         'nodeWidth',
         'padding',
         'parentNode?',
         'relationship'
       ],
       exports: [ 'as parentNode' ],

       properties: [
         'data',
         { name: 'height', factory: function() { return this.nodeHeight; } },
         { name: 'width',  factory: function() { return this.nodeWidth; } },
         [ 'border', 'gray' ],
         {
           name: 'childNodes',
           factory: function() { return []; }
         },
         [ 'left',  0 ],
         [ 'right', 0 ],
         [ 'maxLeft',  0 ],
         [ 'maxRight', 0 ],
         {
           class: 'Boolean',
           name: 'expanded',
           value: true
         },
         [ 'color', 'white' ]
       ],

       methods: [
         function initCView() {
           this.SUPER();

           this.formatNode();

           if ( this.relationship ) {
             var data = this.data.clone(this.__subContext__);

             try {
               data[this.relationship.forwardName].select(function(data) {
                 this.addChildNode({data: data});
                }.bind(this));
              } catch(x) {}
              this.graph.doLayout();
            }
         },

         function paint(x) {
           if ( ! this.parentNode || this.parentNode.expanded ) this.SUPER(x);
         },

         function paintSelf(x) {
           x.translate(-this.width/2, 0);
           this.SUPER(x);
           x.translate(this.width/2, 0);

           this.paintConnectors(x);
         },

         function paintConnectors(x) {
           function line(x1, y1, x2, y2) {
             x.beginPath();
             x.moveTo(x1, y1);
             x.lineTo(x2, y2);
             x.stroke();
           }

           x.lineWidth   = 0.5; //this.borderWidth;
           x.strokeStyle = this.border;

           // Paint lines to childNodes
           if ( this.expanded && this.childNodes.length ) {
             var h = this.childNodes[0].y*3/4;
             line(0, this.height, 0, h);
             var l = this.childNodes.length;
             for ( var i = 0 ; i < l ; i++ ) {
               var c = this.childNodes[i];
               if ( i == 0 || i == l-1 ) {
                line(0, h, c.x, h);
               }
               line(c.x, h, c.x, c.y);
             }
           }

           x.lineWidth = this.borderWidth;
           // Paint expand/collapse arrow
           if ( this.childNodes.length ) {
             var d = this.expanded ? 5 : -5;
             var y = this.height - 8;
             line(-5, y, 0, y+d);
             line(0, y+d, 5, y);
           }
         },

         function addChildNode(args) {
           var node = this.cls_.create(args, this);
           this.add(node);
           this.childNodes.push(node);
           this.graph.doLayout();
           return this;
         },

         function layout() {
           this.left = this.right = 0;

           if ( ! this.expanded ) return false;

           var moved      = false;
           var childNodes = this.childNodes;
           var l          = childNodes.length;

           // Layout children
           for ( var i = 0 ; i < l ; i++ ) {
             var c = childNodes[i];
             if ( c.y < this.height*2 ) { moved = true; c.y += 2; }

             if ( c.layout() ) moved = true;
             this.left  = Math.min(this.left, c.x);
             this.right = Math.max(this.right, c.x);
           }

           // Move children away from each other if required
           var m = l/2;
           for ( var i = 0 ; i < l-1 ; i++ ) {
             var n1 = childNodes[i];
             var n2 = childNodes[i+1];
             var d  = n2.x-n1.x+n2.left-n1.right;
             if ( d != this.width + this.padding ) {
               moved = true;
               var w = Math.min(Math.abs(this.width+this.padding-d), 10);
               if ( d > this.width + this.padding ) w = -w;
               if ( i+1 == m ) {
                 n1.x -= w/2;
                 n2.x += w/2;
               } else if ( i < Math.floor(m) ) {
                 n1.x -= w;
               } else {
                 n2.x += w;
               }
             }
           }
           // TODO/BUG: I'm not sure why this is necessary, but without, center
           // nodes are a few pixels off.
           if ( l%2 == 1 ) childNodes[Math.floor(m)].x = 0;

           // Calculate maxLeft and maxRight
           this.maxLeft = this.maxRight = 0;
           for ( var i = 0 ; i < l ; i++ ) {
             var c = childNodes[i];
             this.maxLeft  = Math.min(c.x + c.maxLeft, this.maxLeft);
             this.maxRight = Math.max(c.x + c.maxRight, this.maxRight);
           }

           return moved;
         }
       ],

       listeners: [
         {
           name: 'doLayout',
           isFramed: true,
           documentation: 'Animate layout until positions stabilize',
           code: function() {
             var needsLayout = false;

             // Scale and translate the view to fit in the available window
             var gw = this.graph.width-100;
             var w = this.maxRight - this.maxLeft + 50;
             if ( w > gw ) {
               var scaleX = Math.min(1, gw / w);
               if ( scaleX != this.scaleX ) needsLayout = 1;
               this.scaleX = Math.min(1, (19*this.scaleX+scaleX)/20);
             }

             var x = (-this.maxLeft+25)/w * gw + 50;
             if ( x != this.x ) {
               this.x = (19*this.x + x)/20;
               needsLayout = true;
             }
             if ( this.layout() || needsLayout ) {
               this.doLayout();
             }
             this.graph.invalidate();
           }
         }
       ]
     }
   ]
 });
<|endoftext|>


<commit_before>'use strict';

/*global $:false, angular:false, window:false, ace:false, esper:false, document:false, _:false */

var myAppModule = angular.module('MyApp', ['ui.ace', 'ui.bootstrap']);

myAppModule.controller('main', function($scope, $timeout, $http, $q, $location) {
	var params = $location.search();

	$scope.brekpoints = [];
	if ( params.gist ) {
		$scope.code = '// Loading gist...';
		$http({
			url: 'https://api.github.com/gists/' + params.gist
		}).then(function(cb) {
			var result = cb.data;
			var name = Object.keys(result.files).pop();
			$scope.code = result.files[name].content;
		});
	} else {
		$scope.code = window.localStorage.code || document.getElementById('exampleCode').innerText;
	}

	$scope.opts = {forceVar: true, decorateLuaObjects: true, luaCalls: true, luaOperators: true,
		encloseWithFunctions: false, useStrict: false, noMutliReturnSquish: false};

	$scope.fix = function(c) { return c.reverse(); };

	$scope.runMode = function() {
		return typeof $scope.frames !== 'undefined';
	};

	$scope.aceLoaded = function(ai) {
		$scope.ace = ai;
		window.a = ai;
		$scope.Range = ace.require('ace/range').Range;

		ai.on('guttermousedown', function(e) {

			var target = e.domEvent.target;
			console.log(target, e);
			if (target.className.indexOf('ace_gutter-cell') == -1) return;
			if (!ai.isFocused()) return;
			if (e.clientX > 25 + target.getBoundingClientRect().left) return;

			var row = e.getDocumentPosition().row;
			var bps = e.editor.session.getBreakpoints();
			if ( !bps[row] ) {
				e.editor.session.setBreakpoint(row);
			} else {
				e.editor.session.clearBreakpoint(row);
			}
			$scope.brekpoints = e.editor.session.getBreakpoints();
			e.stop();
		});

		ai.focus();
	};

	$scope.speed = params.speed || 5;
	var timer = function timer() {
		if ( $scope.speed === 0 ) return $timeout(timer, 1000);
		if ( $scope.esper && $scope.auto ) $scope.step();
		var delay = 1000 / Math.pow(10,($scope.speed - 3) / 3);
		if ( $scope.speed == 10 ) delay = 0;
		$timeout(timer, delay);
	};
	$timeout(timer, 100);

	$scope.names = function(o) {
		return Object.getOwnPropertyNames(o).join(', ');
	};

	$scope.isASTOpen = function(ast) {
		if (!ast) return false;
		return ast._open !== false;
	};

	$scope.tgl = function(ast) {
		if ( ast._open === false ) delete ast._open;
		else ast._open = false;
	};

	$scope.getChildNodes = function(ast) {
		var out = [];
		for (var p in ast) {
			let n = ast[p];
			if ( p === 'parent' ) continue;
			if ( p === 'loc' ) continue;
			if ( p === 'type' ) continue;
			if ( p === 'nodeID' ) continue;
			if ( n === null ) continue;
			if ( angular.isArray(n) ) {
				for ( var i in n ) {
					if ( typeof n[i].type === 'string' ) out.push(n[i]);
				}
				continue;
			}
			if ( typeof n.type !== 'string' ) {
				continue;
			}
			if ( n.type === 'Identifier' || n.type === 'Literal' ) continue;
			out.push(n);
		}
		return out;
	};

	$scope.compile = function() {
		var epr = new esper.Engine();
		epr.addGlobalFx('fetch', function(url) {
			return esper.FutureValue.make($http({
				url: url,
				method: 'GET',
				transformResponse: null
			}).then(function(data) {
				return epr.realm.fromNative(data.data);
			}, function(e) {
				return $q.reject(epr.realm.fromNative(new Error('Fetch failed.')));
			}));
		});

		epr.addGlobalFx('fork', function(yourFX) {
			var parent = $scope.esper;
			var fx = esper.Value.getBookmark(yourFX);
			var e = parent.evaluator;
			var E = e.constructor;
			var newThread = new E(e.realm, e.ast, parent.globalScope);
			var scope = parent.globalScope.createChild();
			let c = fx.call(esper.Value.undef, [], scope);
			newThread.pushFrame({generator: c, type: 'program', scope: scope, ast: null});
			var eng = new esper.Engine();
			eng.evaluator = newThread;
			eng.generator = newThread.generator();
			eng.realm = e.realm;
			$scope.engines.push(eng);
		});

		try {
			epr.load($scope.code);
		} catch ( e ) {
			$scope.error = e.stack || e.toString();
			return;
		}

		$scope.output = '';
		epr.realm.print = function() {
			$scope.output += Array.prototype.join.call(arguments,' ') + '\n';
		};
		delete $scope.error;
		$scope.esper = epr;
		$scope.engines = [epr];
		$scope.ast = $scope.esper.evaluator.ast;
		window.engine = epr;
	};

	$scope.start = function() {
		$scope.compile();
		$scope.auto = true;
	};

	$scope.clear = function() {
		angular.forEach($scope.marker, function(marker) {
			$scope.ace.session.removeMarker(marker);
		});
		$scope.marker = [];
	};

	$scope.step = function() {
		if ( !$scope.esper ) return;
		$scope.clear();
		for ( var i in $scope.engines ) {
			var eng = $scope.engines[i];
			if ( stepOne(eng) && eng == $scope.esper ) {
				delete $scope.esper;
				delete $scope.gen;
			}
		}

	};

	function stepOne(engine) {
		var result;
		try {
			result = engine.step();
		} catch ( e ) {
			console.log(e);
			$scope.error = e.stack || e.toString();
			result = e;
			//delete $scope.esper;
			//delete $scope.gen;
		}

		if ( result ) {
			return true;
		} else {
			var frames = engine.evaluator.frames;
			var ast;
			for ( var i = 0; i < frames.length; ++i ) {
				if ( frames[i].ast ) {
					ast = frames[i].ast;
					break;
				}
			}

			function readScope(scope) {
				var vars = {};
				var props = scope.object.properties;
				var varz = Object.getOwnPropertyNames(props);
				for ( var z in varz ) {
					var vname = varz[z];
					var val = props[vname].value;
					vars[vname] = (val && val.debugString) ? val.debugString : val;
				}
				return vars;
			}
			var lines = [];
			for ( i = 0; i < frames.length; ++i ) {
				var f = frames[i];
				var o = {
					id: (frames.length - i),
					type: f.type,
					vars: {}
				};
				if ( f.ast ) {
					o.node = f.ast.type;
					o.name = f.ast.srcName;
					o.loc = f.ast.loc.start.line + ':' + f.ast.loc.start.column;
				}
				if ( f.value ) o.value = f.value.debugString;
				if ( f.scope ) {
					o.vars = readScope(f.scope);
					o.vars['this'] = f.scope.thiz && JSON.stringify(f.scope.thiz.toString());
				}
				lines.push(o);
			}

			if ( ast ) {
				var range = ast.loc;
				var ln = range.start.line - 1;
				if ( $scope.brekpoints[ln] && $scope.skipBP != ln ) {
					$scope.skipBP = ln;
					$scope.auto = false;
				} else if ( $scope.skipBP != ln ) {
					delete $scope.skipBP;
				}
				var rr = new $scope.Range(range.start.line - 1, range.start.column, range.end.line - 1, range.end.column);
				$scope.marker.push($scope.ace.session.addMarker(rr,'executing', 'text'));
				//$scope.ace.session.selection.setRange(rr);
				//$scope.output = JSON.stringify(frames,null,'  ');
			}

			$scope.frames = lines;
		}

	}

	$scope.pause = function() { $scope.auto = false; };
	$scope.play = function() { $scope.auto = true; };

	$scope.stop = function() {
		$scope.clear();
		delete $scope.esper;
		delete $scope.gen;
		delete $scope.frames;
		$scope.auto = false;
	};

	$scope.aceChanged = _.debounce(function() {
		window.localStorage.code = $scope.code;
		$scope.clear();
		$scope.compile();
	},200);

	$scope.$watch('opts', function() {
		$scope.stop();
	}, true);
});
<commit_msg>Allow forked function to terminate without running the main program.<commit_after>'use strict';

/*global $:false, angular:false, window:false, ace:false, esper:false, document:false, _:false */

var myAppModule = angular.module('MyApp', ['ui.ace', 'ui.bootstrap']);

myAppModule.controller('main', function($scope, $timeout, $http, $q, $location) {
	var params = $location.search();

	$scope.brekpoints = [];
	if ( params.gist ) {
		$scope.code = '// Loading gist...';
		$http({
			url: 'https://api.github.com/gists/' + params.gist
		}).then(function(cb) {
			var result = cb.data;
			var name = Object.keys(result.files).pop();
			$scope.code = result.files[name].content;
		});
	} else {
		$scope.code = window.localStorage.code || document.getElementById('exampleCode').innerText;
	}

	$scope.opts = {forceVar: true, decorateLuaObjects: true, luaCalls: true, luaOperators: true,
		encloseWithFunctions: false, useStrict: false, noMutliReturnSquish: false};

	$scope.fix = function(c) { return c.reverse(); };

	$scope.runMode = function() {
		return typeof $scope.frames !== 'undefined';
	};

	$scope.aceLoaded = function(ai) {
		$scope.ace = ai;
		window.a = ai;
		$scope.Range = ace.require('ace/range').Range;

		ai.on('guttermousedown', function(e) {

			var target = e.domEvent.target;
			console.log(target, e);
			if (target.className.indexOf('ace_gutter-cell') == -1) return;
			if (!ai.isFocused()) return;
			if (e.clientX > 25 + target.getBoundingClientRect().left) return;

			var row = e.getDocumentPosition().row;
			var bps = e.editor.session.getBreakpoints();
			if ( !bps[row] ) {
				e.editor.session.setBreakpoint(row);
			} else {
				e.editor.session.clearBreakpoint(row);
			}
			$scope.brekpoints = e.editor.session.getBreakpoints();
			e.stop();
		});

		ai.focus();
	};

	$scope.speed = params.speed || 5;
	var timer = function timer() {
		if ( $scope.speed === 0 ) return $timeout(timer, 1000);
		if ( $scope.esper && $scope.auto ) $scope.step();
		var delay = 1000 / Math.pow(10,($scope.speed - 3) / 3);
		if ( $scope.speed == 10 ) delay = 0;
		$timeout(timer, delay);
	};
	$timeout(timer, 100);

	$scope.names = function(o) {
		return Object.getOwnPropertyNames(o).join(', ');
	};

	$scope.isASTOpen = function(ast) {
		if (!ast) return false;
		return ast._open !== false;
	};

	$scope.tgl = function(ast) {
		if ( ast._open === false ) delete ast._open;
		else ast._open = false;
	};

	$scope.getChildNodes = function(ast) {
		var out = [];
		for (var p in ast) {
			let n = ast[p];
			if ( p === 'parent' ) continue;
			if ( p === 'loc' ) continue;
			if ( p === 'type' ) continue;
			if ( p === 'nodeID' ) continue;
			if ( n === null ) continue;
			if ( angular.isArray(n) ) {
				for ( var i in n ) {
					if ( typeof n[i].type === 'string' ) out.push(n[i]);
				}
				continue;
			}
			if ( typeof n.type !== 'string' ) {
				continue;
			}
			if ( n.type === 'Identifier' || n.type === 'Literal' ) continue;
			out.push(n);
		}
		return out;
	};

	$scope.compile = function() {
		var epr = new esper.Engine();
		epr.addGlobalFx('fetch', function(url) {
			return esper.FutureValue.make($http({
				url: url,
				method: 'GET',
				transformResponse: null
			}).then(function(data) {
				return epr.realm.fromNative(data.data);
			}, function(e) {
				return $q.reject(epr.realm.fromNative(new Error('Fetch failed.')));
			}));
		});

		epr.addGlobalFx('fork', function(yourFX) {
			var parent = $scope.esper;
			var fx = esper.Value.getBookmark(yourFX);
			var e = parent.evaluator;
			var E = e.constructor;
			var newThread = new E(e.realm, e.ast, parent.globalScope);
			var scope = parent.globalScope.createChild();
			let c = fx.call(esper.Value.undef, [], scope);
			newThread.frames = [];
			newThread.pushFrame({generator: c, type: 'program', scope: scope, ast: null});
			var eng = new esper.Engine();
			eng.evaluator = newThread;
			eng.generator = newThread.generator();
			eng.realm = e.realm;
			$scope.engines.push(eng);
		});

		try {
			epr.load($scope.code);
		} catch ( e ) {
			$scope.error = e.stack || e.toString();
			return;
		}

		$scope.output = '';
		epr.realm.print = function() {
			$scope.output += Array.prototype.join.call(arguments,' ') + '\n';
		};
		delete $scope.error;
		$scope.esper = epr;
		$scope.engines = [epr];
		$scope.ast = $scope.esper.evaluator.ast;
		window.engine = epr;
	};

	$scope.start = function() {
		$scope.compile();
		$scope.auto = true;
	};

	$scope.clear = function() {
		angular.forEach($scope.marker, function(marker) {
			$scope.ace.session.removeMarker(marker);
		});
		$scope.marker = [];
	};

	$scope.step = function() {
		if ( !$scope.esper ) return;
		$scope.clear();
		var terminated = [];
		for ( var i in $scope.engines ) {
			var eng = $scope.engines[i];
			if ( stepOne(eng) ) {
				if ( eng == $scope.esper ) {
					delete $scope.esper;
					delete $scope.gen;
				}
				terminated.push(eng);
			}
		}
		var stillRunning = [];
		angular.forEach($scope.engines, function(e) {
			if ( terminated.indexOf(e) === -1 ) stillRunning.push(e);
		});

		$scope.engines = stillRunning;

	};

	function stepOne(engine) {
		var result;
		try {
			result = engine.step();
		} catch ( e ) {
			console.log(e);
			$scope.error = e.stack || e.toString();
			result = e;
			//delete $scope.esper;
			//delete $scope.gen;
		}

		if ( result ) {
			return true;
		} else {
			var frames = engine.evaluator.frames;
			var ast;
			for ( var i = 0; i < frames.length; ++i ) {
				if ( frames[i].ast ) {
					ast = frames[i].ast;
					break;
				}
			}

			function readScope(scope) {
				var vars = {};
				var props = scope.object.properties;
				var varz = Object.getOwnPropertyNames(props);
				for ( var z in varz ) {
					var vname = varz[z];
					var val = props[vname].value;
					vars[vname] = (val && val.debugString) ? val.debugString : val;
				}
				return vars;
			}
			var lines = [];
			for ( i = 0; i < frames.length; ++i ) {
				var f = frames[i];
				var o = {
					id: (frames.length - i),
					type: f.type,
					vars: {}
				};
				if ( f.ast ) {
					o.node = f.ast.type;
					o.name = f.ast.srcName;
					o.loc = f.ast.loc.start.line + ':' + f.ast.loc.start.column;
				}
				if ( f.value ) o.value = f.value.debugString;
				if ( f.scope ) {
					o.vars = readScope(f.scope);
					o.vars['this'] = f.scope.thiz && JSON.stringify(f.scope.thiz.toString());
				}
				lines.push(o);
			}

			if ( ast ) {
				var range = ast.loc;
				var ln = range.start.line - 1;
				if ( $scope.brekpoints[ln] && $scope.skipBP != ln ) {
					$scope.skipBP = ln;
					$scope.auto = false;
				} else if ( $scope.skipBP != ln ) {
					delete $scope.skipBP;
				}
				var rr = new $scope.Range(range.start.line - 1, range.start.column, range.end.line - 1, range.end.column);
				$scope.marker.push($scope.ace.session.addMarker(rr,'executing', 'text'));
				//$scope.ace.session.selection.setRange(rr);
				//$scope.output = JSON.stringify(frames,null,'  ');
			}

			$scope.frames = lines;
		}

	}

	$scope.pause = function() { $scope.auto = false; };
	$scope.play = function() { $scope.auto = true; };

	$scope.stop = function() {
		$scope.clear();
		delete $scope.esper;
		delete $scope.gen;
		delete $scope.frames;
		$scope.auto = false;
	};

	$scope.aceChanged = _.debounce(function() {
		window.localStorage.code = $scope.code;
		$scope.clear();
		$scope.compile();
	},200);

	$scope.$watch('opts', function() {
		$scope.stop();
	}, true);
});
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Joyent, Inc.  All rights reserved.
 *
 * Amon Master controller for '/checks/...' endpoints.
 */

var assert = require('assert');
var restify = require('restify');
var amon_common = require('amon-common');

var utils = require('./utils');
var Check = require('./model/check');

//--- globals

var Constants = amon_common.Constants;
var Messages = amon_common.Messages;

var _message = Messages.message;

var HttpCodes = restify.HttpCodes;
var RestCodes = restify.RestCodes;
var log = restify.log;

//---- controllers

module.exports = {

  create: function(req, res, next) {
    assert.ok(req._config);
    assert.ok(req._config.plugins);

    log.debug('checks.create entered: params=%o', req.params);

    var customer = req.params.customer;
    var zone = req.params.zone;
    var urn = req.params.urn;
    var config = req.params.config;

    if (!customer) {
      utils.sendMissingArgument(res, 'customer');
      return next();
    }
    if (!zone) {
      utils.sendMissingArgument(res, 'zone');
      return next();
    }
    if (!urn) {
      utils.sendMissingArgument(res, 'urn');
      return next();
    }
    if (!config) {
      utils.sendMissingArgument(res, 'config');
      return next();
    }
    var plugin = req._config.plugins[urn];
    if (!plugin) {
      utils.sendInvalidUrn(res, urn);
      return next();
    }

    log.debug('checks.create: found plugin %o', plugin);

    try {
      plugin.validateConfig(config);
    } catch (e) {
      utils.sendInvalidConfig(res, e.message);
      return next();
    }

    var check = new Check({
      riak: req._riak,
      customer: req.params.customer,
      zone: req.params.zone,
      urn: urn,
      config: config
    });

    check.save(function(err) {
      if (err) {
        log.warn('Error saving new check to riak: ' + err);
        res.send(500);
      } else {
        var data = check.serialize();
        log.debug('checks.create returning %d, object=%o', 201,
                  data);
        res.send(201, data);
      }
      return next();
    });
  },

  list: function(req, res, next) {
    log.debug('checks.list entered: params=%o', req.params);

    var check = new Check({
      riak: req._riak
    });
    // Bug here in that it's possible for an idiot to pass in a zone not owned
    // by the customer. That's a problem for future amon developers...
    if (req.params.zone) {
      check.findByZone(req.params.zone, function(err, checks) {
        if (err) {
          log.warn('Error finding checks in riak: ' + err);
          res.send(500);
        } else {
          log.debug('checks.list returning %d, obj=%o', 200, checks);
          res.send(200, checks);
        }
        return next();
      });
    } else if (req.params.customer) {
      check.findByCustomer(req.params.customer, function(err, checks) {
        if (err) {
          log.warn('Error finding checks in riak: ' + err);
          res.send(500);
        } else {
          log.debug('checks.list returning %d, obj=%o', 200, checks);
          res.send(200, checks);
        }
        return next();
      });
    } else {
      utils.sendMissingArgument(res, 'zone');
      return next();
    }

  },

  get: function(req, res, next) {
    log.debug('checks.get entered: params=%o', req.params);

    var check = new Check({
      riak: req._riak
    });

    check.load(req.uriParams.id, function(err, loaded) {
      if (err) {
        log.warn('Error loading check from riak: ' + err);
        res.send(500);
      } else {
        if (!loaded) {
          _sendNoCheck(res, req.uriParams.id);
        } else {
          var obj = check.serialize();
          log.debug('checks.get returning %d, obj=%o', 200, obj);
          res.send(200, obj);
        }
      }
      return next();
    });
  },

  del: function(req, res, next) {
    log.debug('checks.del entered: params=%o', req.params);

    var check = new Check({
      riak: req._riak
    });

    check.load(req.uriParams.id, function(err, loaded) {
      if (err) {
        log.warn('Error loading check from riak: ' + err);
        res.send(500);
        return next();
      }

      if (!loaded) {
        _sendNoCheck(res, req.uriParams.id);
        return next();
      }

      return check.destroy(req.uriParams.id, function(err) {
        if (err) {
          log.warn('Error destroying check from riak: ' + err);
          res.send(500);
        } else {
          log.debug('checks.del returning %d', 204);
          res.send(204);
        }
        return next();
      });
    });
  }

};
<commit_msg>these methods are in utils.js now<commit_after>/*
 * Copyright 2011 Joyent, Inc.  All rights reserved.
 *
 * Amon Master controller for '/checks/...' endpoints.
 */

var assert = require('assert');
var restify = require('restify');
var amon_common = require('amon-common');

var utils = require('./utils');
var Check = require('./model/check');

//--- globals

var Constants = amon_common.Constants;
var Messages = amon_common.Messages;

var _message = Messages.message;

var HttpCodes = restify.HttpCodes;
var RestCodes = restify.RestCodes;
var log = restify.log;

//---- controllers

module.exports = {

  create: function(req, res, next) {
    assert.ok(req._config);
    assert.ok(req._config.plugins);

    log.debug('checks.create entered: params=%o', req.params);

    var customer = req.params.customer;
    var zone = req.params.zone;
    var urn = req.params.urn;
    var config = req.params.config;

    if (!customer) {
      utils.sendMissingArgument(res, 'customer');
      return next();
    }
    if (!zone) {
      utils.sendMissingArgument(res, 'zone');
      return next();
    }
    if (!urn) {
      utils.sendMissingArgument(res, 'urn');
      return next();
    }
    if (!config) {
      utils.sendMissingArgument(res, 'config');
      return next();
    }
    var plugin = req._config.plugins[urn];
    if (!plugin) {
      utils.sendInvalidUrn(res, urn);
      return next();
    }

    log.debug('checks.create: found plugin %o', plugin);

    try {
      plugin.validateConfig(config);
    } catch (e) {
      utils.sendInvalidConfig(res, e.message);
      return next();
    }

    var check = new Check({
      riak: req._riak,
      customer: req.params.customer,
      zone: req.params.zone,
      urn: urn,
      config: config
    });

    check.save(function(err) {
      if (err) {
        log.warn('Error saving new check to riak: ' + err);
        res.send(500);
      } else {
        var data = check.serialize();
        log.debug('checks.create returning %d, object=%o', 201,
                  data);
        res.send(201, data);
      }
      return next();
    });
  },

  list: function(req, res, next) {
    log.debug('checks.list entered: params=%o', req.params);

    var check = new Check({
      riak: req._riak
    });
    // Bug here in that it's possible for an idiot to pass in a zone not owned
    // by the customer. That's a problem for future amon developers...
    if (req.params.zone) {
      check.findByZone(req.params.zone, function(err, checks) {
        if (err) {
          log.warn('Error finding checks in riak: ' + err);
          res.send(500);
        } else {
          log.debug('checks.list returning %d, obj=%o', 200, checks);
          res.send(200, checks);
        }
        return next();
      });
    } else if (req.params.customer) {
      check.findByCustomer(req.params.customer, function(err, checks) {
        if (err) {
          log.warn('Error finding checks in riak: ' + err);
          res.send(500);
        } else {
          log.debug('checks.list returning %d, obj=%o', 200, checks);
          res.send(200, checks);
        }
        return next();
      });
    } else {
      utils.sendMissingArgument(res, 'zone');
      return next();
    }

  },

  get: function(req, res, next) {
    log.debug('checks.get entered: params=%o', req.params);

    var check = new Check({
      riak: req._riak
    });

    check.load(req.uriParams.id, function(err, loaded) {
      if (err) {
        log.warn('Error loading check from riak: ' + err);
        res.send(500);
      } else {
        if (!loaded) {
          utils.sendNoCheck(res, req.uriParams.id);
        } else {
          var obj = check.serialize();
          log.debug('checks.get returning %d, obj=%o', 200, obj);
          res.send(200, obj);
        }
      }
      return next();
    });
  },

  del: function(req, res, next) {
    log.debug('checks.del entered: params=%o', req.params);

    var check = new Check({
      riak: req._riak
    });

    check.load(req.uriParams.id, function(err, loaded) {
      if (err) {
        log.warn('Error loading check from riak: ' + err);
        res.send(500);
        return next();
      }

      if (!loaded) {
        utils.sendNoCheck(res, req.uriParams.id);
        return next();
      }

      return check.destroy(req.uriParams.id, function(err) {
        if (err) {
          log.warn('Error destroying check from riak: ' + err);
          res.send(500);
        } else {
          log.debug('checks.del returning %d', 204);
          res.send(204);
        }
        return next();
      });
    });
  }

};
<|endoftext|>