<commit_before>import React from 'react';
import {routerShape} from 'react-router';

import Alert from '../../../../../../src/js/components/Alert';
import DateUtil from '../../../../../../src/js/utils/DateUtil';
import ConfigurationMap from '../../../../../../src/js/components/ConfigurationMap';
import ConfigurationMapHeading from '../../../../../../src/js/components/ConfigurationMapHeading';
import ConfigurationMapSection from '../../../../../../src/js/components/ConfigurationMapSection';
import DeclinedOffersHelpText from '../../constants/DeclinedOffersHelpText';
import DeclinedOffersTable from '../../components/DeclinedOffersTable';
import HashMapDisplay from '../../../../../../src/js/components/HashMapDisplay';
import MarathonStore from '../../stores/MarathonStore';
import Pod from '../../structs/Pod';
import PodContainerTerminationTable from './PodContainerTerminationTable';
import RecentOffersSummary from '../../components/RecentOffersSummary';
import TimeAgo from '../../../../../../src/js/components/TimeAgo';

const METHODS_TO_BIND = ['handleJumpToRecentOffersClick'];

class PodDebugTabView extends React.Component {
  constructor() {
    super(...arguments);

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentWillMount() {
    MarathonStore.setShouldEmbedLastUnusedOffers(true);
  }

  componentWillUnmount() {
    MarathonStore.setShouldEmbedLastUnusedOffers(false);
  }

  getDeclinedOffersTable() {
    const {pod} = this.props;
    const queue = pod.getQueue();

    if (queue == null || queue.declinedOffers.offers == null) {
      return null;
    }

    return (

        <ConfigurationMapHeading level={2}>
          Details
        </ConfigurationMapHeading>
        <DeclinedOffersTable offers={queue.declinedOffers.offers}
          service={pod}
          summary={queue.declinedOffers.summary} />

    );
  }

  getTerminationHistory() {
    const history = this.props.pod.getTerminationHistoryList().getItems();
    if (!history.length) {
      return (
        <ConfigurationMapSection>
          <ConfigurationMapHeading>
            Last Terminations
          </ConfigurationMapHeading>

(No data)

        </ConfigurationMapSection>
      );
    }

    return history.reduce(function (accumulator, item, index) {
      let headline;
      let startedAt = item.getStartedAt();
      let terminatedAt = item.getTerminatedAt();
      let terminationValueMapping = {
        'Instance ID': item.getId(),
        'Message': item.getMessage(),
        'Started At': (

            {startedAt.toString()} (<TimeAgo time={startedAt} />)

        )
      };

      if (index === 0) {
        headline = (
          <ConfigurationMapHeading level={2}>
            Last Termination (<TimeAgo time={terminatedAt} />)
          </ConfigurationMapHeading>
        );
      } else {
        headline = (
          <ConfigurationMapHeading level={2}>
            Terminated at {terminatedAt.toString()} (<TimeAgo time={terminatedAt} />)
          </ConfigurationMapHeading>
        );
      }

      accumulator.push(
        <ConfigurationMapSection key={`termination-${index}`}>
          {headline}
          <HashMapDisplay hash={terminationValueMapping} />
        </ConfigurationMapSection>,
        <ConfigurationMapSection key={`container-${index}`}>
          <ConfigurationMapHeading level={3}>
            Containers
          </ConfigurationMapHeading>
          <PodContainerTerminationTable containers={item.getContainers()} />
        </ConfigurationMapSection>
      );

      return accumulator;
    }, []);
  }

  getLastVersionChange() {
    const {pod} = this.props;
    let lastUpdated = pod.getLastUpdated();

    // Note to reader: `getLastChanged` refers to the last changes that happend
    // to the pod (such as state changes or instance changes), but we are
    // interested in the last configuration update, for which we are using the
    // `getLastUpdate` function.

    let LastVersionChangeValueMapping = {
      'Configuration': (

          {lastUpdated.toString()} (<TimeAgo time={lastUpdated} />)

      )
    };

    return (
      <ConfigurationMapSection>
        <ConfigurationMapHeading>
          Last Changes
        </ConfigurationMapHeading>
        <HashMapDisplay hash={LastVersionChangeValueMapping} />
      </ConfigurationMapSection>
    );
  }

  getRecentOfferSummary() {
    const queue = this.props.pod.getQueue();
    let introText = null;
    let mainContent = null;
    let offerCount = null;

    if (queue == null || queue.declinedOffers.summary == null) {
      introText = 'Offers will appear here when your service is deploying or waiting for resources.';
    } else {
      const {declinedOffers: {summary}} = queue;
      const {roles: {offers = 0}} = summary;

      introText = DeclinedOffersHelpText.summaryIntro;

      mainContent = (

          <ConfigurationMapHeading level={2}>
            Summary
          </ConfigurationMapHeading>
          <RecentOffersSummary data={summary} />

      );

      offerCount = ` (${offers})`;
    }

    return (

 { this.offerSummaryRef = ref; }}>
        <ConfigurationMapHeading>
          Recent Resource Offers{offerCount}
        </ConfigurationMapHeading>

{introText}

        {mainContent}

    );
  }

  getWaitingForResourcesNotice() {
    const queue = this.props.pod.getQueue();

    if (queue == null || queue.since == null) {
      return null;
    }

    const waitingSince = DateUtil.strToMs(queue.since);
    const timeWaiting = Date.now() - waitingSince;

    // If the service has been waiting for less than five minutes, we don't
    // display the warning.
    if (timeWaiting < 1000 * 60 * 5) {
      return null;
    }

    return (
      <Alert>
        DC/OS has been waiting for resources and unable to complete this deployment for {DateUtil.getDuration(timeWaiting, null)}. See recent resource offers.
      </Alert>
    );
  }

  handleJumpToRecentOffersClick() {
    if (this.offerSummaryRef) {
      this.offerSummaryRef.scrollIntoView();
    }
  }

  render() {
    return (

        {this.getWaitingForResourcesNotice()}
        <ConfigurationMap>
          {this.getLastVersionChange()}
          {this.getTerminationHistory()}
          {this.getRecentOfferSummary()}
          {this.getDeclinedOffersTable()}
        </ConfigurationMap>

    );
  }
}

PodDebugTabView.contextTypes = {
  router: routerShape
};

PodDebugTabView.propTypes = {
  pod: React.PropTypes.instanceOf(Pod)
};

module.exports = PodDebugTabView;
<commit_msg>reduce -> map<commit_after>import React from 'react';
import {routerShape} from 'react-router';

import Alert from '../../../../../../src/js/components/Alert';
import DateUtil from '../../../../../../src/js/utils/DateUtil';
import ConfigurationMap from '../../../../../../src/js/components/ConfigurationMap';
import ConfigurationMapHeading from '../../../../../../src/js/components/ConfigurationMapHeading';
import ConfigurationMapSection from '../../../../../../src/js/components/ConfigurationMapSection';
import DeclinedOffersHelpText from '../../constants/DeclinedOffersHelpText';
import DeclinedOffersTable from '../../components/DeclinedOffersTable';
import HashMapDisplay from '../../../../../../src/js/components/HashMapDisplay';
import MarathonStore from '../../stores/MarathonStore';
import Pod from '../../structs/Pod';
import PodContainerTerminationTable from './PodContainerTerminationTable';
import RecentOffersSummary from '../../components/RecentOffersSummary';
import TimeAgo from '../../../../../../src/js/components/TimeAgo';

const METHODS_TO_BIND = ['handleJumpToRecentOffersClick'];

class PodDebugTabView extends React.Component {
  constructor() {
    super(...arguments);

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentWillMount() {
    MarathonStore.setShouldEmbedLastUnusedOffers(true);
  }

  componentWillUnmount() {
    MarathonStore.setShouldEmbedLastUnusedOffers(false);
  }

  getDeclinedOffersTable() {
    const {pod} = this.props;
    const queue = pod.getQueue();

    if (queue == null || queue.declinedOffers.offers == null) {
      return null;
    }

    return (

        <ConfigurationMapHeading level={2}>
          Details
        </ConfigurationMapHeading>
        <DeclinedOffersTable offers={queue.declinedOffers.offers}
          service={pod}
          summary={queue.declinedOffers.summary} />

    );
  }

  getTerminationHistory() {
    const history = this.props.pod.getTerminationHistoryList().getItems();
    if (!history.length) {
      return (
        <ConfigurationMapSection>
          <ConfigurationMapHeading>
            Last Terminations
          </ConfigurationMapHeading>

(No data)

        </ConfigurationMapSection>
      );
    }

    return history.map(function (item, index) {
      let headline;
      let startedAt = item.getStartedAt();
      let terminatedAt = item.getTerminatedAt();
      let terminationValueMapping = {
        'Instance ID': item.getId(),
        'Message': item.getMessage(),
        'Started At': (

            {startedAt.toString()} (<TimeAgo time={startedAt} />)

        )
      };

      if (index === 0) {
        headline = (
          <ConfigurationMapHeading level={2}>
            Last Termination (<TimeAgo time={terminatedAt} />)
          </ConfigurationMapHeading>
        );
      } else {
        headline = (
          <ConfigurationMapHeading level={2}>
            Terminated at {terminatedAt.toString()} (<TimeAgo time={terminatedAt} />)
          </ConfigurationMapHeading>
        );
      }

      return (
        <ConfigurationMapSection key={`termination-${index}`}>
          {headline}
          <HashMapDisplay hash={terminationValueMapping} />
        </ConfigurationMapSection>,
        <ConfigurationMapSection key={`container-${index}`}>
          <ConfigurationMapHeading level={3}>
            Containers
          </ConfigurationMapHeading>
          <PodContainerTerminationTable containers={item.getContainers()} />
        </ConfigurationMapSection>
      );
    });
  }

  getLastVersionChange() {
    const {pod} = this.props;
    let lastUpdated = pod.getLastUpdated();

    // Note to reader: `getLastChanged` refers to the last changes that happend
    // to the pod (such as state changes or instance changes), but we are
    // interested in the last configuration update, for which we are using the
    // `getLastUpdate` function.

    let LastVersionChangeValueMapping = {
      'Configuration': (

          {lastUpdated.toString()} (<TimeAgo time={lastUpdated} />)

      )
    };

    return (
      <ConfigurationMapSection>
        <ConfigurationMapHeading>
          Last Changes
        </ConfigurationMapHeading>
        <HashMapDisplay hash={LastVersionChangeValueMapping} />
      </ConfigurationMapSection>
    );
  }

  getRecentOfferSummary() {
    const queue = this.props.pod.getQueue();
    let introText = null;
    let mainContent = null;
    let offerCount = null;

    if (queue == null || queue.declinedOffers.summary == null) {
      introText = 'Offers will appear here when your service is deploying or waiting for resources.';
    } else {
      const {declinedOffers: {summary}} = queue;
      const {roles: {offers = 0}} = summary;

      introText = DeclinedOffersHelpText.summaryIntro;

      mainContent = (

          <ConfigurationMapHeading level={2}>
            Summary
          </ConfigurationMapHeading>
          <RecentOffersSummary data={summary} />

      );

      offerCount = ` (${offers})`;
    }

    return (

 { this.offerSummaryRef = ref; }}>
        <ConfigurationMapHeading>
          Recent Resource Offers{offerCount}
        </ConfigurationMapHeading>

{introText}

        {mainContent}

    );
  }

  getWaitingForResourcesNotice() {
    const queue = this.props.pod.getQueue();

    if (queue == null || queue.since == null) {
      return null;
    }

    const waitingSince = DateUtil.strToMs(queue.since);
    const timeWaiting = Date.now() - waitingSince;

    // If the service has been waiting for less than five minutes, we don't
    // display the warning.
    if (timeWaiting < 1000 * 60 * 5) {
      return null;
    }

    return (
      <Alert>
        DC/OS has been waiting for resources and unable to complete this deployment for {DateUtil.getDuration(timeWaiting, null)}. See recent resource offers.
      </Alert>
    );
  }

  handleJumpToRecentOffersClick() {
    if (this.offerSummaryRef) {
      this.offerSummaryRef.scrollIntoView();
    }
  }

  render() {
    return (

        {this.getWaitingForResourcesNotice()}
        <ConfigurationMap>
          {this.getLastVersionChange()}
          {this.getTerminationHistory()}
          {this.getRecentOfferSummary()}
          {this.getDeclinedOffersTable()}
        </ConfigurationMap>

    );
  }
}

PodDebugTabView.contextTypes = {
  router: routerShape
};

PodDebugTabView.propTypes = {
  pod: React.PropTypes.instanceOf(Pod)
};

module.exports = PodDebugTabView;
<|endoftext|>


<commit_before>'use strict';
// if you checked "fancy-settings" in extensionizr.com, uncomment this lines

// var settings = new Store("settings", {
//     "sample_setting": "This is how you use Store.js to remember values"
// });
var socket = io('https://localhost:3001/', {secure: true});
var users = {};

socket.on('users', function (data) {
    users = data;
    console.log(users);
    chrome.runtime.sendMessage({fn: 'updateUsers', users: users});
});

var cart = {
    refreshUsers: function (data, callback) {
        callback({users: users});
    },
    login: function (data, callback) {
        chrome.cookies.get({
            url: "https://www.10bis.co.il/",
            name: "WebApplication.Context"
        }, function (a) {
            if (a && a.hasOwnProperty('value')) {
                data.user.cart = a.value.match(/ShoppingCartGuid=([^&]*)/)[1];
                socket.user = data.user;
                socket.emit('peer-joined', data.user);
                callback(null, data.user);
            } else {
                console.error('could not retrieve cookie', a);
                callback(null, null);
            }
        });
        callback();
    },
    join: function joinCart(body, callback) {
        var guid = body.guid;
        chrome.cookies.get({
            url: "https://www.10bis.co.il/*",
            name: "WebApplication.Context"
        }, function (a) {
            var value = a.value.replace(/ShoppingCartGuid=([^&]*)/, 'ShoppingCartGuid=' + guid);
            chrome.cookies.set({
                url: 'https://www.10bis.co.il',
                name: "WebApplication.Context",
                value: value
            }, callback);
        });
    }
};
//example of using a message handler from the inject scripts
//joinCart('d37dfc49-205d-4bb4-b83d-0af2f6b3c47f')

chrome.extension.onMessage.addListener(
    function (request, sender, sendResponse) {
        if (request && request.fn && cart && cart[request.fn]) {
            cart[request.fn](request, function (err, data) {
                return sendResponse(data);
            });
        }
        return true;
    });<commit_msg>added getcart function in background<commit_after>'use strict';
// if you checked "fancy-settings" in extensionizr.com, uncomment this lines

// var settings = new Store("settings", {
//     "sample_setting": "This is how you use Store.js to remember values"
// });
var socket = io('https://localhost:3001/', {secure: true});
var users = {};

socket.on('users', function (data) {
    users = data;
    console.log(users);
    chrome.runtime.sendMessage({fn: 'updateUsers', users: users});
});

function getCart(callback) {
    chrome.cookies.get({
        url: "https://www.10bis.co.il/",
        name: "WebApplication.Context"
    }, function (a) {
        if (a && a.hasOwnProperty('value')) {
            callback(null, a.value.match(/ShoppingCartGuid=([^&]*)/)[1]);
        } else {
            console.error('could not retrieve cookie', a);
            callback(null, null);
        }
    });
}
var cart = {
    refreshUsers: function (data, callback) {
        callback({users: users});
    },
    getCartId: function (data, callback) {
        getCart(callback);
    },
    login: function (data, callback) {
        getCart(function (err, cart) {
            if (err) {
                return callback(err, null);
            }

            data.user.cart = cart;
            socket.user = data.user;
            socket.emit('peer-joined', data.user);
            callback(null, socket.user);
        });
    },
    join: function joinCart(body, callback) {
        var guid = body.guid;
        chrome.cookies.get({
            url: "https://www.10bis.co.il/*",
            name: "WebApplication.Context"
        }, function (a) {
            var value = a.value.replace(/ShoppingCartGuid=([^&]*)/, 'ShoppingCartGuid=' + guid);
            chrome.cookies.set({
                url: 'https://www.10bis.co.il',
                name: "WebApplication.Context",
                value: value
            }, callback);
        });
    }
};
//example of using a message handler from the inject scripts
//joinCart('d37dfc49-205d-4bb4-b83d-0af2f6b3c47f')

chrome.extension.onMessage.addListener(
    function (request, sender, sendResponse) {
        if (request && request.fn && cart && cart[request.fn]) {
            cart[request.fn](request, function (err, data) {
                return sendResponse(data);
            });
        }
        return true;
    });<|endoftext|>


<commit_before>(function() {
  var create_date, create_fields, days_in_month, image_added, open_edit_image;
  image_added = function(image, chunk) {
    var dynamic_items, id, image_id, img, new_list, target;
    image_id = $(image).attr('id').replace('image_', '');
    new_list = $("li.empty_" + chunk).clone();
    new_list.find('input').next().val(image_id);
    new_list.find('span').html($(image).attr('alt'));
    id = parseInt(image_id + Math.random() * 101);
    $('input', new_list).each(function(i, input) {
      input = $(input);
      input.attr('name', input.attr('name').replace(/images_attributes\]\[[\d]+/, "images_attributes][" + id));
      return input.attr('id', input.attr('id').replace(/images_attributes_[\d]+/, "images_attributes_" + id));
    });
    img = $("").attr({
      title: $(image).attr('title'),
      alt: $(image).attr('alt'),
      src: $(image).attr('data-grid')
    }).appendTo(new_list);
    dynamic_items = new_list.find("#dynamic_items");
    dynamic_items.attr('id', "dynamic_items_" + image_id);
    dynamic_items.find("input").val("");
    new_list.attr('id', "image_" + image_id).removeClass('empty');
    new_list.attr('id', "image_" + image_id).removeClass("empty_" + chunk);
    new_list.show();
    target = "#page_images_" + chunk;
    return new_list.appendTo(target);
  };
  jQuery(function() {
    $('.edit_image').live('click', function() {
      var image_id, items;
      image_id = $(this).parents().parents().attr('id').replace('image_', '');
      items = $(this).parents().parents().find("#dynamic_items_" + image_id)[0];
      return open_edit_image(items, image_id);
    });
    $('.delete_image').live('click', function() {
      var rm;
      rm = confirm("Are you sure delete this image?");
      if (rm === true) {
        return $(this).parents('li').first().remove();
      } else {
        return false;
      }
    });
    $('li.image_field').live('hover', function() {
      var chunk;
      chunk = $(this).find('input').first().val();
      return $("#page_images_" + chunk).sortable();
    });
    return $("#month, #year").live('change', function() {
      var month, year;
      year = $("#year").find(":selected").val();
      month = $("#month").find(":selected").val();
      return days_in_month(year, month);
    });
  });
  open_edit_image = function(items, image_id) {
    var fields, input;
    fields = $(items).clone();
    input = fields.find('input');
    input.each(function(i, inp) {
      var field, title, type, value;
      title = $(inp).attr('data-name');
      type = $(inp).attr('data-type');
      value = $(inp).val();
      field = create_fields(type, value);
      return $(inp).after($("
" + title + "" + field + "
"));
    });
    input.after($("

Insert

"));
    fields.dialog({
      title: "Edit Image Fields",
      modal: true,
      resizable: false,
      autoOpen: true,
      width: 800,
      height: 500,
      close: function() {
        return setTimeout(function() {
          return fields.remove();
        }, 500);
      }
    });
    $('a.ui-dialog-titlebar-close').click(function() {
      return fields.dialog('close');
    });
    return $('a#insert_fields').click(function() {
      input.each(function(i, inp) {
        var date, date_value, field, hour, input_val, minute, title, type;
        title = $(inp).attr('data-name');
        type = $(inp).attr('data-type');
        if (type === "string" || type === "integer" || type === "float" || type === "decimal") {
          field = "input";
        } else if (type === "boolean") {
          field = "input-checkbox";
        } else if (type === "text") {
          field = "textarea";
        } else if (type === "date" || type === "datetime") {
          field = "select";
        }
        input_val = $(items).find("input[data-name='" + title + "']");
        if (field === "select") {
          date_value = [];
          $("div#image" + image_id + "_title_" + title).find("" + field).each(function() {
            return date_value.push($(this).val());
          });
          date = "" + date_value[0] + "-" + date_value[1] + "-" + date_value[2];
          hour = date_value[3];
          minute = date_value[4];
          if (hour) {
            date = "" + date + " " + hour + ":" + minute;
          }
          input_val.val(date);
        } else if (field === "input-checkbox") {
          field = field.split("-");
          if ($("div#image" + image_id + "_title_" + title).find("" + field[0]).is(":checked")) {
            input_val.val("true");
          } else {
            input_val.val("false");
          }
        } else {
          input_val.val($("div#image" + image_id + "_title_" + title).find("" + field).val());
        }
        return fields.dialog('close');
      });
      return fields.remove();
    });
  };
  create_fields = function(type, value) {
    var checked, field;
    switch (type) {
      case "string":
      case "integer":
      case "float":
      case "decimal":
        return field = "<input class='image-edit' type='text' value='" + value + "' />";
      case "boolean":
        checked = '';
        if (value === "true") {
          checked = "checked";
        }
        return field = "<input class='image-edit-checkbox' type='checkbox' " + checked + " />";
      case "text":
        return field = "<textarea class='image-edit'>" + value + "</textarea>";
      case "date":
        if (value) {
          value = value.split("-");
          return field = "<select id='year'><option></option>" + (create_date(2010, 2030, 'year', value[0])) + "</select>                 <select id='month'><option></option>" + (create_date(1, 12, 'month', value[1])) + "</select>                 <select id='day'><option></option>" + (create_date(1, '', 'day', value)) + "</select>";
        } else {
          return field = "<select id='year'><option></option>" + (create_date(2010, 2030, 'year')) + "</select>                 <select id='month'><option></option>" + (create_date(1, 12, 'month')) + "</select>                 <select id='day'><option></option>" + (create_date(1, '', 'day')) + "</select>";
        }
        break;
      case "datetime":
        if (value) {
          value = value.split("-");
          return field = "<select id='year'><option></option>" + (create_date(2010, 2030, 'year', value[0])) + "</select>                 <select id='month'><option></option>" + (create_date(1, 12, 'month', value[1])) + "</select>                 <select id='day'><option></option>" + (create_date(1, '', 'day', value)) + "</select>                 <select id='hour'><option></option>" + (create_date(00, 23, 'hour', value.join("-"))) + "</select>                 <select id='minute'><option></option>" + (create_date(00, 59, 'minute', value.join("-"))) + "</select>";
        } else {
          return field = "<select name='date[0]' id='year'><option></option>" + (create_date(2010, 2030, 'year')) + "</select>                 <select name='date[1]' id='month'><option></option>" + (create_date(1, 12, 'month')) + "</select>                 <select name='date[2]' id='day'><option></option>" + (create_date(1, '', 'day')) + "</select>                 <select name='date[3]' id='hour'><option></option>" + (create_date(00, 23, 'hour')) + "</select>                 <select name='date[4]' id='minute'><option></option>" + (create_date(00, 59, 'minute')) + "</select>";
        }
    }
  };
  create_date = function(init, end, obj_id, value) {
    var day, month, selected, year, _ref, _ref2, _results;
    if (obj_id === 'day' && !value) {
      year = new Date().getFullYear();
      month = new Date().getMonth();
      end = new Date(year, month + 1, 0).getDate();
    } else if (obj_id === 'day' && value) {
      year = new Date(value).getFullYear();
      month = new Date(value).getMonth() + 1;
      day = new Date(value).getDate();
      end = new Date(year, month, 0).getDate();
    }
    _results = [];
    for (init = _ref = init, _ref2 = end; _ref <= _ref2 ? init <= _ref2 : init >= _ref2; _ref <= _ref2 ? init++ : init--) {
      selected = '';
      if (value) {
        if (obj_id === 'year' && init === new Date(value, 1).getFullYear()) {
          selected = 'selected';
        }
        if (obj_id === 'month' && init === new Date(0, value).getMonth()) {
          selected = 'selected';
        }
        if (obj_id === 'day' && init === new Date(year, month, day).getDate()) {
          selected = 'selected';
        }
        if (obj_id === 'hour' && init === new Date(value).getUTCHours()) {
          selected = 'selected';
        }
        if (obj_id === 'minute' && init === new Date(value).getUTCMinutes()) {
          selected = 'selected';
        }
      }
      _results.push("<option value='" + init + "' " + selected + " >" + init + "</option>");
    }
    return _results;
  };
  days_in_month = function(year, month) {
    var end, init, _ref, _ref2, _results;
    $("#day").empty();
    init = 1;
    end = new Date(year, month, 0).getDate();
    _results = [];
    for (init = _ref = init, _ref2 = end; _ref <= _ref2 ? init <= _ref2 : init >= _ref2; _ref <= _ref2 ? init++ : init--) {
      _results.push($("#day").append("<option value='" + init + "'>" + init + "</option>"));
    }
    return _results;
  };
}).call(this);
<commit_msg>Fix gallery javascript without bare<commit_after>var create_date, create_fields, days_in_month, image_added, open_edit_image;
image_added = function(image, chunk) {
  var dynamic_items, id, image_id, img, new_list, target;
  image_id = $(image).attr('id').replace('image_', '');
  new_list = $("li.empty_" + chunk).clone();
  new_list.find('input').next().val(image_id);
  new_list.find('span').html($(image).attr('alt'));
  id = parseInt(image_id + Math.random() * 101);
  $('input', new_list).each(function(i, input) {
    input = $(input);
    input.attr('name', input.attr('name').replace(/images_attributes\]\[[\d]+/, "images_attributes][" + id));
    return input.attr('id', input.attr('id').replace(/images_attributes_[\d]+/, "images_attributes_" + id));
  });
  img = $("").attr({
    title: $(image).attr('title'),
    alt: $(image).attr('alt'),
    src: $(image).attr('data-grid')
  }).appendTo(new_list);
  dynamic_items = new_list.find("#dynamic_items");
  dynamic_items.attr('id', "dynamic_items_" + image_id);
  dynamic_items.find("input").val("");
  new_list.attr('id', "image_" + image_id).removeClass('empty');
  new_list.attr('id', "image_" + image_id).removeClass("empty_" + chunk);
  new_list.show();
  target = "#page_images_" + chunk;
  return new_list.appendTo(target);
};
jQuery(function() {
  $('.edit_image').live('click', function() {
    var image_id, items;
    image_id = $(this).parents().parents().attr('id').replace('image_', '');
    items = $(this).parents().parents().find("#dynamic_items_" + image_id)[0];
    return open_edit_image(items, image_id);
  });
  $('.delete_image').live('click', function() {
    var rm;
    rm = confirm("Are you sure delete this image?");
    if (rm === true) {
      return $(this).parents('li').first().remove();
    } else {
      return false;
    }
  });
  $('li.image_field').live('hover', function() {
    var chunk;
    chunk = $(this).find('input').first().val();
    return $("#page_images_" + chunk).sortable();
  });
  return $("#month, #year").live('change', function() {
    var month, year;
    year = $("#year").find(":selected").val();
    month = $("#month").find(":selected").val();
    return days_in_month(year, month);
  });
});
open_edit_image = function(items, image_id) {
  var fields, input;
  fields = $(items).clone();
  input = fields.find('input');
  input.each(function(i, inp) {
    var field, title, type, value;
    title = $(inp).attr('data-name');
    type = $(inp).attr('data-type');
    value = $(inp).val();
    field = create_fields(type, value);
    return $(inp).after($("
" + title + "" + field + "
"));
  });
  input.after($("

Insert

"));
  fields.dialog({
    title: "Edit Image Fields",
    modal: true,
    resizable: false,
    autoOpen: true,
    width: 800,
    height: 500,
    close: function() {
      return setTimeout(function() {
        return fields.remove();
      }, 500);
    }
  });
  $('a.ui-dialog-titlebar-close').click(function() {
    return fields.dialog('close');
  });
  return $('a#insert_fields').click(function() {
    return input.each(function(i, inp) {
      var date, date_value, field, hour, input_val, minute, title, type;
      title = $(inp).attr('data-name');
      type = $(inp).attr('data-type');
      if (type === "string" || type === "integer" || type === "float" || type === "decimal") {
        field = "input";
      } else if (type === "boolean") {
        field = "input-checkbox";
      } else if (type === "text") {
        field = "textarea";
      } else if (type === "date" || type === "datetime") {
        field = "select";
      }
      input_val = $(items).find("input[data-name='" + title + "']");
      if (field === "select") {
        date_value = [];
        $("div#image" + image_id + "_title_" + title).find("" + field).each(function() {
          return date_value.push($(this).val());
        });
        date = "" + date_value[0] + "-" + date_value[1] + "-" + date_value[2];
        hour = date_value[3];
        minute = date_value[4];
        if (hour) {
          date = "" + date + " " + hour + ":" + minute;
        }
        input_val.val(date);
      } else if (field === "input-checkbox") {
        field = field.split("-");
        if ($("div#image" + image_id + "_title_" + title).find("" + field[0]).is(":checked")) {
          input_val.val("true");
        } else {
          input_val.val("false");
        }
      } else {
        input_val.val($("div#image" + image_id + "_title_" + title).find("" + field).val());
      }
      return fields.dialog('close');
    });
  });
};
create_fields = function(type, value) {
  var checked, field;
  switch (type) {
    case "string":
    case "integer":
    case "float":
    case "decimal":
      return field = "<input class='image-edit' type='text' value='" + value + "' />";
    case "boolean":
      checked = '';
      if (value === "true") {
        checked = "checked";
      }
      return field = "<input class='image-edit-checkbox' type='checkbox' " + checked + " />";
    case "text":
      return field = "<textarea class='image-edit'>" + value + "</textarea>";
    case "date":
      if (value) {
        value = value.split("-");
        return field = "<select id='year'><option></option>" + (create_date(2010, 2030, 'year', value[0])) + "</select>                 <select id='month'><option></option>" + (create_date(1, 12, 'month', value[1])) + "</select>                 <select id='day'><option></option>" + (create_date(1, '', 'day', value)) + "</select>";
      } else {
        return field = "<select id='year'><option></option>" + (create_date(2010, 2030, 'year')) + "</select>                 <select id='month'><option></option>" + (create_date(1, 12, 'month')) + "</select>                 <select id='day'><option></option>" + (create_date(1, '', 'day')) + "</select>";
      }
      break;
    case "datetime":
      if (value) {
        value = value.split("-");
        return field = "<select id='year'><option></option>" + (create_date(2010, 2030, 'year', value[0])) + "</select>                 <select id='month'><option></option>" + (create_date(1, 12, 'month', value[1])) + "</select>                 <select id='day'><option></option>" + (create_date(1, '', 'day', value)) + "</select>                 <select id='hour'><option></option>" + (create_date(00, 23, 'hour', value.join("-"))) + "</select>                 <select id='minute'><option></option>" + (create_date(00, 59, 'minute', value.join("-"))) + "</select>";
      } else {
        return field = "<select name='date[0]' id='year'><option></option>" + (create_date(2010, 2030, 'year')) + "</select>                 <select name='date[1]' id='month'><option></option>" + (create_date(1, 12, 'month')) + "</select>                 <select name='date[2]' id='day'><option></option>" + (create_date(1, '', 'day')) + "</select>                 <select name='date[3]' id='hour'><option></option>" + (create_date(00, 23, 'hour')) + "</select>                 <select name='date[4]' id='minute'><option></option>" + (create_date(00, 59, 'minute')) + "</select>";
      }
  }
};
create_date = function(init, end, obj_id, value) {
  var day, month, selected, year, _ref, _ref2, _results;
  if (obj_id === 'day' && !value) {
    year = new Date().getFullYear();
    month = new Date().getMonth();
    end = new Date(year, month + 1, 0).getDate();
  } else if (obj_id === 'day' && value) {
    year = new Date(value).getFullYear();
    month = new Date(value).getMonth() + 1;
    day = new Date(value).getDate();
    end = new Date(year, month, 0).getDate();
  }
  _results = [];
  for (init = _ref = init, _ref2 = end; _ref <= _ref2 ? init <= _ref2 : init >= _ref2; _ref <= _ref2 ? init++ : init--) {
    selected = '';
    if (value) {
      if (obj_id === 'year' && init === new Date(value, 1).getFullYear()) {
        selected = 'selected';
      }
      if (obj_id === 'month' && init === new Date(0, value).getMonth()) {
        selected = 'selected';
      }
      if (obj_id === 'day' && init === new Date(year, month, day).getDate()) {
        selected = 'selected';
      }
      if (obj_id === 'hour' && init === new Date(value).getUTCHours()) {
        selected = 'selected';
      }
      if (obj_id === 'minute' && init === new Date(value).getUTCMinutes()) {
        selected = 'selected';
      }
    }
    _results.push("<option value='" + init + "' " + selected + " >" + init + "</option>");
  }
  return _results;
};
days_in_month = function(year, month) {
  var end, init, _ref, _ref2, _results;
  $("#day").empty();
  init = 1;
  end = new Date(year, month, 0).getDate();
  _results = [];
  for (init = _ref = init, _ref2 = end; _ref <= _ref2 ? init <= _ref2 : init >= _ref2; _ref <= _ref2 ? init++ : init--) {
    _results.push($("#day").append("<option value='" + init + "'>" + init + "</option>"));
  }
  return _results;
};<|endoftext|>


<commit_before>var cheerio = require('cheerio');
var $;
var URI = require('URIjs');
var he = require('he');
var crypto = require('crypto');
var log = require('./log');

//var _config;
var Parser = function() {}

Parser.prototype.init = function(options) {
    this._targets = options.targets;
    this._blacklist = options.blacklist;
    this._siteUri = new URI(options.url);
    this._cache = {};
    this._cacheFile = {};
}

Parser.prototype.load = function(html, config, url) {
    log.verbose('[Parser] Load html and inject config');
    $ = cheerio.load(html);
    _config = config;
}

Parser.prototype.getLinks = function() {
    log.verbose('[Parser] Get links');

    var links = [];
    var selector = 'a[rel!=nofollow]';
    var blacklist = this._blacklist;
    var siteUri = this._siteUri;
    var cache = this._cache;
    var cacheFile = this._cacheFile;

    if (blacklist.classes !== undefined) {
        selector += ':not(' + blacklist.classes.join(',') + ')';
    }

    $(selector).each(function() {
        var url = $(this).attr('href');

        // Skip links that has no href
        if (url === undefined || !url) {
            var outerHTML = $('
').append($(this)).html();
            log.debug('[Parser] No link: ' + outerHTML);
            return;
        }
        url = url.trim();
        log.silly('[Parser] Found url: ' + url);

        // Skip blacklisted paths
        if (blacklist.paths !== undefined) {
            for (var i = 0; i < blacklist.paths.length; i++) {
                if (url.indexOf(blacklist.paths[i]) !== -1) {
                    log.debug('[Parser] Skip ignored path (' + blacklist.paths[i] + '): ' + url);
                    return;
                }
            }
        }

        var uri = URI(url);

        // Prepend domain to relative path (Example: )
        if (uri.is('relative')) {
            uri.protocol(siteUri.protocol()).hostname(siteUri.hostname());
        }

        // Skip external links
        if (uri.hostname() !== siteUri.hostname()) {
            log.debug('[Parser] Skip external link: ' + url);
            return;
        }

        // Skip media files
        if (uri.suffix().match(/jpg|jpeg|png|gif|bmp|svg|pdf/i) !== null) {
            log.debug('[Parser] Skip media file: ' + url);
            return;
        }

        // Remove anchor (Example: http://domain/page.html#anchor)
        uri.hash('');

        // Remove trailing slash (Example: http://domain/section/) -> important?

        url = uri.normalize().toString();
        log.silly('[Parser] Processed: ' + url);

        // Skip previously downloaded pages
        var md5 = crypto.createHash('md5').update(url).digest('hex');
        if (cache[md5] === undefined) {
            cache[md5] = true;
            log.silly('[Parser] Send to queue');
        } else {
            log.silly('[Parser] Already fetched');
            return;
        }

        // Skip previously downloaded filenames
        if (uri.filename()) {
            var md5file = crypto.createHash('md5').update(uri.filename()).digest('hex');
            if (cacheFile[md5file] === undefined) {
                cacheFile[md5file] = [ url ];
            } else {
                cacheFile[md5file].push(url);
                log.warn(cacheFile[md5file]);
                return;
            }
        }

        links.push(url);
    });

    if (links.length) {
        log.verbose('[Parser] ' + links.length + ' new links');
        return links;
    } else {
        log.verbose('[Parser] No new links');
        return false;
    }

}

Parser.prototype.getData = function(obj) {
    log.verbose('[Parser] Parse content of ' + obj.url);
    $ = cheerio.load(obj.html);
    obj.web = {};
    pageParser(null, obj.config.targets, obj.web);
    log.debug(obj.web);
    return obj;
}

function pageParser($container, targets, data, depth) {
    depth = depth || 1;
    var logPrefix = '[Parser] ' + Array(depth).join("    ") + '';
    log.silly(logPrefix + 'Depth: ' + depth);
    for (var i = 0; i < targets.length; i++) {
        var target = targets[i];

        // Support single and multiple elements. Ex: '.foobar' and ['.foo', '.bar']
        var elements = Array.isArray(target.elem) ? target.elem : [ target.elem ];

        var $elem;
        if (target.ifelse) {
            // Only use the first found element in array
            for (var l = 0; l < elements.length; l++) {
                $elem = $container !== null ? $(elements[l], $container) : $(elements[l]);
                if ($elem.length) { break; }
            }
        } else {
            $elem = $container !== null ? $(elements.join(','), $container) : $(elements.join(','));
        }

        var msg = target.type + ': ' + target.elem + (target.name ? ' (' + target.name + ')' : '');
        if ($elem.length === 0) {
            if (target.miss) {
                var $missing = $container !== null ? $(target.miss, $container) : $(target.miss);
                if ($missing.length) {
                    continue;
                }
            } else if (target.optional) {
                continue;
            }
            log.warn('[Parser] Couldn\'t find ' + msg);
            continue;
        }

        log.silly(logPrefix + 'Found ' + msg);
        var key = target.name;
        if (target.type == 'container') {
            if (!key) {
                pageParser($elem, target.children, data, depth + 1);
            } else if ($elem.length > 1) {
                log.silly(logPrefix + 'Name: ' + key);
                $elem.each(function() {
                    if (data[key] === undefined) {
                        data[key] = [];
                    }
                    var obj = {};
                    data[key].push(obj);
                    pageParser($(this), target.children, obj, depth + 1);
                });
            } else {
                data[key] = {};
                log.silly(logPrefix + 'Name: ' + key);
                pageParser($elem, target.children, data[key], depth + 1);
            }
        } else if (target.type == 'data') {
            // Get value(s) from the data attribute, a custom attribute or content of tag
            var values = [];
            $elem.each(function() {
                if (target.data) {
                    // Ex:

                    var data = Array.isArray(target.data) ? target.data : [ target.data ];
                    for (var j = 0; j < data.length; j++) {
                        values.push($(this).data(data[j]));
                    }
                } else if (target.attr) {
                    // Ex: , foo
                    values.push($(this).attr(target.attr));
                } else if (target.text) {
                    // Ex:
valueskip this

                    values.push($(this).contents().filter(function() { return this.nodeType == 3; } ).text()); // 3 = TEXT_NODE
                } else {
                    // Ex:

value 1

value 2

,
value

                    var value = target.tags ? $(this).html() : $(this).text();
                    values.push(value.trim());
                }
            });

            // Run functions defined in config on found values
            if (target.func) {
                var functions = Array.isArray(target.func) ? target.func : [ target.func ];
                for (var j = 0; j < functions.length; j++) {
                    var name = functions[j].name;
                    var args = functions[j].args;
                    for (var k = 0; k < values.length; k++) {
                        var value = values[k];
                        values[k] = _functions[name](value, args);
                        log.silly(logPrefix + 'Run function: ' + name + (args ? ' (' + value + ', ' + JSON.stringify(args) + ')' : ''));
                    }
                }
            }

            // Store found and processed values in data structure
            if (values.length > 1) {
                // Support joining of values
                if (target.glue) {
                    log.silly(logPrefix + 'Glue: ' + values.length + ' items joined with "' + target.glue + '"');
                    values = values.join(target.glue);
                }
                data[key] = data[key] ? Array.concat(data[key], values) : values; // join values with same name
            } else if (values.length) {
                data[key] = data[key] ? values.concat(data[key]) : values.pop(); // join values with same name
            }
        }
    }
}

// Parse functions
var _functions = {
    regexp: function(value, args) {
        var matches = value.match(new RegExp(args[0]));
        if (matches) {
            return args[1] ? matches[args[1]] : matches;
        } else {
            return null;
        }
    },
    prepend: function(value, text) {
        return text + value;
    },
    append: function(value, text) {
        return value + text;
    },
    join: function(value, args) {
        var str = '';
        for (var i = 0; i < args.length; i++) {
            if (args[i].charAt(0) === '$') {
                if (Array.isArray(value)) {
                    var index = parseInt(args[i].substr(1));
                    str += value[index];
                }
                else {
                    str += value;
                }
            }
            else {
                str += args[i];
            }
        }
        return str;
    },
    replace: function(value, args) {
        // Check if pattern is a regex or string
        var pattern = args[2] && args[2] == 'regexp' ? new RegExp(args[0], 'g') : args[0];
        return value.replace(pattern, args[1]);
    },
    toInt: function(value) {
        return /^\d+$/.test(value) ? parseInt(value, 10) : false;
    },
    parsePrice: function(price, args) {
        // Example inputs: "kr 2.347,95", "969 NOK", "625 kr.", "449.0" (number)
        price = price.toString().replace(/[^\d,.]/g, ''); // strip everything except numbers, "," and "."
        var match = price.match(/^([\d,.]+)[.,](\d{1,2})$/); // split price on decimals if they exist
        if (match) {
            price = match[1].replace(/[,.]/g, ''); // strip "," and "." from the part before the decimals
            price = Math.round(price + '.' + match[2]); // add decimals and round
        } else {
            price = parseInt(price.replace(/[,.]/g, ''), 10); // strip "," and "." and convert to int
        }
        if (args && args.addVat) {
            price *= 1.25; // Add MVA/VAT
        }
        return price;
    },
    htmlEntitiesDecode: function(value) {
        return he.decode(value);
    }
}

module.exports = Parser;
<commit_msg>Add check on no html for cheerio<commit_after>var cheerio = require('cheerio');
var $;
var URI = require('URIjs');
var he = require('he');
var crypto = require('crypto');
var log = require('./log');

//var _config;
var Parser = function() {}

Parser.prototype.init = function(options) {
    this._targets = options.targets;
    this._blacklist = options.blacklist;
    this._siteUri = new URI(options.url);
    this._cache = {};
    this._cacheFile = {};
}

Parser.prototype.load = function(html, config, url) {
    log.verbose('[Parser] Load html and inject config');
    $ = cheerio.load(html);
    _config = config;
}

Parser.prototype.getLinks = function() {
    log.verbose('[Parser] Get links');

    var links = [];
    var selector = 'a[rel!=nofollow]';
    var blacklist = this._blacklist;
    var siteUri = this._siteUri;
    var cache = this._cache;
    var cacheFile = this._cacheFile;

    if (blacklist.classes !== undefined) {
        selector += ':not(' + blacklist.classes.join(',') + ')';
    }

    $(selector).each(function() {
        var url = $(this).attr('href');

        // Skip links that has no href
        if (url === undefined || !url) {
            var outerHTML = $('
').append($(this)).html();
            log.debug('[Parser] No link: ' + outerHTML);
            return;
        }
        url = url.trim();
        log.silly('[Parser] Found url: ' + url);

        // Skip blacklisted paths
        if (blacklist.paths !== undefined) {
            for (var i = 0; i < blacklist.paths.length; i++) {
                if (url.indexOf(blacklist.paths[i]) !== -1) {
                    log.debug('[Parser] Skip ignored path (' + blacklist.paths[i] + '): ' + url);
                    return;
                }
            }
        }

        var uri = URI(url);

        // Prepend domain to relative path (Example: )
        if (uri.is('relative')) {
            uri.protocol(siteUri.protocol()).hostname(siteUri.hostname());
        }

        // Skip external links
        if (uri.hostname() !== siteUri.hostname()) {
            log.debug('[Parser] Skip external link: ' + url);
            return;
        }

        // Skip media files
        if (uri.suffix().match(/jpg|jpeg|png|gif|bmp|svg|pdf/i) !== null) {
            log.debug('[Parser] Skip media file: ' + url);
            return;
        }

        // Remove anchor (Example: http://domain/page.html#anchor)
        uri.hash('');

        // Remove trailing slash (Example: http://domain/section/) -> important?

        url = uri.normalize().toString();
        log.silly('[Parser] Processed: ' + url);

        // Skip previously downloaded pages
        var md5 = crypto.createHash('md5').update(url).digest('hex');
        if (cache[md5] === undefined) {
            cache[md5] = true;
            log.silly('[Parser] Send to queue');
        } else {
            log.silly('[Parser] Already fetched');
            return;
        }

        // Skip previously downloaded filenames
        if (uri.filename()) {
            var md5file = crypto.createHash('md5').update(uri.filename()).digest('hex');
            if (cacheFile[md5file] === undefined) {
                cacheFile[md5file] = [ url ];
            } else {
                cacheFile[md5file].push(url);
                log.warn(cacheFile[md5file]);
                return;
            }
        }

        links.push(url);
    });

    if (links.length) {
        log.verbose('[Parser] ' + links.length + ' new links');
        return links;
    } else {
        log.verbose('[Parser] No new links');
        return false;
    }

}

Parser.prototype.getData = function(obj) {
    log.verbose('[Parser] Parse content of ' + obj.url);
    if (!obj.html) {
        log.error('[Parser] No html for: ' + obj.url);
        return obj;
    }
    $ = cheerio.load(obj.html);
    obj.web = {};
    pageParser(null, obj.config.targets, obj.web);
    log.debug(obj.web);
    return obj;
}

function pageParser($container, targets, data, depth) {
    depth = depth || 1;
    var logPrefix = '[Parser] ' + Array(depth).join("    ") + '';
    log.silly(logPrefix + 'Depth: ' + depth);
    for (var i = 0; i < targets.length; i++) {
        var target = targets[i];

        // Support single and multiple elements. Ex: '.foobar' and ['.foo', '.bar']
        var elements = Array.isArray(target.elem) ? target.elem : [ target.elem ];

        var $elem;
        if (target.ifelse) {
            // Only use the first found element in array
            for (var l = 0; l < elements.length; l++) {
                $elem = $container !== null ? $(elements[l], $container) : $(elements[l]);
                if ($elem.length) { break; }
            }
        } else {
            $elem = $container !== null ? $(elements.join(','), $container) : $(elements.join(','));
        }

        var msg = target.type + ': ' + target.elem + (target.name ? ' (' + target.name + ')' : '');
        if ($elem.length === 0) {
            if (target.miss) {
                var $missing = $container !== null ? $(target.miss, $container) : $(target.miss);
                if ($missing.length) {
                    continue;
                }
            } else if (target.optional) {
                continue;
            }
            log.warn('[Parser] Couldn\'t find ' + msg);
            continue;
        }

        log.silly(logPrefix + 'Found ' + msg);
        var key = target.name;
        if (target.type == 'container') {
            if (!key) {
                pageParser($elem, target.children, data, depth + 1);
            } else if ($elem.length > 1) {
                log.silly(logPrefix + 'Name: ' + key);
                $elem.each(function() {
                    if (data[key] === undefined) {
                        data[key] = [];
                    }
                    var obj = {};
                    data[key].push(obj);
                    pageParser($(this), target.children, obj, depth + 1);
                });
            } else {
                data[key] = {};
                log.silly(logPrefix + 'Name: ' + key);
                pageParser($elem, target.children, data[key], depth + 1);
            }
        } else if (target.type == 'data') {
            // Get value(s) from the data attribute, a custom attribute or content of tag
            var values = [];
            $elem.each(function() {
                if (target.data) {
                    // Ex:

                    var data = Array.isArray(target.data) ? target.data : [ target.data ];
                    for (var j = 0; j < data.length; j++) {
                        values.push($(this).data(data[j]));
                    }
                } else if (target.attr) {
                    // Ex: , foo
                    values.push($(this).attr(target.attr));
                } else if (target.text) {
                    // Ex:
valueskip this

                    values.push($(this).contents().filter(function() { return this.nodeType == 3; } ).text()); // 3 = TEXT_NODE
                } else {
                    // Ex:

value 1

value 2

,
value

                    var value = target.tags ? $(this).html() : $(this).text();
                    values.push(value.trim());
                }
            });

            // Run functions defined in config on found values
            if (target.func) {
                var functions = Array.isArray(target.func) ? target.func : [ target.func ];
                for (var j = 0; j < functions.length; j++) {
                    var name = functions[j].name;
                    var args = functions[j].args;
                    for (var k = 0; k < values.length; k++) {
                        var value = values[k];
                        values[k] = _functions[name](value, args);
                        log.silly(logPrefix + 'Run function: ' + name + (args ? ' (' + value + ', ' + JSON.stringify(args) + ')' : ''));
                    }
                }
            }

            // Store found and processed values in data structure
            if (values.length > 1) {
                // Support joining of values
                if (target.glue) {
                    log.silly(logPrefix + 'Glue: ' + values.length + ' items joined with "' + target.glue + '"');
                    values = values.join(target.glue);
                }
                data[key] = data[key] ? Array.concat(data[key], values) : values; // join values with same name
            } else if (values.length) {
                data[key] = data[key] ? values.concat(data[key]) : values.pop(); // join values with same name
            }
        }
    }
}

// Parse functions
var _functions = {
    regexp: function(value, args) {
        var matches = value.match(new RegExp(args[0]));
        if (matches) {
            return args[1] ? matches[args[1]] : matches;
        } else {
            return null;
        }
    },
    prepend: function(value, text) {
        return text + value;
    },
    append: function(value, text) {
        return value + text;
    },
    join: function(value, args) {
        var str = '';
        for (var i = 0; i < args.length; i++) {
            if (args[i].charAt(0) === '$') {
                if (Array.isArray(value)) {
                    var index = parseInt(args[i].substr(1));
                    str += value[index];
                }
                else {
                    str += value;
                }
            }
            else {
                str += args[i];
            }
        }
        return str;
    },
    replace: function(value, args) {
        // Check if pattern is a regex or string
        var pattern = args[2] && args[2] == 'regexp' ? new RegExp(args[0], 'g') : args[0];
        return value.replace(pattern, args[1]);
    },
    toInt: function(value) {
        return /^\d+$/.test(value) ? parseInt(value, 10) : false;
    },
    parsePrice: function(price, args) {
        // Example inputs: "kr 2.347,95", "969 NOK", "625 kr.", "449.0" (number)
        price = price.toString().replace(/[^\d,.]/g, ''); // strip everything except numbers, "," and "."
        var match = price.match(/^([\d,.]+)[.,](\d{1,2})$/); // split price on decimals if they exist
        if (match) {
            price = match[1].replace(/[,.]/g, ''); // strip "," and "." from the part before the decimals
            price = Math.round(price + '.' + match[2]); // add decimals and round
        } else {
            price = parseInt(price.replace(/[,.]/g, ''), 10); // strip "," and "." and convert to int
        }
        if (args && args.addVat) {
            price *= 1.25; // Add MVA/VAT
        }
        return price;
    },
    htmlEntitiesDecode: function(value) {
        return he.decode(value);
    }
}

module.exports = Parser;
<|endoftext|>


<commit_before>"use strict";

//TODO: background.jsからurlの変更messageを受取る
//TODO: item_content数分のoriginal_urlを取得
//TODO: item_contentのitem_linkを書き換える
//TODO: item_linkのclickイベントを奪取
<commit_msg>inject.jsでbackground.jsからmessageを受け取り<commit_after>"use strict";

//TODO: background.jsからurlの変更messageを受取る
//TODO: item_content数分のoriginal_urlを取得
//TODO: item_contentのitem_linkを書き換える
//TODO: item_linkのclickイベントを奪取

chrome.runtime.onMessage.addListener(function (req) {
  switch (req.type) {
    case "RUN":
      console.log('発火');
      run();
      break;
    default:
      console.log("Error: Unknown request. : ", req);
  }
});

const run = () => {
  let urls = document.getElementsByClassName('original_url');
  console.log(urls[0].href);

};
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Sankarsan Kampa
 *                    https://sankarsankampa.com/contact
 *
 * This file is a part of Bastion Discord BOT.
 *                        https://github.com/snkrsnkampa/Bastion
 *
 * This code is licensed under the SNKRSN Shared License. It is free to
 * download, copy, compile, use, study and refer under the terms of the
 * SNKRSN Shared License. You can modify the code only for personal or
 * internal use only. However, you can not redistribute the code without
 * explicitly getting permission fot it.
 *
 * Bastion BOT is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY. See the SNKRSN Shared License for
 * more details.
 *
 * You should have received a copy of the SNKRSN Shared License along
 * with this program. If not, see <https://github.com/snkrsnkampa/Bastion/LICENSE>.
 */

exports.run = function(Bastion, message, args) {
  if (Bastion.credentials.ownerId.indexOf(message.author.id) < 0) return Bastion.log.info('You don\'t have permissions to use this command.');

  try {
    var evaled = eval(args.join(' '));
    if (typeof evaled !== 'string') evaled = require('util').inspect(evaled);
    message.delete().then(() => {
      message.channel.sendMessage('', {embed: {
        color: 5088314,
        fields: [
          {
            name: ':inbox_tray:  INPUT',
            value: `\`\`\`js\n${args.join(' ')}\n\`\`\``
          },
          {
            name: ':outbox_tray:  OUTPUT',
            value: `\`\`\`js\n${clean(evaled)}\n\`\`\``
          }
        ]
      }}).catch(e => {
        Bastion.log.error(e.stack);
      });
    }).catch(e => {
      Bastion.log.error(e.stack);
    });
  }
  catch(e) {
    message.delete().then(() => {
      message.channel.sendMessage('', {embed: {
        color: 13380644,
        fields: [
          {
            name: ':no_entry:  ERROR',
            value: `\`\`\`js\n${clean(e)}\n\`\`\``
          }
        ]
      }}).catch(e => {
        Bastion.log.error(e.stack);
      });
    }).catch(e => {
      Bastion.log.error(e.stack);
    });
  }
};

exports.conf = {
  aliases: []
};

exports.help = {
  name: 'eval',
  description: 'Evaluates any JavaScript statement.',
  permission: '',
  usage: ['eval message.guild.members.size']
};

function clean(text) {
  if (typeof(text) === 'string') return text.replace(/`/g, '`' + String.fromCharCode(8203)).replace(/@/g, '@' + String.fromCharCode(8203));
  else return text;
}
<commit_msg>Safer eval<commit_after>/*
 * Copyright (C) 2017 Sankarsan Kampa
 *                    https://sankarsankampa.com/contact
 *
 * This file is a part of Bastion Discord BOT.
 *                        https://github.com/snkrsnkampa/Bastion
 *
 * This code is licensed under the SNKRSN Shared License. It is free to
 * download, copy, compile, use, study and refer under the terms of the
 * SNKRSN Shared License. You can modify the code only for personal or
 * internal use only. However, you can not redistribute the code without
 * explicitly getting permission fot it.
 *
 * Bastion BOT is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY. See the SNKRSN Shared License for
 * more details.
 *
 * You should have received a copy of the SNKRSN Shared License along
 * with this program. If not, see <https://github.com/snkrsnkampa/Bastion/LICENSE>.
 */

exports.run = function(Bastion, message, args) {
  if (Bastion.credentials.ownerId.indexOf(message.author.id) < 0) return Bastion.log.info('You don\'t have permissions to use this command.');

  try {
    var evaled = eval(args.join(' '));
    if (typeof evaled !== 'string') evaled = require('util').inspect(evaled);
    message.delete().then(() => {
      message.channel.sendMessage('', {embed: {
        color: 5088314,
        fields: [
          {
            name: ':inbox_tray:  INPUT',
            value: `\`\`\`js\n${args.join(' ')}\n\`\`\``
          },
          {
            name: ':outbox_tray:  OUTPUT',
            value: `\`\`\`js\n${clean(Bastion, evaled)}\n\`\`\``
          }
        ]
      }}).catch(e => {
        Bastion.log.error(e.stack);
      });
    }).catch(e => {
      Bastion.log.error(e.stack);
    });
  }
  catch(e) {
    message.delete().then(() => {
      message.channel.sendMessage('', {embed: {
        color: 13380644,
        fields: [
          {
            name: ':no_entry:  ERROR',
            value: `\`\`\`js\n${clean(Bastion, e)}\n\`\`\``
          }
        ]
      }}).catch(e => {
        Bastion.log.error(e.stack);
      });
    }).catch(e => {
      Bastion.log.error(e.stack);
    });
  }
};

exports.conf = {
  aliases: []
};

exports.help = {
  name: 'eval',
  description: 'Evaluates any JavaScript statement.',
  permission: '',
  usage: ['eval message.guild.members.size']
};

function clean(Bastion, text) {
  if (text.includes(Bastion.token)) text = text.replace(Bastion.token, 'Not for your :eyes:!');
  if (typeof(text) === 'string') return text.replace(/`/g, '`' + String.fromCharCode(8203)).replace(/@/g, '@' + String.fromCharCode(8203));
  else return text;
}
<|endoftext|>


<commit_before>// tempart templating library

;(function(tempartParser) {
	////-----------------------------------------------------------------------------------------
	// id generator for the blocks, needs to be global because of the recusion
	tempartParser._increment = 0;
	////-----------------------------------------------------------------------------------------
	// which things are reserved words
	tempartParser.defined = ['if', 'each', 'variable', 'echo', 'log'];
	////-----------------------------------------------------------------------------------------
	// defines what commands need an {{/end}}
	tempartParser.needsEnd = ['if', 'each'];
	////-----------------------------------------------------------------------------------------
	// Precompiles the html and generates json-arrays
	tempartParser.parse = function(templateContent) {
		this._increment = 0;
		templateContent = this._escapeSpecials(templateContent);

		if(templateContent.indexOf('{{') === 0) {
			templateContent = templateContent.slice(2, templateContent.length);
		} else {
			templateContent = this._addEcho(templateContent);
		}
		// @TODO add check if open-blocks are the same as end-blocks
		var searches = templateContent.split('{{');
		return this._parseBlocks(searches).content;
	};
	////-----------------------------------------------------------------------------------------
	// takes an array of commands
	tempartParser._parseBlocks = function(blocks) {
		var result = [];
		var end    = null;
		while(blocks.length) {
			var block = this._parseBlock(blocks);
			if(block == 'end' || block == 'else') { // @TODO improve!
				end = block;
				break;
			} else if(block) {
				block.id = this._increment;
				result.push(block);
			}
			this._increment++;
		}
		return {content: result, end: end};
	};
	////-----------------------------------------------------------------------------------------
	// parses one command and adds new ones if needed
	tempartParser._parseBlock = function(blocks) {
		var block = blocks[0];
		var result = {};
		var end = this._getEnd(block);
		var type = block.slice(0, end).split(' ');
		if(type[0][0] == '/') {
			// @TODO add for debugging purpose a check if this was the one which was last opened
			result = 'end';
		} else if(type[0] == 'else') {
			result = 'else';
		} else if(this.defined.indexOf(type[0]) == -1) {
			result.type = 'variable';
			result.depending = [type[0]];
		} else {
			result.type    = type[0];
			type.shift();
			result.depending = type;
			if(result.type == 'echo') {
				result.content = block.slice(end + 2, block.length);
			}
		}
		blocks.shift();

		this._handleOverlength(block, blocks);
		this._handleElse(result, blocks);

		return result;
	};
	////-----------------------------------------------------------------------------------------
	// Checks if an block-has the {{else}} possibility and adds elseContains
	tempartParser._handleElse = function(result, blocks) {
		if(this.needsEnd.indexOf(result.type) != -1) {
			var contains = this._parseBlocks(blocks);
			if(contains) {
				result.contains = contains.content;
				if(contains.end == 'else') {
					result.elseContains = this._parseBlocks(blocks).content;
				} else {
					result.elseContains = [];
				}
			}
		}
	};
	////-----------------------------------------------------------------------------------------
	// Checks if an block has an html-string behind it
	tempartParser._handleOverlength = function(block, blocks) {
		var end = this._getEnd(block);
		if(block.length > end + 2 && block.slice(0, end) != 'echo') { // Handling of not-variable stuff
			blocks.unshift(this._addEcho(block.slice(end + 2, block.length)));
		}
	};
	////-----------------------------------------------------------------------------------------
	// plain html without any variable
	tempartParser._addEcho = function(echo) {
		return 'echo}}' +  echo;
	};
	////-----------------------------------------------------------------------------------------
	// returns int on which position the }} are existent
	tempartParser._getEnd = function(block) {
		return block.indexOf('}}');
	};
	////-----------------------------------------------------------------------------------------
	// escaping backslashes, single quotes, and newlines
	tempartParser._escapeSpecials = function(templateContent) {
		return templateContent.replace(/\\/g, '\\\\').replace(/\'/g, '\\\'').replace(/\n/g, '\\n').replace(/\r/g, '');
	};
}(typeof module == 'object' ? module.exports : window.tempartParser = {}));
<commit_msg>[parser] removed escaping - did weird shit<commit_after>// tempart templating library

;(function(tempartParser) {
	////-----------------------------------------------------------------------------------------
	// id generator for the blocks, needs to be global because of the recusion
	tempartParser._increment = 0;
	////-----------------------------------------------------------------------------------------
	// which things are reserved words
	tempartParser.defined = ['if', 'each', 'variable', 'echo', 'log'];
	////-----------------------------------------------------------------------------------------
	// defines what commands need an {{/end}}
	tempartParser.needsEnd = ['if', 'each'];
	////-----------------------------------------------------------------------------------------
	// Precompiles the html and generates json-arrays
	tempartParser.parse = function(templateContent) {
		this._increment = 0;
		templateContent = this._escapeSpecials(templateContent);

		if(templateContent.indexOf('{{') === 0) {
			templateContent = templateContent.slice(2, templateContent.length);
		} else {
			templateContent = this._addEcho(templateContent);
		}
		// @TODO add check if open-blocks are the same as end-blocks
		var searches = templateContent.split('{{');
		return this._parseBlocks(searches).content;
	};
	////-----------------------------------------------------------------------------------------
	// takes an array of commands
	tempartParser._parseBlocks = function(blocks) {
		var result = [];
		var end    = null;
		while(blocks.length) {
			var block = this._parseBlock(blocks);
			if(block == 'end' || block == 'else') { // @TODO improve!
				end = block;
				break;
			} else if(block) {
				block.id = this._increment;
				result.push(block);
			}
			this._increment++;
		}
		return {content: result, end: end};
	};
	////-----------------------------------------------------------------------------------------
	// parses one command and adds new ones if needed
	tempartParser._parseBlock = function(blocks) {
		var block = blocks[0];
		var result = {};
		var end = this._getEnd(block);
		var type = block.slice(0, end).split(' ');
		if(type[0][0] == '/') {
			// @TODO add for debugging purpose a check if this was the one which was last opened
			result = 'end';
		} else if(type[0] == 'else') {
			result = 'else';
		} else if(this.defined.indexOf(type[0]) == -1) {
			result.type = 'variable';
			result.depending = [type[0]];
		} else {
			result.type    = type[0];
			type.shift();
			if(type.length) result.depending = type;
			if(result.type == 'echo') {
				result.content = block.slice(end + 2, block.length);
			}
		}
		blocks.shift();

		this._handleOverlength(block, blocks);
		this._handleElse(result, blocks);

		return result;
	};
	////-----------------------------------------------------------------------------------------
	// Checks if an block-has the {{else}} possibility and adds elseContains
	tempartParser._handleElse = function(result, blocks) {
		if(this.needsEnd.indexOf(result.type) != -1) {
			var contains = this._parseBlocks(blocks);
			if(contains) {
				result.contains = contains.content;
				if(contains.end == 'else') {
					result.elseContains = this._parseBlocks(blocks).content;
				} else {
					result.elseContains = [];
				}
			}
		}
	};
	////-----------------------------------------------------------------------------------------
	// Checks if an block has an html-string behind it
	tempartParser._handleOverlength = function(block, blocks) {
		var end = this._getEnd(block);
		if(block.length > end + 2 && block.slice(0, end) != 'echo') { // Handling of not-variable stuff
			blocks.unshift(this._addEcho(block.slice(end + 2, block.length)));
		}
	};
	////-----------------------------------------------------------------------------------------
	// plain html without any variable
	tempartParser._addEcho = function(echo) {
		return 'echo}}' +  echo;
	};
	////-----------------------------------------------------------------------------------------
	// returns int on which position the }} are existent
	tempartParser._getEnd = function(block) {
		return block.indexOf('}}');
	};
	////-----------------------------------------------------------------------------------------
	// escaping backslashes, single quotes, and newlines
	tempartParser._escapeSpecials = function(templateContent) {
		return templateContent;
		// return templateContent.replace(/\\/g, '\\\\').replace(/\'/g, '\\\'').replace(/\r/g, '');
	};
}(typeof module == 'object' ? module.exports : window.tempartParser = {}));
<|endoftext|>


<commit_before>/**
 * @fileOverview Low level JSGI adapter implementation.
 */

var {Headers, getMimeParameter} = require('ringo/utils/http');
var {Stream} = require('io');
var {Binary, ByteString} = require('binary');
var system = require('system')

export('handleRequest', 'writeHeaders');
var log = require('ringo/logging').getLogger(module.id);

/**
 * Handle a JSGI request.
 * @param moduleId the module id. Ignored if functionObj is already a function.
 * @param functionObj the function, either as function object or function name to be
 *             imported from the module moduleId.
 * @param req the JSGI request object
 * @returns the JSGI response object
 */
function handleRequest(moduleId, functionObj, request) {
    initRequest(request);
    var app;
    if (typeof(functionObj) === 'function') {
        app = functionObj;
    } else {
        var module = require(moduleId);
        app = module[functionObj];
        var middleware = module.middleware || [];
        request.env.ringo_config = moduleId;
        app = middleware.reduceRight(middlewareWrapper, resolve(app));
    }
    // if RINGO_ENV environment variable is set and application supports
    // modular JSGI environment feature use the proper environment
    if (app && system.env.RINGO_ENV && typeof(app.env) === 'function') {
        app = app.env(system.env.RINGO_ENV);
    }
    if (typeof(app) !== 'function') {
        throw new Error('No valid JSGI app: ' + app);
    }
    var result = app(request);
    if (!result) {
        throw new Error('No valid JSGI response: ' + result);
    }
    commitResponse(request, result);
}

/**
 * Set up the I/O related properties of a jsgi environment object.
 * @param env a jsgi request object
 */
function initRequest(request) {
    var input, errors;
    if (request.hasOwnProperty('input')) {
        // already set up, probably because the original request threw a retry
        return;
    }
    Object.defineProperty(request, "input", {
        get: function() {
            if (!input)
                input = new Stream(request.env.servletRequest.getInputStream());
            return input;
        }
    });
    Object.defineProperty(request.jsgi, "errors", {
        value: system.stderr
    });
}

/**
 * Apply the return value of a JSGI application to a servlet response.
 * This is used internally by the org.ringojs.jsgi.JsgiServlet class, so
 * you won't need this unless you're implementing your own servlet
 * based JSGI connector.
 *
 * @param req the JSGI request argument
 * @param result the object returned by a JSGI application
 */
function commitResponse(req, result) {
    var request = req.env.servletRequest;
    var response = req.env.servletResponse;
    var {status, headers, body} = result;
    if (!status || !headers || !body) {
        // Check if this is an asynchronous response. If not throw an Error
        if (handleAsyncResponse(request, response, result)) {
            return;
        } else {
            throw new Error('No valid JSGI response: ' + result);
        }
    }
    // Allow application/middleware to handle request via Servlet API
    if (!response.isCommitted() && !Headers(headers).contains("X-JSGI-Skip-Response")) {
        writeResponse(response, status, headers, body);
    }
}

function writeResponse(servletResponse, status, headers, body) {
    servletResponse.setStatus(status);
    writeHeaders(servletResponse, headers);
    var charset = getMimeParameter(headers.get("Content-Type"), "charset");
    writeBody(servletResponse, body, charset);
}

function writeHeaders(servletResponse, headers) {
    for (var key in headers) {
        var values = headers[key];
        if (typeof values === "string") {
            values = values.split("\n");
        } else if (!Array.isArray(values)) {
            continue;
        }
        values.forEach(function(value) {
            servletResponse.addHeader(key, value);
        });
    }
}

function writeBody(response, body, charset) {
    if (body && typeof body.forEach == "function") {
        var output = response.getOutputStream();
        var writer = function(part) {
            if (!(part instanceof Binary)) {
                part = part.toByteString(charset);
            }
            output.write(part);
        };
        body.forEach(writer);
        if (typeof body.close == "function") {
            body.close(writer);
        }
    } else {
        throw new Error("Response body doesn't implement forEach: " + body);
    }
}

function writeAsync(servletResponse, jsgiResponse) {
    if (!jsgiResponse.status || !jsgiResponse.headers || !jsgiResponse.body) {
        throw new Error('No valid JSGI response: ' + jsgiResponse);
    }
    var {status, headers, body} = jsgiResponse;
    writeResponse(servletResponse, status, Headers(headers), body);
}

function handleAsyncResponse(request, response, result) {
    // support for asynchronous JSGI based on Jetty continuations
    // If result has a "suspend" method we just call it and return, letting
    // the response take care of everything
    if (typeof result.suspend === "function") {
        result.suspend();
        return true;
    }
    // As a convenient shorthand, allow apps to return the deferred as returned
    // by ringo.promise.defer()
    if (result.promise && typeof result.promise.then === "function") {
        result = result.promise;
    }
    // Only handle asynchronously if the result has a then() function
    if (typeof result.then !== "function") {
        return false;
    }

    var {ContinuationSupport, ContinuationListener} = org.eclipse.jetty.continuation;
    var continuation = ContinuationSupport.getContinuation(request);
    var handled = false;

    var onFinish = sync(function(value) {
        if (handled) return;
        log.debug("JSGI async response finished", value);
        handled = true;
        writeAsync(continuation.getServletResponse(), value);
        continuation.complete();
    }, request);

    var onError = sync(function(error) {
        if (handled) return;
        log.error("JSGI async error", error);
        var jsgiResponse = {
            status: 500,
            headers: {"Content-Type": "text/html"},
            body: ["<!DOCTYPE html>
Error

", String(error), "
"]
        };
        handled = true;
        writeAsync(continuation.getServletResponse(), jsgiResponse);
        continuation.complete();
    }, request);

    continuation.addContinuationListener(new ContinuationListener({
        onTimeout: sync(function() {
            if (handled) return;
            log.error("JSGI async timeout");
            var jsgiResponse = {
                status: 500,
                headers: {"Content-Type": "text/html"},
                body: ["<!DOCTYPE html>
Error

Request timed out
"]
            };
            handled = true;
            writeAsync(continuation.getServletResponse(), jsgiResponse);
            continuation.complete();
        }, request)
    }));

    log.debug('handling JSGI async response, calling then');
    sync(function() {
        result.then(onFinish, onError);
        // default async request timeout is 30 seconds
        continuation.setTimeout(result.timeout || 30000);
        continuation.suspend(response);
    }, request)();
    return true;
}

/**
 * Convenience function that resolves a module id or object to a
 * JSGI middleware or application function. This assumes the function is
 * exported as "middleware" or "handleRequest".
 * @param app a function, module object, module id, or an array of
 *            any of these
 * @returns the resolved middleware function
 */
function resolve(app) {
    if (typeof app == 'string') {
        var module = require(app);
        return module.middleware || module.handleRequest;
    } else if (Array.isArray(app)) {
        // allow an app or middleware item to be itself a list of middlewares
        return app.reduceRight(middlewareWrapper);
    }
    return app;
}

/**
 * Helper function for wrapping middleware stacks
 * @param inner an app or middleware module or function wrapped by outer
 * @param outer a middleware module or function wrapping inner
 * @returns the wrapped middleware function
 */
function middlewareWrapper(inner, outer) {
    return resolve(outer)(inner);
}
<commit_msg>Throw better error if Jetty continuations are not available in async response handling.<commit_after>/**
 * @fileOverview Low level JSGI adapter implementation.
 */

var {Headers, getMimeParameter} = require('ringo/utils/http');
var {Stream} = require('io');
var {Binary, ByteString} = require('binary');
var system = require('system')

export('handleRequest', 'writeHeaders');
var log = require('ringo/logging').getLogger(module.id);

/**
 * Handle a JSGI request.
 * @param moduleId the module id. Ignored if functionObj is already a function.
 * @param functionObj the function, either as function object or function name to be
 *             imported from the module moduleId.
 * @param req the JSGI request object
 * @returns the JSGI response object
 */
function handleRequest(moduleId, functionObj, request) {
    initRequest(request);
    var app;
    if (typeof(functionObj) === 'function') {
        app = functionObj;
    } else {
        var module = require(moduleId);
        app = module[functionObj];
        var middleware = module.middleware || [];
        request.env.ringo_config = moduleId;
        app = middleware.reduceRight(middlewareWrapper, resolve(app));
    }
    // if RINGO_ENV environment variable is set and application supports
    // modular JSGI environment feature use the proper environment
    if (app && system.env.RINGO_ENV && typeof(app.env) === 'function') {
        app = app.env(system.env.RINGO_ENV);
    }
    if (typeof(app) !== 'function') {
        throw new Error('No valid JSGI app: ' + app);
    }
    var result = app(request);
    if (!result) {
        throw new Error('No valid JSGI response: ' + result);
    }
    commitResponse(request, result);
}

/**
 * Set up the I/O related properties of a jsgi environment object.
 * @param env a jsgi request object
 */
function initRequest(request) {
    var input, errors;
    if (request.hasOwnProperty('input')) {
        // already set up, probably because the original request threw a retry
        return;
    }
    Object.defineProperty(request, "input", {
        get: function() {
            if (!input)
                input = new Stream(request.env.servletRequest.getInputStream());
            return input;
        }
    });
    Object.defineProperty(request.jsgi, "errors", {
        value: system.stderr
    });
}

/**
 * Apply the return value of a JSGI application to a servlet response.
 * This is used internally by the org.ringojs.jsgi.JsgiServlet class, so
 * you won't need this unless you're implementing your own servlet
 * based JSGI connector.
 *
 * @param req the JSGI request argument
 * @param result the object returned by a JSGI application
 */
function commitResponse(req, result) {
    var request = req.env.servletRequest;
    var response = req.env.servletResponse;
    var {status, headers, body} = result;
    if (!status || !headers || !body) {
        // Check if this is an asynchronous response. If not throw an Error
        if (handleAsyncResponse(request, response, result)) {
            return;
        } else {
            throw new Error('No valid JSGI response: ' + result);
        }
    }
    // Allow application/middleware to handle request via Servlet API
    if (!response.isCommitted() && !Headers(headers).contains("X-JSGI-Skip-Response")) {
        writeResponse(response, status, headers, body);
    }
}

function writeResponse(servletResponse, status, headers, body) {
    servletResponse.setStatus(status);
    writeHeaders(servletResponse, headers);
    var charset = getMimeParameter(headers.get("Content-Type"), "charset");
    writeBody(servletResponse, body, charset);
}

function writeHeaders(servletResponse, headers) {
    for (var key in headers) {
        var values = headers[key];
        if (typeof values === "string") {
            values = values.split("\n");
        } else if (!Array.isArray(values)) {
            continue;
        }
        values.forEach(function(value) {
            servletResponse.addHeader(key, value);
        });
    }
}

function writeBody(response, body, charset) {
    if (body && typeof body.forEach == "function") {
        var output = response.getOutputStream();
        var writer = function(part) {
            if (!(part instanceof Binary)) {
                part = part.toByteString(charset);
            }
            output.write(part);
        };
        body.forEach(writer);
        if (typeof body.close == "function") {
            body.close(writer);
        }
    } else {
        throw new Error("Response body doesn't implement forEach: " + body);
    }
}

function writeAsync(servletResponse, jsgiResponse) {
    if (!jsgiResponse.status || !jsgiResponse.headers || !jsgiResponse.body) {
        throw new Error('No valid JSGI response: ' + jsgiResponse);
    }
    var {status, headers, body} = jsgiResponse;
    writeResponse(servletResponse, status, Headers(headers), body);
}

function handleAsyncResponse(request, response, result) {
    // support for asynchronous JSGI based on Jetty continuations
    // If result has a "suspend" method we just call it and return, letting
    // the response take care of everything
    if (typeof result.suspend === "function") {
        result.suspend();
        return true;
    }
    // As a convenient shorthand, allow apps to return the deferred as returned
    // by ringo.promise.defer()
    if (result.promise && typeof result.promise.then === "function") {
        result = result.promise;
    }
    // Only handle asynchronously if the result has a then() function
    if (typeof result.then !== "function") {
        return false;
    }

    var {ContinuationSupport, ContinuationListener} = org.eclipse.jetty.continuation;
    var continuation = ContinuationSupport.getContinuation(request);
    if (!continuation) {
        throw new Error("Jetty continuation support required for asynchronous "
                      + "response is not available");
    }
    var handled = false;

    var onFinish = sync(function(value) {
        if (handled) return;
        log.debug("JSGI async response finished", value);
        handled = true;
        writeAsync(continuation.getServletResponse(), value);
        continuation.complete();
    }, request);

    var onError = sync(function(error) {
        if (handled) return;
        log.error("JSGI async error", error);
        var jsgiResponse = {
            status: 500,
            headers: {"Content-Type": "text/html"},
            body: ["<!DOCTYPE html>
Error

", String(error), "
"]
        };
        handled = true;
        writeAsync(continuation.getServletResponse(), jsgiResponse);
        continuation.complete();
    }, request);

    continuation.addContinuationListener(new ContinuationListener({
        onTimeout: sync(function() {
            if (handled) return;
            log.error("JSGI async timeout");
            var jsgiResponse = {
                status: 500,
                headers: {"Content-Type": "text/html"},
                body: ["<!DOCTYPE html>
Error

Request timed out
"]
            };
            handled = true;
            writeAsync(continuation.getServletResponse(), jsgiResponse);
            continuation.complete();
        }, request)
    }));

    log.debug('handling JSGI async response, calling then');
    sync(function() {
        result.then(onFinish, onError);
        // default async request timeout is 30 seconds
        continuation.setTimeout(result.timeout || 30000);
        continuation.suspend(response);
    }, request)();
    return true;
}

/**
 * Convenience function that resolves a module id or object to a
 * JSGI middleware or application function. This assumes the function is
 * exported as "middleware" or "handleRequest".
 * @param app a function, module object, module id, or an array of
 *            any of these
 * @returns the resolved middleware function
 */
function resolve(app) {
    if (typeof app == 'string') {
        var module = require(app);
        return module.middleware || module.handleRequest;
    } else if (Array.isArray(app)) {
        // allow an app or middleware item to be itself a list of middlewares
        return app.reduceRight(middlewareWrapper);
    }
    return app;
}

/**
 * Helper function for wrapping middleware stacks
 * @param inner an app or middleware module or function wrapped by outer
 * @param outer a middleware module or function wrapping inner
 * @returns the wrapped middleware function
 */
function middlewareWrapper(inner, outer) {
    return resolve(outer)(inner);
}
<|endoftext|>