<commit_before>$(document).ready(function() {
    $("input#Item_Expiration").datepicker();

    $("select#Item_ItemType").change(function(event) {
        var url = getExtendedPropertyUrl;

        $.getJSON(url + '/' + $(this).val(), {},
                    function(result) {

                        var length = result.length;

                        if (length > 0) {
                            $.each(result, function(index, item) {

                                var name = item.Name.replace(/ /g, "");

                                // create the label
                                var label = $("<label>").attr("for", "item." + name).html(item.Name);
                                var textBox = $("<input>").attr("id", "ExtendedProperties[" + index + "]_value")
                                                          .attr("name", "ExtendedProperties[" + index + "].value")
                                                          .attr("type", "text");
                                // create hidden field to store the extended property id
                                var hidden = $("<input>").attr("type", "hidden")
                                                         .attr("id", "ExtendedProperties[" + index + "]_propertyId")
                                                         .attr("name", "ExtendedProperties[" + index + "].propertyId")
                                                         .val(item.Id);

                                if (item.QuestionType.Name == "Date") {
                                    textBox.datepicker();
                                }

                                var p = $("<p>").append(label).append(textBox).append(hidden);
                                $("div#ExtendedProperties").append(p);
                            });
                        }
                    });
    });

    $("img#tagAddButton").click(function(event) {
        var input = $("<input>").attr("id", "tags").attr("name", "tags").val($("input#tagInput").val());
        input.attr("type", "text");
        input.css("cursor", "pointer");
        input.click(function(event) { $(this).remove(); });
        $("div#tagContainer").append(input);

        // blank the input
        $("input#tagInput").val("");
    });

    $("input#tags").click(function(event) {
        $(this).remove();
    });

    $("a.FormSubmit").click(function(event) {
        //$(this).parents("form#RemoveForm").submit();

        $(this).parent().submit();
    });

    $("textarea#BodyText").tinymce({
        script_url: scriptUrl,
        // General options
        theme: "advanced",
        plugins: "safari,style,save,searchreplace,print,contextmenu,paste",

        // Theme options
        theme_advanced_buttons1: "save,print,|,bold,italic,underline,|,styleselect,formatselect,fontselect,fontsizeselect",
        theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,undo,redo,|,bullist,numlist",
        theme_advanced_buttons3: "",
        theme_advanced_toolbar_location: "top",
        theme_advanced_toolbar_align: "left",
        theme_advanced_statusbar_location: "bottom",
        theme_advanced_resizing: false,

        // dimensions stuff
        height: "400",

        // Example content CSS (should be your site CSS)
        //content_css: "css/Main.css",

        // Drop lists for link/image/media/template dialogs
        template_external_list_url: "js/template_list.js",
        external_link_list_url: "js/link_list.js",
        external_image_list_url: "js/image_list.js",
        media_external_list_url: "js/media_list.js",

        save_onsavecallback: function() {
            var textbox = $(this);
            var token = $($("input:hidden[name='__RequestVerificationToken']")[0]).val();

            $.post(saveTemplateUrl, { id: id, text: textbox.val(), __RequestVerificationToken: token }
                , function(result) { if (result) { alert("template saved."); } else { alert("template was unable to save."); } });
        }
    });

    $("textarea#Item_Description").tinymce({
        script_url: scriptUrl,
        // General options
        theme: "advanced",
        plugins: "safari,style,save,searchreplace,print,contextmenu,paste",

        // Theme options
        theme_advanced_buttons1: "print,|,bold,italic,underline,|,styleselect,formatselect,fontselect,fontsizeselect",
        theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,undo,redo",
        theme_advanced_buttons3: "",
        theme_advanced_toolbar_location: "top",
        theme_advanced_toolbar_align: "left",
        theme_advanced_statusbar_location: "bottom",
        theme_advanced_resizing: false,

        // dimensions stuff
        height: "400",

        // Example content CSS (should be your site CSS)
        //content_css: "css/Main.css",

        // Drop lists for link/image/media/template dialogs
        template_external_list_url: "js/template_list.js",
        external_link_list_url: "js/link_list.js",
        external_image_list_url: "js/image_list.js",
        media_external_list_url: "js/media_list.js"
    });

    $("textarea#Item_CheckPaymentInstructions").tinymce({
        script_url: scriptUrl,
        // General options
        theme: "advanced",
        plugins: "safari,style,save,searchreplace,print,contextmenu,paste",

        // Theme options
        theme_advanced_buttons1: "print,|,bold,italic,underline,|,styleselect,formatselect,fontselect,fontsizeselect",
        theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,undo,redo",
        theme_advanced_buttons3: "",
        theme_advanced_toolbar_location: "top",
        theme_advanced_toolbar_align: "left",
        theme_advanced_statusbar_location: "bottom",
        theme_advanced_resizing: false,

        // dimensions stuff
        height: "225",

        // Example content CSS (should be your site CSS)
        //content_css: "css/Main.css",

        // Drop lists for link/image/media/template dialogs
        template_external_list_url: "js/template_list.js",
        external_link_list_url: "js/link_list.js",
        external_image_list_url: "js/image_list.js",
        media_external_list_url: "js/media_list.js"
    });
});<commit_msg>Add date watermarks to item extended properties when the ItemType is changed.<commit_after>$(document).ready(function() {
    $("input#Item_Expiration").datepicker();

    $("select#Item_ItemType").change(function(event) {
        var url = getExtendedPropertyUrl;
        $.getJSON(url + '/' + $(this).val(), {},
                    function(result) {

                        var length = result.length;

                        if (length > 0) {
                            $.each(result, function(index, item) {

                                var name = item.Name.replace(/ /g, "");

                                // create the label
                                var label = $("<label>").attr("for", "item." + name).html(item.Name);
                                var textBox = $("<input>").attr("id", "ExtendedProperties[" + index + "]_value")
                                                          .attr("name", "ExtendedProperties[" + index + "].value")
                                                          .attr("type", "text");
                                // create hidden field to store the extended property id
                                var hidden = $("<input>").attr("type", "hidden")
                                                         .attr("id", "ExtendedProperties[" + index + "]_propertyId")
                                                         .attr("name", "ExtendedProperties[" + index + "].propertyId")
                                                         .val(item.Id);

                                if (item.QuestionType.Name == "Date") {
                                    textBox.datepicker().watermark("mm/dd/yyyy", { className: "watermark" });
                                }

                                var p = $("<p>").append(label).append(textBox).append(hidden);
                                $("div#ExtendedProperties").append(p);
                            });
                        }
                    });
    });

    $("img#tagAddButton").click(function(event) {
        var input = $("<input>").attr("id", "tags").attr("name", "tags").val($("input#tagInput").val());
        input.attr("type", "text");
        input.css("cursor", "pointer");
        input.click(function(event) { $(this).remove(); });
        $("div#tagContainer").append(input);

        // blank the input
        $("input#tagInput").val("");
    });

    $("input#tags").click(function(event) {
        $(this).remove();
    });

    $("a.FormSubmit").click(function(event) {
        //$(this).parents("form#RemoveForm").submit();

        $(this).parent().submit();
    });

    $("textarea#BodyText").tinymce({
        script_url: scriptUrl,
        // General options
        theme: "advanced",
        plugins: "safari,style,save,searchreplace,print,contextmenu,paste",

        // Theme options
        theme_advanced_buttons1: "save,print,|,bold,italic,underline,|,styleselect,formatselect,fontselect,fontsizeselect",
        theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,undo,redo,|,bullist,numlist",
        theme_advanced_buttons3: "",
        theme_advanced_toolbar_location: "top",
        theme_advanced_toolbar_align: "left",
        theme_advanced_statusbar_location: "bottom",
        theme_advanced_resizing: false,

        // dimensions stuff
        height: "400",

        // Example content CSS (should be your site CSS)
        //content_css: "css/Main.css",

        // Drop lists for link/image/media/template dialogs
        template_external_list_url: "js/template_list.js",
        external_link_list_url: "js/link_list.js",
        external_image_list_url: "js/image_list.js",
        media_external_list_url: "js/media_list.js",

        save_onsavecallback: function() {
            var textbox = $(this);
            var token = $($("input:hidden[name='__RequestVerificationToken']")[0]).val();

            $.post(saveTemplateUrl, { id: id, text: textbox.val(), __RequestVerificationToken: token }
                , function(result) { if (result) { alert("template saved."); } else { alert("template was unable to save."); } });
        }
    });

    $("textarea#Item_Description").tinymce({
        script_url: scriptUrl,
        // General options
        theme: "advanced",
        plugins: "safari,style,save,searchreplace,print,contextmenu,paste",

        // Theme options
        theme_advanced_buttons1: "print,|,bold,italic,underline,|,styleselect,formatselect,fontselect,fontsizeselect",
        theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,undo,redo",
        theme_advanced_buttons3: "",
        theme_advanced_toolbar_location: "top",
        theme_advanced_toolbar_align: "left",
        theme_advanced_statusbar_location: "bottom",
        theme_advanced_resizing: false,

        // dimensions stuff
        height: "400",

        // Example content CSS (should be your site CSS)
        //content_css: "css/Main.css",

        // Drop lists for link/image/media/template dialogs
        template_external_list_url: "js/template_list.js",
        external_link_list_url: "js/link_list.js",
        external_image_list_url: "js/image_list.js",
        media_external_list_url: "js/media_list.js"
    });

    $("textarea#Item_CheckPaymentInstructions").tinymce({
        script_url: scriptUrl,
        // General options
        theme: "advanced",
        plugins: "safari,style,save,searchreplace,print,contextmenu,paste",

        // Theme options
        theme_advanced_buttons1: "print,|,bold,italic,underline,|,styleselect,formatselect,fontselect,fontsizeselect",
        theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,undo,redo",
        theme_advanced_buttons3: "",
        theme_advanced_toolbar_location: "top",
        theme_advanced_toolbar_align: "left",
        theme_advanced_statusbar_location: "bottom",
        theme_advanced_resizing: false,

        // dimensions stuff
        height: "225",

        // Example content CSS (should be your site CSS)
        //content_css: "css/Main.css",

        // Drop lists for link/image/media/template dialogs
        template_external_list_url: "js/template_list.js",
        external_link_list_url: "js/link_list.js",
        external_image_list_url: "js/image_list.js",
        media_external_list_url: "js/media_list.js"
    });
});<|endoftext|>


<commit_before>import React from "react"
import { connect } from "react-redux"
import { withRouter } from "react-router";
import * as limitOrderActions from "../../actions/limitOrderActions"
import * as common from "../../utils/common"
import { getTranslate } from 'react-localize-redux'
import * as converter from "../../utils/converter"
import BLOCKCHAIN_INFO from "../../../../env";
import * as constants from "../../services/constants"

@connect((store, props) => {
  const account = store.account.account
  const translate = getTranslate(store.locale)
  const tokens = store.tokens.tokens
  const limitOrder = store.limitOrder
  const ethereum = store.connection.ethereum

  return {
    translate, limitOrder, tokens, account, ethereum,
    global: store.global

  }
})

class LimitOrderFee extends React.Component {
  componentDidMount = () =>{
    this.fetchFee()
    this.intervalFetchFee = setInterval(() => {
      this.fetchFee(false);
    }, 10000)
  }

  componentWillUnmount = () => {
    clearInterval(this.intervalFetchFee)
  }

  fetchFee = (shouldLoading = true) => {
    if (this.props.account !== false){
      var userAddr = this.props.account.address
      var src = this.props.tokens[this.props.limitOrder.sourceTokenSymbol].address
      var dest = this.props.tokens[this.props.limitOrder.destTokenSymbol].address
      var srcAmount = this.props.limitOrder.sourceAmount
      var destAmount = this.props.limitOrder.destAmount
      this.props.dispatch(limitOrderActions.fetchFee(userAddr, src, dest, srcAmount, destAmount, shouldLoading))
    } else {
      this.props.dispatch(limitOrderActions.fetchFeeComplete(constants.LIMIT_ORDER_CONFIG.maxFee, constants.LIMIT_ORDER_CONFIG.maxFee, 0))
    }
  }

  redirectToSwap = () => {
    this.props.history.push("/swap/eth-knc");
  }

  render() {
    var sourceTokenSymbol = this.props.limitOrder.sourceTokenSymbol === BLOCKCHAIN_INFO.wrapETHToken ? constants.WETH_SUBSTITUTE_NAME : this.props.limitOrder.sourceTokenSymbol

    const orderFee = converter.multiplyOfTwoNumber(this.props.limitOrder.sourceAmount, converter.divOfTwoNumber(this.props.limitOrder.orderFee, 100));
    const orderFeeAfterDiscount = converter.multiplyOfTwoNumber(this.props.limitOrder.sourceAmount, converter.divOfTwoNumber(this.props.limitOrder.orderFeeAfterDiscount, 100));
    const sourceAmountAfterFee = converter.subOfTwoNumber(this.props.limitOrder.sourceAmount, orderFeeAfterDiscount);
    const discountFee = converter.subOfTwoNumber(orderFee, orderFeeAfterDiscount);
    const orderFeeDiscountPercentage = converter.multiplyOfTwoNumber(converter.divOfTwoNumber(discountFee, orderFee), 100);

    let orderFeeText = ;
    let orderDiscountFeeText = `0 ${sourceTokenSymbol} (${orderFeeDiscountPercentage.toFixed(0) > 0 ? '~' : ''}${orderFeeDiscountPercentage.toFixed(0)}% of Fee)`;
    let orderNetFeeText = ;

    if (!this.props.limitOrder.isFetchingFee) {
      orderFeeText = {converter.formatNumber(orderFee, 5, '')} {sourceTokenSymbol} ({this.props.limitOrder.orderFee}% of {converter.displayNumberWithDot(this.props.limitOrder.sourceAmount)} {sourceTokenSymbol})
      orderNetFeeText = {converter.formatNumber(orderFeeAfterDiscount, 5, '')} {sourceTokenSymbol};

      if (this.props.limitOrder.sourceAmount && orderFeeDiscountPercentage) {
        orderDiscountFeeText = - {converter.formatNumber(discountFee, 5, '')} {sourceTokenSymbol} (~{orderFeeDiscountPercentage}% of Fee)
      }
    }

    return (

{this.props.translate("limit_order.fee") || "Fee"}:

{orderFeeText}

            {this.props.translate("more_info") || "More Info"}

{this.props.translate("discount") || "Discount"}:

{orderDiscountFeeText}

{this.props.translate("net_fee") || "Net Fee"}:

{orderNetFeeText}

        {this.props.limitOrder.sourceAmount > 0 &&

            {this.props.translate("limit_order.fee_info", {
              sourceTokenSymbol: this.props.limitOrder.sourceTokenSymbol,
              destTokenSymbol: this.props.limitOrder.destTokenSymbol,
              sourceAmount: converter.formatNumber(sourceAmountAfterFee, 5, '')
            }) || `Upon execution, fee is deducted from source token and remaining ${converter.formatNumber(sourceAmountAfterFee, 5, '')} ${this.props.limitOrder.sourceTokenSymbol} is converted to ${this.props.limitOrder.destTokenSymbol}`}

        }

    )
  }
}

export default withRouter(LimitOrderFee);
<commit_msg>fix fee<commit_after>import React from "react"
import { connect } from "react-redux"
import { withRouter } from "react-router";
import * as limitOrderActions from "../../actions/limitOrderActions"
import * as common from "../../utils/common"
import { getTranslate } from 'react-localize-redux'
import * as converter from "../../utils/converter"
import BLOCKCHAIN_INFO from "../../../../env";
import * as constants from "../../services/constants"

@connect((store, props) => {
  const account = store.account.account
  const translate = getTranslate(store.locale)
  const tokens = store.tokens.tokens
  const limitOrder = store.limitOrder
  const ethereum = store.connection.ethereum

  return {
    translate, limitOrder, tokens, account, ethereum,
    global: store.global

  }
})

class LimitOrderFee extends React.Component {
  componentDidMount = () =>{
    this.fetchFee()
    this.intervalFetchFee = setInterval(() => {
      this.fetchFee(false);
    }, 10000)
  }

  componentWillUnmount = () => {
    clearInterval(this.intervalFetchFee)
  }

  fetchFee = (shouldLoading = true) => {
    if (this.props.account !== false){
      var userAddr = this.props.account.address
      var src = this.props.tokens[this.props.limitOrder.sourceTokenSymbol].address
      var dest = this.props.tokens[this.props.limitOrder.destTokenSymbol].address
      var srcAmount = this.props.limitOrder.sourceAmount
      var destAmount = this.props.limitOrder.destAmount
      this.props.dispatch(limitOrderActions.fetchFee(userAddr, src, dest, srcAmount, destAmount, shouldLoading))
    } else {
      this.props.dispatch(limitOrderActions.fetchFeeComplete(constants.LIMIT_ORDER_CONFIG.maxFee, constants.LIMIT_ORDER_CONFIG.maxFee, 0))
    }
  }

  redirectToSwap = () => {
    this.props.history.push("/swap/eth-knc");
  }

  render() {
    var sourceTokenSymbol = this.props.limitOrder.sourceTokenSymbol === BLOCKCHAIN_INFO.wrapETHToken ? constants.WETH_SUBSTITUTE_NAME : this.props.limitOrder.sourceTokenSymbol

    const orderFee = converter.multiplyOfTwoNumber(this.props.limitOrder.sourceAmount, converter.divOfTwoNumber(this.props.limitOrder.orderFee, 100));
    const orderFeeAfterDiscount = converter.multiplyOfTwoNumber(this.props.limitOrder.sourceAmount, converter.divOfTwoNumber(this.props.limitOrder.orderFeeAfterDiscount, 100));
    const sourceAmountAfterFee = converter.subOfTwoNumber(this.props.limitOrder.sourceAmount, orderFeeAfterDiscount);
    const discountFee = converter.subOfTwoNumber(orderFee, orderFeeAfterDiscount);
    var orderFeeDiscountPercentage = converter.multiplyOfTwoNumber(converter.divOfTwoNumber(discountFee, orderFee), 100);

    let orderFeeText = ;
    let orderDiscountFeeText = `0 ${sourceTokenSymbol} (${converter.compareTwoNumber(orderFeeDiscountPercentage, 0) == 1 ? '~' : ''}${converter.formatNumber(orderFeeDiscountPercentage, 1)}% of Fee)`;
    let orderNetFeeText = ;

    if (!this.props.limitOrder.isFetchingFee) {
      orderFeeText = {converter.formatNumber(orderFee, 5, '')} {sourceTokenSymbol} ({this.props.limitOrder.orderFee}% of {converter.displayNumberWithDot(this.props.limitOrder.sourceAmount)} {sourceTokenSymbol})
      orderNetFeeText = {converter.formatNumber(orderFeeAfterDiscount, 5, '')} {sourceTokenSymbol};

      if (this.props.limitOrder.sourceAmount && orderFeeDiscountPercentage) {
        orderDiscountFeeText = - {converter.formatNumber(discountFee, 5, '')} {sourceTokenSymbol} (~{converter.formatNumber(orderFeeDiscountPercentage, 1)}% of Fee)
      }
    }

    return (

{this.props.translate("limit_order.fee") || "Fee"}:

{orderFeeText}

            {this.props.translate("more_info") || "More Info"}

{this.props.translate("discount") || "Discount"}:

{orderDiscountFeeText}

{this.props.translate("net_fee") || "Net Fee"}:

{orderNetFeeText}

        {this.props.limitOrder.sourceAmount > 0 &&

            {this.props.translate("limit_order.fee_info", {
              sourceTokenSymbol: this.props.limitOrder.sourceTokenSymbol,
              destTokenSymbol: this.props.limitOrder.destTokenSymbol,
              sourceAmount: converter.formatNumber(sourceAmountAfterFee, 5, '')
            }) || `Upon execution, fee is deducted from source token and remaining ${converter.formatNumber(sourceAmountAfterFee, 5, '')} ${this.props.limitOrder.sourceTokenSymbol} is converted to ${this.props.limitOrder.destTokenSymbol}`}

        }

    )
  }
}

export default withRouter(LimitOrderFee);
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');

var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var Modal = require('matrix-react-sdk/lib/Modal');
var sdk = require('matrix-react-sdk')
var dis = require('matrix-react-sdk/lib/dispatcher');

module.exports = React.createClass({
    displayName: 'RoomDirectory',

    getInitialState: function() {
        return {
            publicRooms: [],
            roomAlias: '',
            loading: true,
        }
    },

    componentDidMount: function() {
        var self = this;
        MatrixClientPeg.get().publicRooms(function (err, data) {
            if (err) {
                self.setState({ loading: false });
                console.error("Failed to get publicRooms: %s", JSON.stringify(err));
                var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
                Modal.createDialog(ErrorDialog, {
                    title: "Failed to get public room list",
                    description: err.message
                });
            }
            else {
                self.setState({
                    publicRooms: data.chunk,
                    loading: false,
                });
                self.forceUpdate();
            }
        });
    },

    showRoom: function(roomId) {
        dis.dispatch({
            action: 'view_room',
            room_id: roomId
        });
    },

    getRows: function(filter) {
        if (!this.state.publicRooms) return [];

        var rooms = this.state.publicRooms.filter(function(a) {
            // FIXME: if incrementally typing, keep narrowing down the search set
            // incrementally rather than starting over each time.
            return (a.aliases[0].toLowerCase().search(filter.toLowerCase()) >= 0 && a.num_joined_members > 0);
        }).sort(function(a,b) {
            return a.num_joined_members - b.num_joined_members;
        });
        var rows = [];
        var self = this;
        var guestRead, guestJoin, perms;
        for (var i = 0; i < rooms.length; i++) {
            var name = rooms[i].name || rooms[i].aliases[0];
            guestRead = null;
            guestJoin = null;

            if (rooms[i].world_readable) {
                guestRead = (
                    [world readable]
                );
                    //
            }
            if (rooms[i].guest_can_join) {
                guestJoin = (
                    [guests allowed]
                );
                    //
            }

            perms = null;
            if (guestRead || guestJoin) {
                perms =
{guestRead} {guestJoin}
;
            }

            //
            rows.unshift(

                        { name }
                        { rooms[i].aliases[0] }
                        { rooms[i].num_joined_members }

                        {perms} { rooms[i].topic }

            );
        }
        return rows;
    },

    onKeyUp: function(ev) {
        this.forceUpdate();
        this.setState({ roomAlias : this.refs.roomAlias.value })
        if (ev.key == "Enter") {
            this.showRoom(this.refs.roomAlias.value);
        }
    },

    render: function() {
        if (this.state.loading) {
            var Loader = sdk.getComponent("elements.Spinner");
            return (

                    <Loader />

            );
        }

        var RoomHeader = sdk.getComponent('rooms.RoomHeader');
        return (

                <RoomHeader simpleHeader="Public Rooms" />

                    <input ref="roomAlias" placeholder="Join a room (e.g. #foo:domain.com)" className="mx_RoomDirectory_input" size="64" onKeyUp={ this.onKeyUp }/>

Room	Alias	Members

                            { this.getRows(this.state.roomAlias) }

        );
    }
});

<commit_msg>tart up room directory<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');

var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var ContentRepo = require("matrix-js-sdk").ContentRepo;
var Modal = require('matrix-react-sdk/lib/Modal');
var sdk = require('matrix-react-sdk')
var dis = require('matrix-react-sdk/lib/dispatcher');

var linkify = require('linkifyjs');
var linkifyElement = require('linkifyjs/element');
var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix');

linkifyMatrix(linkify);

module.exports = React.createClass({
    displayName: 'RoomDirectory',

    getInitialState: function() {
        return {
            publicRooms: [],
            roomAlias: '',
            loading: true,
        }
    },

    componentDidMount: function() {
        var self = this;
        MatrixClientPeg.get().publicRooms(function (err, data) {
            if (err) {
                self.setState({ loading: false });
                console.error("Failed to get publicRooms: %s", JSON.stringify(err));
                var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
                Modal.createDialog(ErrorDialog, {
                    title: "Failed to get public room list",
                    description: err.message
                });
            }
            else {
                self.setState({
                    publicRooms: data.chunk,
                    loading: false,
                });
                self.forceUpdate();
            }
        });

        //linkifyElement(this.refs.directory_table, linkifyMatrix.options);
    },

    showRoom: function(roomId) {
        dis.dispatch({
            action: 'view_room',
            room_id: roomId
        });
    },

    getRows: function(filter) {
        var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');

        if (!this.state.publicRooms) return [];

        var rooms = this.state.publicRooms.filter(function(a) {
            // FIXME: if incrementally typing, keep narrowing down the search set
            // incrementally rather than starting over each time.
            return (a.aliases[0].toLowerCase().search(filter.toLowerCase()) >= 0 && a.num_joined_members > 0);
        }).sort(function(a,b) {
            return a.num_joined_members - b.num_joined_members;
        });
        var rows = [];
        var self = this;
        var guestRead, guestJoin, perms;
        for (var i = 0; i < rooms.length; i++) {
            var name = rooms[i].name || rooms[i].aliases[0];
            guestRead = null;
            guestJoin = null;

            if (rooms[i].world_readable) {
                guestRead = (

World readable

                );
            }
            if (rooms[i].guest_can_join) {
                guestJoin = (

Guests can join

                );
            }

            perms = null;
            if (guestRead || guestJoin) {
                perms =
{guestRead} {guestJoin}
;
            }

            rows.unshift(

                        <BaseAvatar width={24} height={24} resizeMethod='crop'
                            name={ name } idName={ name }
                            url={ ContentRepo.getHttpUriForMxc(
                                    MatrixClientPeg.get().getHomeserverUrl(),
                                    rooms[i].avatar_url, 24, 24, "crop") } />

{ name }

                        { perms }

{ rooms[i].topic }

{ rooms[i].aliases[0] }

                        { rooms[i].num_joined_members }

            );
        }
        return rows;
    },

    onKeyUp: function(ev) {
        this.forceUpdate();
        this.setState({ roomAlias : this.refs.roomAlias.value })
        if (ev.key == "Enter") {
            this.showRoom(this.refs.roomAlias.value);
        }
    },

    render: function() {
        if (this.state.loading) {
            var Loader = sdk.getComponent("elements.Spinner");
            return (

                    <Loader />

            );
        }

        var RoomHeader = sdk.getComponent('rooms.RoomHeader');
        return (

                <RoomHeader simpleHeader="Directory" />

                    <input ref="roomAlias" placeholder="Join a room (e.g. #foo:domain.com)" className="mx_RoomDirectory_input" size="64" onKeyUp={ this.onKeyUp }/>

                                { this.getRows(this.state.roomAlias) }

        );
    }
});

<|endoftext|>


<commit_before>var fs = require('fs')
  , express = module.exports = require('express')
  , path = require('path')
  , hogan = require('hogan.js')
  , klass = global.klass = require('klass')
  , v = global.v = require('valentine')
  , router = require('./router')
  , argv = module.exports.argv = require('optimist').argv
  , minifyViews = process.env.minify || false
  , paths = {
      SERVICES: 'services'
    , HELPERS: 'helpers'
    , MODELS: 'models'
    , CONTROLLERS: 'controllers'
  }
  , filenameSuffixes = {
      SERVICES: 'Service'
    , HELPERS: 'Helper'
    , MODELS: 'Model'
    , CONTROLLERS: 'Controller'
  }

var minify = function () {
  var r = /(<script[^>]*>[\s\S]+?<\/script>)/
    , scr = /^<script([^>]*)>([\s\S]+?)<\/script>/
    , white = /\s+/g
    , closeTags = />\s+</g
    , jsp = require('uglify-js').parser
    , pro = require('uglify-js').uglify
    , uglify = function (src) {
        try {
          var ast = jsp.parse(src)
          ast = pro.ast_squeeze(ast)
          return pro.gen_code(ast)
        }
        catch (ex) {
          return src
        }
      }
  return function (doc) {
    if (!minifyViews) return doc
    return doc.trim().replace(/ +/g, ' ').split(r).map(function (p, i, m) {
      return (m = p.match(scr)) ? '<script' + m[1] + '>' + uglify(m[2]) + '</script>' : p.replace(white, ' ')
    }).join('').replace(closeTags, '><')
  }
}()

function isDirectory(p) {
  try {
    return fs.statSync(p).isDirectory()
  }
  catch (ex) {
    return false
  }
}

module.exports.createApp = function (baseDir, configuration, options) {
  configuration = configuration || {}
  options = options || {}

  var appDir = path.join(baseDir, '/app')
    , fileCache = {}
    , objCache = {}
    , pathCache = {}
    , updateCaches = v(paths).each(function (key, val) {
        fileCache[val] = {}
        objCache[val] = {}
        pathCache[val] = {}
      })
    , partialCache = {}
    , appDirs = [appDir].concat(v(function () {
        var dir = appDir + '/modules'
        return path.existsSync(dir) ? fs.readdirSync(dir) : []
      }()).map(function (dir) {
        return appDir + '/modules/' + dir
      }))
    , app = express.createServer()
    , loadFile = function (subdir, name, p) {
        if (typeof(fileCache[subdir][name]) !== 'undefined') return fileCache[subdir][name]
        var pathname = name.replace(/\./g, '/')
        var dir = v.find((p ? [p] : appDirs), function (dir) {
          var filename = dir + '/' + subdir + '/' + pathname + '.js'
          if (!path.existsSync(filename)) return false
          fileCache[subdir][name] = require(filename)(app, (configuration[subdir] && configuration[subdir][name] ? configuration[subdir][name] : {}))
          pathCache[subdir][name] = dir === appDir ? [appDir] : [dir, appDir]
          return true
        })
        if (!dir) throw new Error('Unable to find ' + subdir + '/' + pathname)

        return fileCache[subdir][name]
      }
    , loadClass = function (subdir, name, localName, definitionOnly) {
        if (definitionOnly) return loadFile(subdir, name)
        if (!objCache[subdir][name]) {
          var File = loadFile(subdir, name)
          objCache[subdir][name] = new File(localName, pathCache[subdir][name])
          objCache[subdir][name]._paths = pathCache[subdir][name]

          if (subdir === paths.MODELS) app.emit('createModel', localName, objCache[subdir][name])
          else if (subdir === paths.SERVICES) app.emit('createService', localName, objCache[subdir][name])
          else if (subdir === paths.CONTROLLERS) app.emit('createController', localName, objCache[subdir][name])
          //not emitting an event for helpers here as we never actually instantiate a helper
        }
        return objCache[subdir][name]
      }
    , mountPublicDir = function (dir) {
      var directory = dir + '/public'
      path.existsSync(directory) && app.use(express.static(directory))
    }

  app.set('base_dir', appDir)
  app.set('public', appDir + '/public')
  v(appDirs).each(mountPublicDir)

  app.controllers = {
    Base: require('./BaseController')(app)
  }

  app.addModulePath = function (dir) {
    appDirs.push(dir)
    mountPublicDir(dir)
  }

  app.getModulePaths = function () {
    return appDirs
  }

  app.mount = function () {
    var router = require('./router')
      , self = this

    v.each(appDirs, function (dir) {
      var filename = dir + '/config/routes.js'
      if (!path.existsSync(filename)) return
      router.init(self, require(filename)(self))
    })
    // static directory server

    router.init(this, {
      root: [['get', /(.+)/, 'Static']]
    })
  }

  app.prefetch = function (options) {
    var self = this

    v(paths).each(function (key, type) {
      v.each(appDirs, function (dir) {
        var d = dir + '/' + type
        if (!isDirectory(d)) return
        v.each(fs.readdirSync(d), function (file) {
          if (isDirectory(d + "/" + file)) return
          if (file.charAt(0) == '.') return
          if (file.substr(file.length - 3) === '.js') file = file.substr(0, file.length - 3)
          loadFile(type, file, dir)
        })
      })
    })
  }

  /**
   * Finds all partial templates relative to the provided view directory, stopping once the root
   * directory has been reached.
   *
   * All templates are added from the /partials/ folder within the current view directory.  We then
   * move to the parent directory and add any partials from it's /partials/ folder that don't conflict
   * with ones already added. We then move to the next parent directory and so on until we reach the
   * application root.
   *
   * This allows views to use common templates, and be able to override sub-templates.
   *
   * Example: consider the following directory structure:
   *   app/
   *       views/
   *           partials/
   *               user-details.html  - contains {{> user-link}})
   *               user-link.html
   *           search/
   *               results.html - contains {{> user-details}}
   *               partials/
   *                   user-link.html
   *           post/
   *               post.html  - contains {{> user-details}}
   *
   * The partials for app/views/search will contain:
   *   app/views/search/partial/user-link.html
   *   app/views/partial/user-details.html
   *
   * The partials for app/views/post will only contain app/views/partials/%
   *
   *
   * TODO: This uses synchronous filesystem APIs. It should either be performed at start up
   * for all controllers or else switched to use async APIs.
   */
  app.getPartials = function (viewDir) {
    var rootDir = app.set('base_dir')
    var viewSuffix = '.' + app.set('view engine')

    if (!partialCache[viewDir]) {

      if (path.relative(rootDir, viewDir).indexOf('../') != -1) {
        throw new Error('View directories must live beneath the application root.')
      }

      var partials = {}
      while (viewDir != rootDir) {
        var partialDir = path.resolve(viewDir, 'partials')
        try {
          fs.readdirSync(partialDir).forEach(function (file) {
            // Ignore hidden files and files that don't have the right extension.
            if (file.charAt(0) == '.') return
            if (file.substr(-viewSuffix.length) != viewSuffix) return

            // Remove the suffix, such that /partials/something.html can be used as {{> something}}
            var partialName = file.substr(0, file.length - viewSuffix.length)

            // If the map already contains this partial it means it has already been specified higher
            // up the view hierarchy.
            if (!partials[partialName]) {
              var partialFilename = path.resolve(partialDir, file)
              try {
                var partialContent = fs.readFileSync(partialFilename, 'utf8')
                partials[partialName] = hogan.compile(minify(partialContent))
              } catch (e) {
                console.log('Unable to compile partial', partialFilename, e)
              }
            }
          })
        } catch (e) {
          // Only log errors if they are not a "no such file or directory" error, since we expect
          // those to happen. (Saves us an fs.statSync.)
          if (e.code != 'ENOENT') console.log('Unable to read partials directory', partialDir, e)
        }
        viewDir = path.resolve(viewDir, '../')
      }
      partialCache[viewDir] = partials
    }

    // Note: This does more work than is necessary, since common parents of views will
    // be hit once for each view. If this turns out to be problematic we can cache at
    // intermediate folders as well.

    return partialCache[viewDir]
  }

  /**
   * Get a service instance or class
   *
   * @param {String} name the name of the service
   * @param {Boolean} definitionOnly whether to just grab the class or to grab an actual
   *     instance
   * @return {Object} a service class or instance
   */
  app.getService = function (name, definitionOnly) {
    return loadClass(paths.SERVICES, name + filenameSuffixes.SERVICES, name, definitionOnly)
  }

  /**
   * Get a controller instance or class
   *
   * @param {String} name the name of the controller
   * @param {Boolean} definitionOnly whether to just grab the class or to grab an actual
   *     instance
   * @return {Object} a controller class or instance
   */
  app.getController = function (name, definitionOnly) {
    if (app.controllers[name]) {
      return definitionOnly ? app.controllers[name] : new app.controllers[name](name, [])
    }
    else {
      return loadClass(paths.CONTROLLERS, name + filenameSuffixes.CONTROLLERS, name, definitionOnly)
    }
  }

  /**
   * Get a model instance or class
   *
   * @param {String} name the name of the model
   * @param {Boolean} definitionOnly whether to just grab the class or to grab an actual
   *     instance
   * @return {Object} a model class or instance
   */
  app.getModel = function (name, definitionOnly) {
    return loadClass(paths.MODELS, name + filenameSuffixes.MODELS, name, definitionOnly)
  }

  /**
   * Get a helper
   *
   * @param {String} name of the helper
   * @return {Object} a helper instance
   */
  app.getHelper = function (name) {
    return loadFile(paths.HELPERS, name + filenameSuffixes.HELPERS)
  }

  /**
   * Override the existing cached version of a service
   *
   * @param {String} name the name of the service
   * @param {Object} instance the service instance
   */
  app.setService = function (name, instance) {
    objCache[paths.SERVICES][name + filenameSuffixes.SERVICES] = instance
  }

  /**
   * Override the existing cached version of a controller
   *
   * @param {String} name the name of the controller
   * @param {Object} instance the controller instance
   */
  app.setController = function (name, instance) {
    objCache[paths.CONTROLLERS][name + filenameSuffixes.Controller] = instance
  }

  /**
   * Override the existing cached version of a model
   *
   * @param {String} name the name of the model
   * @param {Object} instance the model instance
   */
  app.setModel = function (name, instance) {
    objCache[paths.MODELS][name + filenameSuffixes.MODELS] = instance
  }

  app.controllers.Static = require('./StaticController')(app)

  return app
}

module.exports.engine = {
  compile: function (source, options) {
    if (typeof source !== 'string') return source
    source = minify(source)
    return function (options) {
      options.locals = options.locals || {}
      options.partials = options.partials || {}
      if (options.body) options.locals.body = options.body
      for (var i in options.partials) {
        if (v.is.fun(options.partials[i].r)) continue
        try {
          options.partials[i] = hogan.compile(options.partials[i])
        } catch (e) {
          console.log("Unable to compile partial", i, e)
        }
      }
      return hogan.compile(source, options).render(options.locals, options.partials)
    }
  }
}
<commit_msg>Fixing typo in setController<commit_after>var fs = require('fs')
  , express = module.exports = require('express')
  , path = require('path')
  , hogan = require('hogan.js')
  , klass = global.klass = require('klass')
  , v = global.v = require('valentine')
  , router = require('./router')
  , argv = module.exports.argv = require('optimist').argv
  , minifyViews = process.env.minify || false
  , paths = {
      SERVICES: 'services'
    , HELPERS: 'helpers'
    , MODELS: 'models'
    , CONTROLLERS: 'controllers'
  }
  , filenameSuffixes = {
      SERVICES: 'Service'
    , HELPERS: 'Helper'
    , MODELS: 'Model'
    , CONTROLLERS: 'Controller'
  }

var minify = function () {
  var r = /(<script[^>]*>[\s\S]+?<\/script>)/
    , scr = /^<script([^>]*)>([\s\S]+?)<\/script>/
    , white = /\s+/g
    , closeTags = />\s+</g
    , jsp = require('uglify-js').parser
    , pro = require('uglify-js').uglify
    , uglify = function (src) {
        try {
          var ast = jsp.parse(src)
          ast = pro.ast_squeeze(ast)
          return pro.gen_code(ast)
        }
        catch (ex) {
          return src
        }
      }
  return function (doc) {
    if (!minifyViews) return doc
    return doc.trim().replace(/ +/g, ' ').split(r).map(function (p, i, m) {
      return (m = p.match(scr)) ? '<script' + m[1] + '>' + uglify(m[2]) + '</script>' : p.replace(white, ' ')
    }).join('').replace(closeTags, '><')
  }
}()

function isDirectory(p) {
  try {
    return fs.statSync(p).isDirectory()
  }
  catch (ex) {
    return false
  }
}

module.exports.createApp = function (baseDir, configuration, options) {
  configuration = configuration || {}
  options = options || {}

  var appDir = path.join(baseDir, '/app')
    , fileCache = {}
    , objCache = {}
    , pathCache = {}
    , updateCaches = v(paths).each(function (key, val) {
        fileCache[val] = {}
        objCache[val] = {}
        pathCache[val] = {}
      })
    , partialCache = {}
    , appDirs = [appDir].concat(v(function () {
        var dir = appDir + '/modules'
        return path.existsSync(dir) ? fs.readdirSync(dir) : []
      }()).map(function (dir) {
        return appDir + '/modules/' + dir
      }))
    , app = express.createServer()
    , loadFile = function (subdir, name, p) {
        if (typeof(fileCache[subdir][name]) !== 'undefined') return fileCache[subdir][name]
        var pathname = name.replace(/\./g, '/')
        var dir = v.find((p ? [p] : appDirs), function (dir) {
          var filename = dir + '/' + subdir + '/' + pathname + '.js'
          if (!path.existsSync(filename)) return false
          fileCache[subdir][name] = require(filename)(app, (configuration[subdir] && configuration[subdir][name] ? configuration[subdir][name] : {}))
          pathCache[subdir][name] = dir === appDir ? [appDir] : [dir, appDir]
          return true
        })
        if (!dir) throw new Error('Unable to find ' + subdir + '/' + pathname)

        return fileCache[subdir][name]
      }
    , loadClass = function (subdir, name, localName, definitionOnly) {
        if (definitionOnly) return loadFile(subdir, name)
        if (!objCache[subdir][name]) {
          var File = loadFile(subdir, name)
          objCache[subdir][name] = new File(localName, pathCache[subdir][name])
          objCache[subdir][name]._paths = pathCache[subdir][name]

          if (subdir === paths.MODELS) app.emit('createModel', localName, objCache[subdir][name])
          else if (subdir === paths.SERVICES) app.emit('createService', localName, objCache[subdir][name])
          else if (subdir === paths.CONTROLLERS) app.emit('createController', localName, objCache[subdir][name])
          //not emitting an event for helpers here as we never actually instantiate a helper
        }
        return objCache[subdir][name]
      }
    , mountPublicDir = function (dir) {
      var directory = dir + '/public'
      path.existsSync(directory) && app.use(express.static(directory))
    }

  app.set('base_dir', appDir)
  app.set('public', appDir + '/public')
  v(appDirs).each(mountPublicDir)

  app.controllers = {
    Base: require('./BaseController')(app)
  }

  app.addModulePath = function (dir) {
    appDirs.push(dir)
    mountPublicDir(dir)
  }

  app.getModulePaths = function () {
    return appDirs
  }

  app.mount = function () {
    var router = require('./router')
      , self = this

    v.each(appDirs, function (dir) {
      var filename = dir + '/config/routes.js'
      if (!path.existsSync(filename)) return
      router.init(self, require(filename)(self))
    })
    // static directory server

    router.init(this, {
      root: [['get', /(.+)/, 'Static']]
    })
  }

  app.prefetch = function (options) {
    var self = this

    v(paths).each(function (key, type) {
      v.each(appDirs, function (dir) {
        var d = dir + '/' + type
        if (!isDirectory(d)) return
        v.each(fs.readdirSync(d), function (file) {
          if (isDirectory(d + "/" + file)) return
          if (file.charAt(0) == '.') return
          if (file.substr(file.length - 3) === '.js') file = file.substr(0, file.length - 3)
          loadFile(type, file, dir)
        })
      })
    })
  }

  /**
   * Finds all partial templates relative to the provided view directory, stopping once the root
   * directory has been reached.
   *
   * All templates are added from the /partials/ folder within the current view directory.  We then
   * move to the parent directory and add any partials from it's /partials/ folder that don't conflict
   * with ones already added. We then move to the next parent directory and so on until we reach the
   * application root.
   *
   * This allows views to use common templates, and be able to override sub-templates.
   *
   * Example: consider the following directory structure:
   *   app/
   *       views/
   *           partials/
   *               user-details.html  - contains {{> user-link}})
   *               user-link.html
   *           search/
   *               results.html - contains {{> user-details}}
   *               partials/
   *                   user-link.html
   *           post/
   *               post.html  - contains {{> user-details}}
   *
   * The partials for app/views/search will contain:
   *   app/views/search/partial/user-link.html
   *   app/views/partial/user-details.html
   *
   * The partials for app/views/post will only contain app/views/partials/%
   *
   *
   * TODO: This uses synchronous filesystem APIs. It should either be performed at start up
   * for all controllers or else switched to use async APIs.
   */
  app.getPartials = function (viewDir) {
    var rootDir = app.set('base_dir')
    var viewSuffix = '.' + app.set('view engine')

    if (!partialCache[viewDir]) {

      if (path.relative(rootDir, viewDir).indexOf('../') != -1) {
        throw new Error('View directories must live beneath the application root.')
      }

      var partials = {}
      while (viewDir != rootDir) {
        var partialDir = path.resolve(viewDir, 'partials')
        try {
          fs.readdirSync(partialDir).forEach(function (file) {
            // Ignore hidden files and files that don't have the right extension.
            if (file.charAt(0) == '.') return
            if (file.substr(-viewSuffix.length) != viewSuffix) return

            // Remove the suffix, such that /partials/something.html can be used as {{> something}}
            var partialName = file.substr(0, file.length - viewSuffix.length)

            // If the map already contains this partial it means it has already been specified higher
            // up the view hierarchy.
            if (!partials[partialName]) {
              var partialFilename = path.resolve(partialDir, file)
              try {
                var partialContent = fs.readFileSync(partialFilename, 'utf8')
                partials[partialName] = hogan.compile(minify(partialContent))
              } catch (e) {
                console.log('Unable to compile partial', partialFilename, e)
              }
            }
          })
        } catch (e) {
          // Only log errors if they are not a "no such file or directory" error, since we expect
          // those to happen. (Saves us an fs.statSync.)
          if (e.code != 'ENOENT') console.log('Unable to read partials directory', partialDir, e)
        }
        viewDir = path.resolve(viewDir, '../')
      }
      partialCache[viewDir] = partials
    }

    // Note: This does more work than is necessary, since common parents of views will
    // be hit once for each view. If this turns out to be problematic we can cache at
    // intermediate folders as well.

    return partialCache[viewDir]
  }

  /**
   * Get a service instance or class
   *
   * @param {String} name the name of the service
   * @param {Boolean} definitionOnly whether to just grab the class or to grab an actual
   *     instance
   * @return {Object} a service class or instance
   */
  app.getService = function (name, definitionOnly) {
    return loadClass(paths.SERVICES, name + filenameSuffixes.SERVICES, name, definitionOnly)
  }

  /**
   * Get a controller instance or class
   *
   * @param {String} name the name of the controller
   * @param {Boolean} definitionOnly whether to just grab the class or to grab an actual
   *     instance
   * @return {Object} a controller class or instance
   */
  app.getController = function (name, definitionOnly) {
    if (app.controllers[name]) {
      return definitionOnly ? app.controllers[name] : new app.controllers[name](name, [])
    }
    else {
      return loadClass(paths.CONTROLLERS, name + filenameSuffixes.CONTROLLERS, name, definitionOnly)
    }
  }

  /**
   * Get a model instance or class
   *
   * @param {String} name the name of the model
   * @param {Boolean} definitionOnly whether to just grab the class or to grab an actual
   *     instance
   * @return {Object} a model class or instance
   */
  app.getModel = function (name, definitionOnly) {
    return loadClass(paths.MODELS, name + filenameSuffixes.MODELS, name, definitionOnly)
  }

  /**
   * Get a helper
   *
   * @param {String} name of the helper
   * @return {Object} a helper instance
   */
  app.getHelper = function (name) {
    return loadFile(paths.HELPERS, name + filenameSuffixes.HELPERS)
  }

  /**
   * Override the existing cached version of a service
   *
   * @param {String} name the name of the service
   * @param {Object} instance the service instance
   */
  app.setService = function (name, instance) {
    objCache[paths.SERVICES][name + filenameSuffixes.SERVICES] = instance
  }

  /**
   * Override the existing cached version of a controller
   *
   * @param {String} name the name of the controller
   * @param {Object} instance the controller instance
   */
  app.setController = function (name, instance) {
    objCache[paths.CONTROLLERS][name + filenameSuffixes.CONTROLLERS] = instance
  }

  /**
   * Override the existing cached version of a model
   *
   * @param {String} name the name of the model
   * @param {Object} instance the model instance
   */
  app.setModel = function (name, instance) {
    objCache[paths.MODELS][name + filenameSuffixes.MODELS] = instance
  }

  app.controllers.Static = require('./StaticController')(app)

  return app
}

module.exports.engine = {
  compile: function (source, options) {
    if (typeof source !== 'string') return source
    source = minify(source)
    return function (options) {
      options.locals = options.locals || {}
      options.partials = options.partials || {}
      if (options.body) options.locals.body = options.body
      for (var i in options.partials) {
        if (v.is.fun(options.partials[i].r)) continue
        try {
          options.partials[i] = hogan.compile(options.partials[i])
        } catch (e) {
          console.log("Unable to compile partial", i, e)
        }
      }
      return hogan.compile(source, options).render(options.locals, options.partials)
    }
  }
}
<|endoftext|>


<commit_before>import React, {Component, PureComponent} from 'react';
import {
    FlatList,
    StyleSheet,
    Text,
    TouchableOpacity,
    View
} from 'react-native';
import {ContainerFor} from './container.js';

class MyListItem extends PureComponent {
    _onPress = ()  => alert('Clicked');

    render() {
        return (
            <TouchableOpacity onLongPress={this._onPress}>
                <View style={styles.button}>
                   <Text style={styles.item}>{this.props.name}: {this.props.description}</Text>
                </View>
            </TouchableOpacity>
        );
    }
}

class CaretakerRoleList extends Component {

    _renderItem = ({item}) => (
        <MyListItem
            id={item.id}
            onLongPress={this.props.onPressItem}
            name={item.name}
            description={item.description}
        />
    );

    render() {
        return (
            <View style={styles.container}>
                <FlatList
                   data={this.props.caretakerRoles}
                   dataWhichCouldChange={this.props.caretakerRoles.map((caretakerRole) => caretakerRole.volunteer)}
                   renderItem={this._renderItem}
                   keyExtractor={(item) => item.id}
                />
            </View>
        );
    }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#F5FCFF',
  },
  title: {
    fontSize: 24,
    textAlign: 'center',
    margin: 15,
  },
  item: {
    fontSize: 20,
    textAlign: 'left',
    margin: 13,
  },
  modalContent: {
    margin: 13,
  },
  modalTitle: {
    fontSize: 24,
    textAlign: 'center',
    margin: 15
  },
  modalInfo: {
    fontSize: 20,
    textAlign: 'left',
    margin: 10
  }
});

export default ContainerFor(CaretakerRoleList);<commit_msg>Gave up on context menu for caretaker roles. Long press goes straight to edit<commit_after>import React, {Component, PureComponent} from 'react';
import {
    FlatList,
    StyleSheet,
    Text,
    TouchableOpacity,
    View
} from 'react-native';
import {ContainerFor} from './container.js';

class MyListItem extends PureComponent {
    _onPress = ()  => alert('Insert Edit Caretaker Role Screen Here');

    render() {
        return (
            <TouchableOpacity onLongPress={this._onPress}>
                <View style={styles.button}>
                   <Text style={styles.item}>{this.props.name}: {this.props.description}</Text>
                </View>
            </TouchableOpacity>
        );
    }
}

class CaretakerRoleList extends Component {

    _renderItem = ({item}) => (
        <MyListItem
            id={item.id}
            onLongPress={this.props.onPressItem}
            name={item.name}
            description={item.description}
        />
    );

    render() {
        return (
            <View style={styles.container}>
                <FlatList
                   data={this.props.caretakerRoles}
                   dataWhichCouldChange={this.props.caretakerRoles.map((caretakerRole) => caretakerRole.volunteer)}
                   renderItem={this._renderItem}
                   keyExtractor={(item) => item.id}
                />
            </View>
        );
    }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#F5FCFF',
  },
  title: {
    fontSize: 24,
    textAlign: 'center',
    margin: 15,
  },
  item: {
    fontSize: 20,
    textAlign: 'left',
    margin: 13,
  },
  modalContent: {
    margin: 13,
  },
  modalTitle: {
    fontSize: 24,
    textAlign: 'center',
    margin: 15
  },
  modalInfo: {
    fontSize: 20,
    textAlign: 'left',
    margin: 10
  }
});

export default ContainerFor(CaretakerRoleList);<|endoftext|>


<commit_before>Ext.define('SlateAdmin.view.progress.terms.email.Grid', {
    extend: 'Ext.grid.Panel',
    xtype: 'progress-terms-email-grid',
    requires: [
        'Ext.grid.column.Template',
        'Ext.toolbar.Fill'
    ],

    store: 'progress.terms.Emails',
    viewConfig: {
        emptyText: 'No report emails loaded, adjust filters and click "Load Report Emails" above to preview emails',
        deferEmptyText: false
    },
    columns: [
        {
            xtype: 'templatecolumn',

            header: 'Student Name',
            dataIndex: 'sortName',
            sortable: true,
            width: 200,
            tpl: [
                '<a href="#people/lookup/<tpl if="student.Username">{student.Username}<tpl else>?id={student.ID}</tpl>/contacts">',
                '    {sortName}',
                ''
            ]
        },
        {
            header: 'Reports',
            dataIndex: 'reports',
            sortable: true,
            width: 75,
            renderer: function (v) {
                return v ? v.length : 0;
            }
        },
        {
            flex: 1,

            xtype: 'templatecolumn',
            header: 'Recipients',
            dataIndex: 'recipients',
            emptyCellText: 'No recipients',
            tpl: [
                '
',
                '   <tpl for="recipients">',
                '
{name} {email} ({relationship})
',
                '   </tpl>',
                '
'
            ]
        }
    ]
});
<commit_msg>feat: show status in terms email grid<commit_after>Ext.define('SlateAdmin.view.progress.terms.email.Grid', {
    extend: 'Ext.grid.Panel',
    xtype: 'progress-terms-email-grid',
    requires: [
        'Ext.grid.column.Template',
        'Ext.toolbar.Fill'
    ],

    store: 'progress.terms.Emails',
    viewConfig: {
        emptyText: 'No report emails loaded, adjust filters and click "Load Report Emails" above to preview emails',
        deferEmptyText: false
    },
    columns: [
        {
            xtype: 'templatecolumn',

            header: 'Student Name',
            dataIndex: 'sortName',
            sortable: true,
            width: 200,
            tpl: [
                '<a href="#people/lookup/<tpl if="student.Username">{student.Username}<tpl else>?id={student.ID}</tpl>/contacts">',
                '    {sortName}',
                ''
            ]
        },
        {
            header: 'Reports',
            dataIndex: 'reports',
            sortable: true,
            width: 75,
            renderer: function (v) {
                return v ? v.length : 0;
            }
        },
        {
            flex: 1,

            xtype: 'templatecolumn',
            header: 'Recipients',
            dataIndex: 'recipients',
            emptyCellText: 'No recipients',
            tpl: [
                '
',
                '   <tpl for="recipients">',
                '
{name} {email} ({relationship})
',
                '   </tpl>',
                '
'
            ]
        }
    ]
});
<|endoftext|>


<commit_before>'use strict';
const _ = require('lodash');
const rp = require('request-promise');
const LocalRunner = require('./LocalRunner.js');
const DockerRunner = require('./DockerRunner.js');
const endpointToUrl = require('./common.js').endpointToUrl;
const WAIT_TIMEOUT = 300; // seconds

function sleep(ms) {
  return new Promise(resolve => setTimeout(() => resolve(), ms));
}

class InstanceManager {
  constructor(name) {
    this.instances = [];

    if (process.env.RESILIENCE_ARANGO_BASEPATH) {
      this.runner = new LocalRunner(process.env.RESILIENCE_ARANGO_BASEPATH);
    } else if (process.env.RESILIENCE_DOCKER_IMAGE) {
      this.runner = new DockerRunner(process.env.RESILIENCE_DOCKER_IMAGE);
    }

    if (process.env.ARANGO_STORAGE_ENGINE) {
      this.storageEngine = process.env.ARANGO_STORAGE_ENGINE;
      if (this.storageEngine !== 'rocksdb') {
        this.storageEngine = 'mmfiles';
      }
    } else {
      this.storageEngine = 'mmfiles';
    }

    if (!this.runner) {
      throw new Error(
        'Must specify RESILIENCE_ARANGO_BASEPATH (source root dir including a "build" folder containing compiled binaries or RESILIENCE_DOCKER_IMAGE to test a docker container'
      );
    }
    this.currentLog = '';
    this.agentCounter = 0;
    this.coordinatorCounter = 0;
    this.dbServerCounter = 0;
  }

  startArango(name, endpoint, role, args) {
    args.push('--server.authentication=false');
    //args.push('--log.level=v8=debug')
    //args.push('--log.level=communication=debug');
    args.push('--server.storage-engine=' + this.storageEngine);

    let instance = {
      name,
      role,
      process: null,
      status: 'NEW',
      exitcode: null,
      endpoint,
      args,
      logFn: line => {
        if (line.trim().length > 0) {
          let logLine =
            instance.name + '(' + instance.process.pid + '): \t' + line;
          if (process.env.LOG_IMMEDIATE) {
            console.log(logLine);
          } else {
            logLine = logLine.replace(/\x1B/g, '');
            this.currentLog += logLine + '\n';
          }
        }
      }
    };
    return this.runner.firstStart(instance);
  }

  startDbServer(name) {
    this.dbServerCounter++;
    return this.runner
      .createEndpoint()
      .then(endpoint => {
        let args = [
          '--cluster.agency-endpoint=' + this.getAgencyEndpoint(),
          '--cluster.my-role=PRIMARY',
          '--cluster.my-local-info=' + name,
          '--cluster.my-address=' + endpoint
        ];
        return this.startArango(name, endpoint, 'primary', args);
      })
      .then(instance => {
        this.instances.push(instance);
        return instance;
      });
  }

  getAgencyEndpoint() {
    return this.instances.filter(instance => {
      return instance.role === 'agent';
    })[0].endpoint;
  }

  startCoordinator(name) {
    this.coordinatorCounter++;
    return this.runner
      .createEndpoint()
      .then(endpoint => {
        let args = [
          '--cluster.agency-endpoint=' + this.getAgencyEndpoint(),
          '--cluster.my-role=COORDINATOR',
          '--cluster.my-local-info=' + name,
          '--cluster.my-address=' + endpoint
        ];
        return this.startArango(name, endpoint, 'coordinator', args);
      })
      .then(instance => {
        this.instances.push(instance);
        return instance;
      });
  }

  replace(instance) {
    let name, role;
    switch (instance.role) {
      case 'coordinator':
        this.coordinatorCounter++;
        name = 'coordinator-' + this.coordinatorCounter;
        role = 'COORDINATOR';
        break;
      case 'primary':
        this.dbServerCounter++;
        name = 'dbServer-' + this.dbServerCounter;
        role = 'PRIMARY';
        break;
      default:
        throw new Error('Can only replace coordinators/dbServers');
    }
    if (this.instances.includes(instance)) {
      throw new Error('Instance must be destroyed before it can be replaced');
    }
    let args = [
      '--cluster.agency-endpoint=' + this.getAgencyEndpoint(),
      '--cluster.my-role=' + role,
      '--cluster.my-local-info=' + name,
      '--cluster.my-address=' + instance.endpoint
    ];
    return this.startArango(name, instance.endpoint, instance.role, args)
      .then(instance => this.waitForInstance(instance))
      .then(instance => {
        this.instances.push(instance);
        return instance;
      });
  }

  startAgency(options = {}) {
    let size = options.agencySize || 1;
    if (options.agencyWaitForSync === undefined) {
      options.agencyWaitForSync = false;
    }
    const wfs = options.agencyWaitForSync;
    let promise = Promise.resolve([]);
    for (var i = 0; i < size; i++) {
      promise = promise.then(instances => {
        return this.runner
          .createEndpoint()
          .then(endpoint => {
            let args = [
              '--agency.activate=true',
              '--agency.size=' + size,
              '--agency.pool-size=' + size,
              '--agency.wait-for-sync=true',
              '--agency.supervision=true',
              '--server.threads=16',
              '--agency.supervision-frequency=0.5',
              '--agency.supervision-grace-period=2.5',
              '--agency.my-address=' + endpoint,
              '--log.force-direct=true'
            ];
            if (instances.length === 0) {
              args.push('--agency.endpoint=' + endpoint);
            } else {
              args.push('--agency.endpoint=' + instances[0].endpoint);
            }
            this.agentCounter++;
            return this.startArango(
              'agency-' + this.agentCounter,
              endpoint,
              'agent',
              args
            );
          })
          .then(instance => {
            return [...instances, instance];
          });
      });
    }
    return promise.then(agents => {
      this.instances = agents;
      return agents;
    });
  }

  findPrimaryDbServer(collectionName) {
    const baseUrl = endpointToUrl(this.getAgencyEndpoint());
    return rp({
      method: 'POST',
      uri: baseUrl + '/_api/agency/read',
      json: true,
      body: [
        [
          '/arango/Plan/Collections/_system',
          '/arango/Current/ServersRegistered'
        ]
      ]
    }).then(([info]) => {
      const collections = info.arango.Plan.Collections._system;
      const servers = info.arango.Current.ServersRegistered;
      for (const id of Object.keys(collections)) {
        const collection = collections[id];
        if (collection.name !== collectionName) {
          continue;
        }
        const shards = collection.shards;
        const shardsId = Object.keys(shards)[0];
        const uuid = shards[shardsId][0];
        const endpoint = servers[uuid].endpoint;
        const dbServers = this.dbServers().filter(
          instance => instance.endpoint === endpoint
        );
        if (!dbServers.length) {
          return Promise.reject(new Error(`Unknown endpoint "${endpoint}"`));
        }
        return dbServers[0];
      }
      return Promise.reject(
        new Error(`Unknown collection "${collectionName}"`)
      );
    });
  }

  startCluster(numAgents, numCoordinators, numDbServers, options = {}) {
    let agencyOptions = options.agents || {};
    _.extend(agencyOptions, {agencySize: numAgents});

    return this.startAgency(agencyOptions)
      .then(agents => {
        let promises = [Promise.resolve(agents)];

        let coordinators = Array.from(
          Array(numCoordinators).keys()
        ).map(index => {
          return this.startCoordinator('coordinator-' + (index + 1));
        });
        let dbServers = Array.from(Array(numDbServers).keys()).map(index => {
          return this.startDbServer('dbServer-' + (index + 1));
        });
        return Promise.all([].concat(coordinators, dbServers));
      })
      .then(servers => {
        return this.waitForAllInstances();
      })
      .then(() => {
        return this.getEndpoint();
      });
  }

  async waitForInstance(instance, started = Date.now()) {
    if (instance.status !== 'RUNNING') {
      throw new Error(`Instance ${instance.name} is down!`);
    }
    if (Date.now() - started > WAIT_TIMEOUT * 1000) {
      throw new Error(
        `Instance ${instance.name} is still not ready after ${WAIT_TIMEOUT} secs`
      );
    }

    let ok = false;
    try {
      await rp({
        method: 'GET',
        uri: endpointToUrl(instance.endpoint) + '/_api/version'
      });
      ok = true;
    } catch (e) {}
    if (ok) {
      return instance;
    } else {
      await sleep(100);
      return this.waitForInstance(instance, started);
    }
  }

  waitForAllInstances() {
    return Promise.all(
      this.instances.map(instance => {
        return this.waitForInstance(instance);
      })
    );
  }

  getEndpoint(instance) {
    return (instance || this.coordinators()[0]).endpoint;
  }

  getEndpointUrl(instance) {
    return endpointToUrl(this.getEndpoint(instance));
  }

  check() {
    return this.instances.every(instance => {
      return instance.status === 'RUNNING';
    });
  }

  shutdownCluster() {
    let shutdownPromise;

    let nonAgents = [].concat(this.coordinators(), this.dbServers());

    return Promise.all(
      nonAgents.map(server => {
        server.process.kill();
      })
    )
      .then(() => {
        let checkDown = () => {
          let allDown = nonAgents.every(instance => {
            return instance.status === 'EXITED';
          });

          if (allDown) {
            return Promise.resolve(true);
          } else {
            return new Promise((resolve, reject) => {
              setTimeout(() => {
                checkDown.bind(this)().then(resolve, reject);
              }, 1000);
            });
          }
        };
        return checkDown();
      })
      .then(() => {
        return Promise.all(
          this.agents().map(agent => {
            return agent.process.kill();
          })
        );
      })
      .then(() => {
        let checkDown = () => {
          let allDown = this.instances.every(instance => {
            return instance.status === 'EXITED';
          });

          if (allDown) {
            return Promise.resolve(true);
          } else {
            return new Promise((resolve, reject) => {
              setTimeout(() => {
                checkDown.bind(this)().then(resolve, reject);
              }, 100);
            });
          }
        };
        return checkDown();
      });
  }

  cleanup() {
    return this.shutdownCluster()
      .then(() => {
        this.instances = [];
        this.agentCounter = 0;
        this.coordinatorCounter = 0;
        this.dbServerCounter = 0;
        return this.runner.cleanup();
      })
      .then(() => {
        let log = this.currentLog;
        this.currentLog = '';
        return log;
      });
  }

  dbServers() {
    return this.instances.filter(instance => {
      return instance.role === 'primary';
    });
  }

  coordinators() {
    return this.instances.filter(instance => {
      return instance.role === 'coordinator';
    });
  }

  agents() {
    return this.instances.filter(instance => {
      return instance.role === 'agent';
    });
  }

  assignNewEndpoint(instance) {
    let index = this.instances.indexOf(instance);
    if (index === -1) {
      throw new Error("Couldn't find instance " + instance.name);
    }

    var createNewEndpoint = () => {
      return this.runner.createEndpoint().then(endpoint => {
        if (endpoint != instance.endpoint) {
          return endpoint;
        } else {
          return createNewEndpoint();
        }
      });
    };

    return createNewEndpoint().then(endpoint => {
      [
        'server.endpoint',
        'agency.my-address',
        'cluster.my-address'
      ].filter(arg => {
        index = instance.args.indexOf('--' + arg + '=' + instance.endpoint);
        if (index !== -1) {
          instance.args[index] = '--' + arg + '=' + endpoint;
        }
      });
      return this.runner.updateEndpoint(instance, endpoint);
    });
  }

  kill(instance, signal = 'SIGTERM') {
    if (!this.instances.includes(instance)) {
      throw new Error("Couldn't find instance " + instance.name);
    }

    instance.process.kill(signal);
    instance.status = 'KILLED';
    return new Promise((resolve, reject) => {
      let check = function() {
        if (instance.status !== 'EXITED') {
          setTimeout(check, 50);
        } else {
          resolve();
        }
      };
      check();
    });
  }

  destroy(instance) {
    let promise;
    if (this.instances.includes(instance)) {
      promise = this.kill(instance);
    } else {
      promise = Promise.resolve();
    }
    return promise.then(() => this.runner.destroy(instance)).then(() => {
      const i = this.instances.indexOf(instance);
      if (i !== -1) {
        this.instances = [
          ...this.instances.slice(0, i),
          ...this.instances.slice(i + 1)
        ];
      }
    });
  }

  restart(instance) {
    if (!this.instances.includes(instance)) {
      throw new Error("Couldn't find instance " + instance.name);
    }

    return this.runner.restart(instance).then(() => {
      return this.waitForInstance(instance);
    });
  }

  // this will append the logs to the test in case of a failure so
  // you get a nice combined log of what happened on the server and client
  moveServerLogs(test) {
    if (test.state === 'failed') {
      test.err.message = this.currentLog + '\n\n' + test.err.message;
    }
    this.currentLog = '';
  }

  async getFoxxmaster() {
    const baseUrl = endpointToUrl(this.getAgencyEndpoint());
    const [info] = await rp({
      method: 'POST',
      uri: baseUrl + '/_api/agency/read',
      json: true,
      body: [
        ['/arango/Current/Foxxmaster', '/arango/Current/ServersRegistered']
      ]
    });
    const uuid = info.arango.Current.Foxxmaster;
    const endpoint = info.arango.Current.ServersRegistered[uuid].endpoint;
    return this.instances.find(instance => instance.endpoint === endpoint);
  }

  async restartCluster() {
    const fm = await this.getFoxxmaster();
    await this.shutdownCluster();
    await Promise.all(this.agents().map(agent => this.restart(agent)));
    await Promise.all(this.dbServers().map(dbs => this.restart(dbs)));
    this.restart(fm);
    await sleep(100);
    await Promise.all(
      this.coordinators()
        .filter(coord => coord !== fm)
        .map(coord => this.restart(coord))
    );
    await this.waitForAllInstances();
  }
}

module.exports = InstanceManager;
<commit_msg>add option to pass more arguments<commit_after>'use strict';
const _ = require('lodash');
const rp = require('request-promise');
const LocalRunner = require('./LocalRunner.js');
const DockerRunner = require('./DockerRunner.js');
const endpointToUrl = require('./common.js').endpointToUrl;
const WAIT_TIMEOUT = 300; // seconds

function sleep(ms) {
  return new Promise(resolve => setTimeout(() => resolve(), ms));
}

class InstanceManager {
  constructor(name) {
    this.instances = [];

    if (process.env.RESILIENCE_ARANGO_BASEPATH) {
      this.runner = new LocalRunner(process.env.RESILIENCE_ARANGO_BASEPATH);
    } else if (process.env.RESILIENCE_DOCKER_IMAGE) {
      this.runner = new DockerRunner(process.env.RESILIENCE_DOCKER_IMAGE);
    }

    if (process.env.ARANGO_STORAGE_ENGINE) {
      this.storageEngine = process.env.ARANGO_STORAGE_ENGINE;
      if (this.storageEngine !== 'rocksdb') {
        this.storageEngine = 'mmfiles';
      }
    } else {
      this.storageEngine = 'mmfiles';
    }

    if (!this.runner) {
      throw new Error(
        'Must specify RESILIENCE_ARANGO_BASEPATH (source root dir including a "build" folder containing compiled binaries or RESILIENCE_DOCKER_IMAGE to test a docker container'
      );
    }
    this.currentLog = '';
    this.agentCounter = 0;
    this.coordinatorCounter = 0;
    this.dbServerCounter = 0;
  }

  startArango(name, endpoint, role, args) {
    args.push('--server.authentication=false');
    //args.push('--log.level=v8=debug')
    //args.push('--log.level=communication=debug');
    args.push('--server.storage-engine=' + this.storageEngine);

    if (process.env.ARANGO_EXTRA_ARGS) {
      args = args.concat(process.env.ARANGO_EXTRA_ARGS.split(' '));
    }

    let instance = {
      name,
      role,
      process: null,
      status: 'NEW',
      exitcode: null,
      endpoint,
      args,
      logFn: line => {
        if (line.trim().length > 0) {
          let logLine =
            instance.name + '(' + instance.process.pid + '): \t' + line;
          if (process.env.LOG_IMMEDIATE) {
            console.log(logLine);
          } else {
            logLine = logLine.replace(/\x1B/g, '');
            this.currentLog += logLine + '\n';
          }
        }
      }
    };
    return this.runner.firstStart(instance);
  }

  startDbServer(name) {
    this.dbServerCounter++;
    return this.runner
      .createEndpoint()
      .then(endpoint => {
        let args = [
          '--cluster.agency-endpoint=' + this.getAgencyEndpoint(),
          '--cluster.my-role=PRIMARY',
          '--cluster.my-local-info=' + name,
          '--cluster.my-address=' + endpoint
        ];
        return this.startArango(name, endpoint, 'primary', args);
      })
      .then(instance => {
        this.instances.push(instance);
        return instance;
      });
  }

  getAgencyEndpoint() {
    return this.instances.filter(instance => {
      return instance.role === 'agent';
    })[0].endpoint;
  }

  startCoordinator(name) {
    this.coordinatorCounter++;
    return this.runner
      .createEndpoint()
      .then(endpoint => {
        let args = [
          '--cluster.agency-endpoint=' + this.getAgencyEndpoint(),
          '--cluster.my-role=COORDINATOR',
          '--cluster.my-local-info=' + name,
          '--cluster.my-address=' + endpoint
        ];
        return this.startArango(name, endpoint, 'coordinator', args);
      })
      .then(instance => {
        this.instances.push(instance);
        return instance;
      });
  }

  replace(instance) {
    let name, role;
    switch (instance.role) {
      case 'coordinator':
        this.coordinatorCounter++;
        name = 'coordinator-' + this.coordinatorCounter;
        role = 'COORDINATOR';
        break;
      case 'primary':
        this.dbServerCounter++;
        name = 'dbServer-' + this.dbServerCounter;
        role = 'PRIMARY';
        break;
      default:
        throw new Error('Can only replace coordinators/dbServers');
    }
    if (this.instances.includes(instance)) {
      throw new Error('Instance must be destroyed before it can be replaced');
    }
    let args = [
      '--cluster.agency-endpoint=' + this.getAgencyEndpoint(),
      '--cluster.my-role=' + role,
      '--cluster.my-local-info=' + name,
      '--cluster.my-address=' + instance.endpoint
    ];
    return this.startArango(name, instance.endpoint, instance.role, args)
      .then(instance => this.waitForInstance(instance))
      .then(instance => {
        this.instances.push(instance);
        return instance;
      });
  }

  startAgency(options = {}) {
    let size = options.agencySize || 1;
    if (options.agencyWaitForSync === undefined) {
      options.agencyWaitForSync = false;
    }
    const wfs = options.agencyWaitForSync;
    let promise = Promise.resolve([]);
    for (var i = 0; i < size; i++) {
      promise = promise.then(instances => {
        return this.runner
          .createEndpoint()
          .then(endpoint => {
            let args = [
              '--agency.activate=true',
              '--agency.size=' + size,
              '--agency.pool-size=' + size,
              '--agency.wait-for-sync=true',
              '--agency.supervision=true',
              '--server.threads=16',
              '--agency.supervision-frequency=0.5',
              '--agency.supervision-grace-period=2.5',
              '--agency.my-address=' + endpoint,
              '--log.force-direct=true'
            ];
            if (instances.length === 0) {
              args.push('--agency.endpoint=' + endpoint);
            } else {
              args.push('--agency.endpoint=' + instances[0].endpoint);
            }
            this.agentCounter++;
            return this.startArango(
              'agency-' + this.agentCounter,
              endpoint,
              'agent',
              args
            );
          })
          .then(instance => {
            return [...instances, instance];
          });
      });
    }
    return promise.then(agents => {
      this.instances = agents;
      return agents;
    });
  }

  findPrimaryDbServer(collectionName) {
    const baseUrl = endpointToUrl(this.getAgencyEndpoint());
    return rp({
      method: 'POST',
      uri: baseUrl + '/_api/agency/read',
      json: true,
      body: [
        [
          '/arango/Plan/Collections/_system',
          '/arango/Current/ServersRegistered'
        ]
      ]
    }).then(([info]) => {
      const collections = info.arango.Plan.Collections._system;
      const servers = info.arango.Current.ServersRegistered;
      for (const id of Object.keys(collections)) {
        const collection = collections[id];
        if (collection.name !== collectionName) {
          continue;
        }
        const shards = collection.shards;
        const shardsId = Object.keys(shards)[0];
        const uuid = shards[shardsId][0];
        const endpoint = servers[uuid].endpoint;
        const dbServers = this.dbServers().filter(
          instance => instance.endpoint === endpoint
        );
        if (!dbServers.length) {
          return Promise.reject(new Error(`Unknown endpoint "${endpoint}"`));
        }
        return dbServers[0];
      }
      return Promise.reject(
        new Error(`Unknown collection "${collectionName}"`)
      );
    });
  }

  startCluster(numAgents, numCoordinators, numDbServers, options = {}) {
    let agencyOptions = options.agents || {};
    _.extend(agencyOptions, {agencySize: numAgents});

    return this.startAgency(agencyOptions)
      .then(agents => {
        let promises = [Promise.resolve(agents)];

        let coordinators = Array.from(
          Array(numCoordinators).keys()
        ).map(index => {
          return this.startCoordinator('coordinator-' + (index + 1));
        });
        let dbServers = Array.from(Array(numDbServers).keys()).map(index => {
          return this.startDbServer('dbServer-' + (index + 1));
        });
        return Promise.all([].concat(coordinators, dbServers));
      })
      .then(servers => {
        return this.waitForAllInstances();
      })
      .then(() => {
        return this.getEndpoint();
      });
  }

  async waitForInstance(instance, started = Date.now()) {
    if (instance.status !== 'RUNNING') {
      throw new Error(`Instance ${instance.name} is down!`);
    }
    if (Date.now() - started > WAIT_TIMEOUT * 1000) {
      throw new Error(
        `Instance ${instance.name} is still not ready after ${WAIT_TIMEOUT} secs`
      );
    }

    let ok = false;
    try {
      await rp({
        method: 'GET',
        uri: endpointToUrl(instance.endpoint) + '/_api/version'
      });
      ok = true;
    } catch (e) {}
    if (ok) {
      return instance;
    } else {
      await sleep(100);
      return this.waitForInstance(instance, started);
    }
  }

  waitForAllInstances() {
    return Promise.all(
      this.instances.map(instance => {
        return this.waitForInstance(instance);
      })
    );
  }

  getEndpoint(instance) {
    return (instance || this.coordinators()[0]).endpoint;
  }

  getEndpointUrl(instance) {
    return endpointToUrl(this.getEndpoint(instance));
  }

  check() {
    return this.instances.every(instance => {
      return instance.status === 'RUNNING';
    });
  }

  shutdownCluster() {
    let shutdownPromise;

    let nonAgents = [].concat(this.coordinators(), this.dbServers());

    return Promise.all(
      nonAgents.map(server => {
        server.process.kill();
      })
    )
      .then(() => {
        let checkDown = () => {
          let allDown = nonAgents.every(instance => {
            return instance.status === 'EXITED';
          });

          if (allDown) {
            return Promise.resolve(true);
          } else {
            return new Promise((resolve, reject) => {
              setTimeout(() => {
                checkDown.bind(this)().then(resolve, reject);
              }, 1000);
            });
          }
        };
        return checkDown();
      })
      .then(() => {
        return Promise.all(
          this.agents().map(agent => {
            return agent.process.kill();
          })
        );
      })
      .then(() => {
        let checkDown = () => {
          let allDown = this.instances.every(instance => {
            return instance.status === 'EXITED';
          });

          if (allDown) {
            return Promise.resolve(true);
          } else {
            return new Promise((resolve, reject) => {
              setTimeout(() => {
                checkDown.bind(this)().then(resolve, reject);
              }, 100);
            });
          }
        };
        return checkDown();
      });
  }

  cleanup() {
    return this.shutdownCluster()
      .then(() => {
        this.instances = [];
        this.agentCounter = 0;
        this.coordinatorCounter = 0;
        this.dbServerCounter = 0;
        return this.runner.cleanup();
      })
      .then(() => {
        let log = this.currentLog;
        this.currentLog = '';
        return log;
      });
  }

  dbServers() {
    return this.instances.filter(instance => {
      return instance.role === 'primary';
    });
  }

  coordinators() {
    return this.instances.filter(instance => {
      return instance.role === 'coordinator';
    });
  }

  agents() {
    return this.instances.filter(instance => {
      return instance.role === 'agent';
    });
  }

  assignNewEndpoint(instance) {
    let index = this.instances.indexOf(instance);
    if (index === -1) {
      throw new Error("Couldn't find instance " + instance.name);
    }

    var createNewEndpoint = () => {
      return this.runner.createEndpoint().then(endpoint => {
        if (endpoint != instance.endpoint) {
          return endpoint;
        } else {
          return createNewEndpoint();
        }
      });
    };

    return createNewEndpoint().then(endpoint => {
      [
        'server.endpoint',
        'agency.my-address',
        'cluster.my-address'
      ].filter(arg => {
        index = instance.args.indexOf('--' + arg + '=' + instance.endpoint);
        if (index !== -1) {
          instance.args[index] = '--' + arg + '=' + endpoint;
        }
      });
      return this.runner.updateEndpoint(instance, endpoint);
    });
  }

  kill(instance, signal = 'SIGTERM') {
    if (!this.instances.includes(instance)) {
      throw new Error("Couldn't find instance " + instance.name);
    }

    instance.process.kill(signal);
    instance.status = 'KILLED';
    return new Promise((resolve, reject) => {
      let check = function() {
        if (instance.status !== 'EXITED') {
          setTimeout(check, 50);
        } else {
          resolve();
        }
      };
      check();
    });
  }

  destroy(instance) {
    let promise;
    if (this.instances.includes(instance)) {
      promise = this.kill(instance);
    } else {
      promise = Promise.resolve();
    }
    return promise.then(() => this.runner.destroy(instance)).then(() => {
      const i = this.instances.indexOf(instance);
      if (i !== -1) {
        this.instances = [
          ...this.instances.slice(0, i),
          ...this.instances.slice(i + 1)
        ];
      }
    });
  }

  restart(instance) {
    if (!this.instances.includes(instance)) {
      throw new Error("Couldn't find instance " + instance.name);
    }

    return this.runner.restart(instance).then(() => {
      return this.waitForInstance(instance);
    });
  }

  // this will append the logs to the test in case of a failure so
  // you get a nice combined log of what happened on the server and client
  moveServerLogs(test) {
    if (test.state === 'failed') {
      test.err.message = this.currentLog + '\n\n' + test.err.message;
    }
    this.currentLog = '';
  }

  async getFoxxmaster() {
    const baseUrl = endpointToUrl(this.getAgencyEndpoint());
    const [info] = await rp({
      method: 'POST',
      uri: baseUrl + '/_api/agency/read',
      json: true,
      body: [
        ['/arango/Current/Foxxmaster', '/arango/Current/ServersRegistered']
      ]
    });
    const uuid = info.arango.Current.Foxxmaster;
    const endpoint = info.arango.Current.ServersRegistered[uuid].endpoint;
    return this.instances.find(instance => instance.endpoint === endpoint);
  }

  async restartCluster() {
    const fm = await this.getFoxxmaster();
    await this.shutdownCluster();
    await Promise.all(this.agents().map(agent => this.restart(agent)));
    await Promise.all(this.dbServers().map(dbs => this.restart(dbs)));
    this.restart(fm);
    await sleep(100);
    await Promise.all(
      this.coordinators()
        .filter(coord => coord !== fm)
        .map(coord => this.restart(coord))
    );
    await this.waitForAllInstances();
  }
}

module.exports = InstanceManager;
<|endoftext|>


<commit_before>
StickyTemplate = function(){
};

StickyTemplate.templates = {};

StickyTemplate.loadFile =
StickyTemplate.loadFiles =
function( files, callback ){

	if( !files ){
		files = [];
	}
	else if( !$.isArray( files ) ){
		files = [ files ];
	}

	for( var i=0; i<files.length; i++ ){

		var file = files[ i ];
		var name = StickyTemplate.stripName( file );

		var template = {
			name: name,
			loaded: false
		};

		StickyTemplate.templates[ name ] = template;

		var url = file;

		if( url.indexOf('?') == -1 ){
			url += '?';
		}
		else{
			url += '&';
		}

		url += 'ac='+new Date().getTime();

		$.get( url, function( html ){

			StickyTemplate.loadHTML( this.name, html );

			if( StickyTemplate.isLoaded() ){
				callback();
			}

		}.bind( template ) );
	}

};

StickyTemplate.loadHTML =
function( name, html ){

	var template = StickyTemplate.templates[ name ];

	if( !template ){
		template = StickyTemplate.templates[ name ] = { name: name };
	}

	var $jq = $(html);

	$jq.find('[data-sticky-template]').each( function(){
		var $sub = $(this);
		$sub.remove();
		var subName = $sub.data('sticky-template');
		$sub.removeAttr('data-sticky-template');
		StickyTemplate.loadHTML( subName, $sub.get(0).outerHTML );
	});

	html = $jq.get(0).outerHTML;

	template.loaded = true;
	template.html = html;
	template.$jQuery = $jq;
}

StickyTemplate.getJQuery =
StickyTemplate.getJQ =
StickyTemplate.jQuery =
StickyTemplate.jq =
function( name, params ){

	var template = StickyTemplate.templates[ name ] || null;

	if( !template ){
		return null;
	}

	var html = template.html;
	var anyTokens = false;

	if( params ){
		for( var token in params ){
			if( token.substr(0,1) != '%' ){
				continue;
			}

			var value = params[ token ];

			if( value.jquery ){
				value = value.get(0).outerHTML;
			}

			html = html.replace( token, value );
			anyTokens = true;
		}
	}

	var $jq;

	if( anyTokens ){
		$jq = $(html);
	}
	else{
		$jq = template.$jQuery.clone();
	}

	if( params ){
		StickyTemplate.setParams( $jq, params );
	}

	return $jq;
};

StickyTemplate.setParams =
StickyTemplate.params =
function( $jq, params ){

	for( var selector in params ){
		if( selector.substr(0,1) == '%' ){
			continue;
		}

		var value = params[ selector ];

		if( value == undefined ){
			value = '';
		}

		var selectorParts = selector.split( /\$/g );

		selector = selectorParts[0];

		var attribute = null;

		if( selectorParts.length > 1 ){
			attribute = selectorParts[1];
		}

		var $targets = $jq.find( selector ).addBack( selector );

		if( attribute ){
			$targets.attr( attribute, value );
		}
		else if( value.jquery ){
			$targets.empty().append( value );
		}
		else{
			$targets.text( value );
		}
	}

};

StickyTemplate.getElement =
StickyTemplate.element =
function( name, params ){

	var $jq = StickyTemplate.jq( name, params );

	if( $jq ){
		return $jq.get(0);
	}
	else{
		return null;
	}
};

StickyTemplate.getHTML =
StickyTemplate.html =
function( name, params ){

	var element = StickyTemplate.element( name, params );

	if( element ){
		return element.outerHTML;
	}
	else{
		return null;
	}
};

StickyTemplate.isLoaded =
function( name ){

	if( name ){

		return StickyTemplate.templates[ name ].loaded;
	}
	else{

		for( var name in StickyTemplate.templates ){
			if( !StickyTemplate.templates[ name ].loaded ){
				return false;
			}
		}

		return true;
	}
};

StickyTemplate.stripName =
function( str ){

	str = str.split('/').pop();
	str = str.split('.')[0];
	return str;
};

<commit_msg>made token replace global<commit_after>
StickyTemplate = function(){
};

StickyTemplate.templates = {};

StickyTemplate.loadFile =
StickyTemplate.loadFiles =
function( files, callback ){

	if( !files ){
		files = [];
	}
	else if( !$.isArray( files ) ){
		files = [ files ];
	}

	for( var i=0; i<files.length; i++ ){

		var file = files[ i ];
		var name = StickyTemplate.stripName( file );

		var template = {
			name: name,
			loaded: false
		};

		StickyTemplate.templates[ name ] = template;

		var url = file;

		if( url.indexOf('?') == -1 ){
			url += '?';
		}
		else{
			url += '&';
		}

		url += 'ac='+new Date().getTime();

		$.get( url, function( html ){

			StickyTemplate.loadHTML( this.name, html );

			if( StickyTemplate.isLoaded() ){
				callback();
			}

		}.bind( template ) );
	}

};

StickyTemplate.loadHTML =
function( name, html ){

	var template = StickyTemplate.templates[ name ];

	if( !template ){
		template = StickyTemplate.templates[ name ] = { name: name };
	}

	var $jq = $(html);

	$jq.find('[data-sticky-template]').each( function(){
		var $sub = $(this);
		$sub.remove();
		var subName = $sub.data('sticky-template');
		$sub.removeAttr('data-sticky-template');
		StickyTemplate.loadHTML( subName, $sub.get(0).outerHTML );
	});

	html = $jq.get(0).outerHTML;

	template.loaded = true;
	template.html = html;
	template.$jQuery = $jq;
}

StickyTemplate.getJQuery =
StickyTemplate.getJQ =
StickyTemplate.jQuery =
StickyTemplate.jq =
function( name, params ){

	var template = StickyTemplate.templates[ name ] || null;

	if( !template ){
		return null;
	}

	var html = template.html;
	var anyTokens = false;

	if( params ){
		for( var token in params ){
			if( token.substr(0,1) != '%' ){
				continue;
			}

			var value = params[ token ];

			if( value.jquery ){
				value = value.get(0).outerHTML;
			}

			html = html.replace( new RegExp( token, "g"), value );
			anyTokens = true;
		}
	}

	var $jq;

	if( anyTokens ){
		$jq = $(html);
	}
	else{
		$jq = template.$jQuery.clone();
	}

	if( params ){
		StickyTemplate.setParams( $jq, params );
	}

	return $jq;
};

StickyTemplate.setParams =
StickyTemplate.params =
function( $jq, params ){

	for( var selector in params ){
		if( selector.substr(0,1) == '%' ){
			continue;
		}

		var value = params[ selector ];

		if( value == undefined ){
			value = '';
		}

		var selectorParts = selector.split( /\$/g );

		selector = selectorParts[0];

		var attribute = null;

		if( selectorParts.length > 1 ){
			attribute = selectorParts[1];
		}

		var $targets = $jq.find( selector ).addBack( selector );

		if( attribute ){
			$targets.attr( attribute, value );
		}
		else if( value.jquery ){
			$targets.empty().append( value );
		}
		else{
			$targets.text( value );
		}
	}

};

StickyTemplate.getElement =
StickyTemplate.element =
function( name, params ){

	var $jq = StickyTemplate.jq( name, params );

	if( $jq ){
		return $jq.get(0);
	}
	else{
		return null;
	}
};

StickyTemplate.getHTML =
StickyTemplate.html =
function( name, params ){

	var element = StickyTemplate.element( name, params );

	if( element ){
		return element.outerHTML;
	}
	else{
		return null;
	}
};

StickyTemplate.isLoaded =
function( name ){

	if( name ){

		return StickyTemplate.templates[ name ].loaded;
	}
	else{

		for( var name in StickyTemplate.templates ){
			if( !StickyTemplate.templates[ name ].loaded ){
				return false;
			}
		}

		return true;
	}
};

StickyTemplate.stripName =
function( str ){

	str = str.split('/').pop();
	str = str.split('.')[0];
	return str;
};

<|endoftext|>