<commit_before>/**
 * Created by ksinger on 10.05.2016.
 */

import angular from "angular";
import postIsOrSeeksInfoModule from "./post-is-or-seeks-info.js";
import labelledHrModule from "./labelled-hr.js";
import postContentGeneral from "./post-content-general.js";
import postHeaderModule from "./post-header.js";
import trigModule from "./trig.js";
import { attach, getIn, get } from "../utils.js";
import won from "../won-es6.js";
import { labels } from "../won-label-utils.js";
import { connect2Redux } from "../won-utils.js";
import * as needUtils from "../need-utils.js";
import * as connectionSelectors from "../selectors/connection-selectors.js";
import { getConnectionUriFromRoute } from "../selectors/general-selectors.js";
import { actionCreators } from "../actions/actions.js";
import { classOnComponentRoot } from "../cstm-ng-utils.js";
import ngAnimate from "angular-animate";

import "style/_post-content.scss";
import "style/_rdflink.scss";

const serviceDependencies = ["$ngRedux", "$scope", "$element"];
function genComponentConf() {
  let template = `

          <svg class="post-failedtoload__icon">
              <use xlink:href="#ico16_indicator_error" href="#ico16_indicator_error"></use>
          </svg>

              Failed To Load - Need might have been deleted

            <button class="post-failedtoload__actions__button red won-button--outlined thin"
                ng-click="self.tryReload()">
                Try Reload
            </button>

          <won-post-is-or-seeks-info branch="::'content'" ng-if="self.hasContent" post-uri="self.post.get('uri')"></won-post-is-or-seeks-info>
          <won-labelled-hr label="::'Search'" class="cp__labelledhr" ng-show="self.hasContent && self.hasSeeksBranch"></won-labelled-hr>
          <won-post-is-or-seeks-info branch="::'seeks'" ng-if="self.hasSeeksBranch" post-uri="self.post.get('uri')"></won-post-is-or-seeks-info>

          <won-labelled-hr label="::'Group Members'" class="cp__labelledhr" ng-if="self.hasGroupMembers"></won-labelled-hr>

              <won-post-header
                class="clickable"
                ng-click="self.router__stateGoCurrent({viewNeedUri: memberUri})"
                need-uri="::memberUri">
              </won-post-header>

          <won-labelled-hr label="::'Suggestions'" class="cp__labelledhr" ng-if="self.hasSuggestions"></won-labelled-hr>

                <won-post-header
                  class="clickable"
                  ng-click="self.connections__markAsRead({connectionUri: conn.get('uri'), needUri: self.post.get('uri')}) && self.router__stateGoCurrent({viewNeedUri: conn.get('remoteNeedUri')})"
                  need-uri="::conn.get('remoteNeedUri')">
                </won-post-header>

                        Request

                        Remove

          <won-labelled-hr label="::'Posts of this Persona'" class="cp__labelledhr" ng-if="self.isPersona && self.hasHeldPosts"></won-labelled-hr>

              <won-post-header
                class="clickable"
                ng-click="self.router__stateGoCurrent({viewNeedUri: heldPostUri})"
                need-uri="::heldPostUri">
              </won-post-header>

          <won-labelled-hr ng-click="self.toggleShowGeneral()" arrow="self.showGeneral ? 'up' : 'down'" label="::'General Information'" class="cp__labelledhr"></won-labelled-hr>
          <won-post-content-general class="post-collapsible-general" ng-if="self.showGeneral" post-uri="self.post.get('uri')"></won-post-content-general>

                RDF

                  <svg class="rdflink__small">
                      <use xlink:href="#rdf_logo_1" href="#rdf_logo_1"></use>
                  </svg>
                  Post

                  <svg class="rdflink__small">
                      <use xlink:href="#rdf_logo_1" href="#rdf_logo_1"></use>
                  </svg>
                  Connection

            <won-trig
              ng-if="self.post.get('jsonld')"
              jsonld="self.post.get('jsonld')">
            </won-trig>

    `;

  class Controller {
    constructor() {
      attach(this, serviceDependencies, arguments);
      this.labels = labels;

      window.postcontent4dbg = this;

      const selectFromState = state => {
        const openConnectionUri = getConnectionUriFromRoute(state);
        const post = getIn(state, ["needs", this.postUri]);
        const isPersona = needUtils.isPersona(post);
        const isOwned = needUtils.isOwned(post);
        const content = post ? post.get("content") : undefined;

        //TODO it will be possible to have more than one seeks
        const seeks = get(post, "seeks");

        const hasContent = this.hasVisibleDetails(content);
        const hasSeeksBranch = this.hasVisibleDetails(seeks);

        const groupMembers = get(post, "groupMembers");

        const heldPosts = get(post, "holds");

        const suggestions = connectionSelectors.getSuggestedConnectionsByNeedUri(
          state,
          this.postUri
        );

        return {
          WON: won.WON,
          hasContent,
          hasSeeksBranch,
          post,
          isPersona,
          hasHeldPosts: isPersona && heldPosts && heldPosts.size > 0,
          heldPostsArray: isPersona && heldPosts && heldPosts.toArray(),
          hasGroupMembers: groupMembers && groupMembers.size > 0,
          groupMembersArray: groupMembers && groupMembers.toArray(),
          hasSuggestions: isOwned && suggestions && suggestions.size > 0,
          suggestionsArray: isOwned && suggestions && suggestions.toArray(),
          postLoading:
            !post ||
            getIn(state, ["process", "needs", post.get("uri"), "loading"]),
          postFailedToLoad:
            post &&
            getIn(state, ["process", "needs", post.get("uri"), "failedToLoad"]),
          createdTimestamp: post && post.get("creationDate"),
          shouldShowRdf: state.getIn(["view", "showRdf"]),
          fromConnection: !!openConnectionUri,
          openConnectionUri,
          showGeneral: state.getIn([
            "view",
            "needs",
            this.postUri,
            "showGeneralInfo",
          ]),
        };
      };
      connect2Redux(selectFromState, actionCreators, ["self.postUri"], this);

      classOnComponentRoot("won-is-loading", () => this.postLoading, this);
    }

    tryReload() {
      if (this.postUri && this.postFailedToLoad) {
        this.needs__fetchUnloadedNeed(this.postUri);
      }
    }

    closeConnection(connUri, rateBad = false) {
      rateBad && this.connections__rate(connUri, won.WON.binaryRatingBad);
      this.connections__close(connUri);
    }

    sendRequest(connUri, remoteNeedUri, message) {
      this.connections__rate(connUri, won.WON.binaryRatingGood);
      this.needs__connect(
        this.groupPostAdminUri,
        connUri,
        remoteNeedUri,
        message
      );
    }

    toggleShowGeneral() {
      this.needs__toggleGeneralInfo(this.postUri);
    }

    /**
     * This function checks if there is at least one detail present that is displayable
     */
    hasVisibleDetails(contentBranchImm) {
      return (
        contentBranchImm &&
        contentBranchImm.find(
          (detailValue, detailKey) =>
            detailKey != "type" &&
            detailKey != "facets" &&
            detailKey != "defaultFacet"
        )
      );
    }
  }

  Controller.$inject = serviceDependencies;
  return {
    restrict: "E",
    controller: Controller,
    controllerAs: "self",
    bindToController: true, //scope-bindings -> ctrl
    template: template,
    scope: {
      postUri: "=",
    },
  };
}

export default angular
  .module("won.owner.components.postContent", [
    ngAnimate,
    postIsOrSeeksInfoModule,
    labelledHrModule,
    postContentGeneral,
    postHeaderModule,
    trigModule,
  ])
  .directive("wonPostContent", genComponentConf).name;
<commit_msg>Adds TODO:<commit_after>/**
 * Created by ksinger on 10.05.2016.
 */

import angular from "angular";
import postIsOrSeeksInfoModule from "./post-is-or-seeks-info.js";
import labelledHrModule from "./labelled-hr.js";
import postContentGeneral from "./post-content-general.js";
import postHeaderModule from "./post-header.js";
import trigModule from "./trig.js";
import { attach, getIn, get } from "../utils.js";
import won from "../won-es6.js";
import { labels } from "../won-label-utils.js";
import { connect2Redux } from "../won-utils.js";
import * as needUtils from "../need-utils.js";
import * as connectionSelectors from "../selectors/connection-selectors.js";
import { getConnectionUriFromRoute } from "../selectors/general-selectors.js";
import { actionCreators } from "../actions/actions.js";
import { classOnComponentRoot } from "../cstm-ng-utils.js";
import ngAnimate from "angular-animate";

import "style/_post-content.scss";
import "style/_rdflink.scss";

const serviceDependencies = ["$ngRedux", "$scope", "$element"];
function genComponentConf() {
  let template = `

          <svg class="post-failedtoload__icon">
              <use xlink:href="#ico16_indicator_error" href="#ico16_indicator_error"></use>
          </svg>

              Failed To Load - Need might have been deleted

            <button class="post-failedtoload__actions__button red won-button--outlined thin"
                ng-click="self.tryReload()">
                Try Reload
            </button>

          <won-post-is-or-seeks-info branch="::'content'" ng-if="self.hasContent" post-uri="self.post.get('uri')"></won-post-is-or-seeks-info>
          <won-labelled-hr label="::'Search'" class="cp__labelledhr" ng-show="self.hasContent && self.hasSeeksBranch"></won-labelled-hr>
          <won-post-is-or-seeks-info branch="::'seeks'" ng-if="self.hasSeeksBranch" post-uri="self.post.get('uri')"></won-post-is-or-seeks-info>

          <won-labelled-hr label="::'Group Members'" class="cp__labelledhr" ng-if="self.hasGroupMembers"></won-labelled-hr>

              <won-post-header
                class="clickable"
                ng-click="self.router__stateGoCurrent({viewNeedUri: memberUri})"
                need-uri="::memberUri">
              </won-post-header>

          <won-labelled-hr label="::'Suggestions'" class="cp__labelledhr" ng-if="self.hasSuggestions"></won-labelled-hr>

                <won-post-header
                  class="clickable"
                  ng-click="self.connections__markAsRead({connectionUri: conn.get('uri'), needUri: self.post.get('uri')}) && self.router__stateGoCurrent({viewNeedUri: conn.get('remoteNeedUri')})"
                  need-uri="::conn.get('remoteNeedUri')">
                </won-post-header>

                        Request

                        Remove

          <won-labelled-hr label="::'Posts of this Persona'" class="cp__labelledhr" ng-if="self.isPersona && self.hasHeldPosts"></won-labelled-hr>

              <won-post-header
                class="clickable"
                ng-click="self.router__stateGoCurrent({viewNeedUri: heldPostUri})"
                need-uri="::heldPostUri">
              </won-post-header>

          <won-labelled-hr ng-click="self.toggleShowGeneral()" arrow="self.showGeneral ? 'up' : 'down'" label="::'General Information'" class="cp__labelledhr"></won-labelled-hr>
          <won-post-content-general class="post-collapsible-general" ng-if="self.showGeneral" post-uri="self.post.get('uri')"></won-post-content-general>

                RDF

                  <svg class="rdflink__small">
                      <use xlink:href="#rdf_logo_1" href="#rdf_logo_1"></use>
                  </svg>
                  Post

                  <svg class="rdflink__small">
                      <use xlink:href="#rdf_logo_1" href="#rdf_logo_1"></use>
                  </svg>
                  Connection

            <won-trig
              ng-if="self.post.get('jsonld')"
              jsonld="self.post.get('jsonld')">
            </won-trig>

    `;

  class Controller {
    constructor() {
      attach(this, serviceDependencies, arguments);
      this.labels = labels;

      window.postcontent4dbg = this;

      const selectFromState = state => {
        const openConnectionUri = getConnectionUriFromRoute(state);
        const post = getIn(state, ["needs", this.postUri]);
        const isPersona = needUtils.isPersona(post);
        const isOwned = needUtils.isOwned(post);
        const content = post ? post.get("content") : undefined;

        //TODO it will be possible to have more than one seeks
        const seeks = get(post, "seeks");

        const hasContent = this.hasVisibleDetails(content);
        const hasSeeksBranch = this.hasVisibleDetails(seeks);

        const groupMembers = get(post, "groupMembers");

        const heldPosts = get(post, "holds");

        const suggestions = connectionSelectors.getSuggestedConnectionsByNeedUri(
          state,
          this.postUri
        );

        return {
          WON: won.WON,
          hasContent,
          hasSeeksBranch,
          post,
          isPersona,
          hasHeldPosts: isPersona && heldPosts && heldPosts.size > 0,
          heldPostsArray: isPersona && heldPosts && heldPosts.toArray(),
          hasGroupMembers: groupMembers && groupMembers.size > 0,
          groupMembersArray: groupMembers && groupMembers.toArray(),
          hasSuggestions: isOwned && suggestions && suggestions.size > 0,
          suggestionsArray: isOwned && suggestions && suggestions.toArray(),
          postLoading:
            !post ||
            getIn(state, ["process", "needs", post.get("uri"), "loading"]),
          postFailedToLoad:
            post &&
            getIn(state, ["process", "needs", post.get("uri"), "failedToLoad"]),
          createdTimestamp: post && post.get("creationDate"),
          shouldShowRdf: state.getIn(["view", "showRdf"]),
          fromConnection: !!openConnectionUri,
          openConnectionUri,
          showGeneral: state.getIn([
            "view",
            "needs",
            this.postUri,
            "showGeneralInfo",
          ]),
        };
      };
      connect2Redux(selectFromState, actionCreators, ["self.postUri"], this);

      classOnComponentRoot("won-is-loading", () => this.postLoading, this);
    }

    tryReload() {
      if (this.postUri && this.postFailedToLoad) {
        this.needs__fetchUnloadedNeed(this.postUri);
      }
    }

    closeConnection(connUri, rateBad = false) {
      rateBad && this.connections__rate(connUri, won.WON.binaryRatingBad);
      this.connections__close(connUri);
    }

    sendRequest(connUri, remoteNeedUri, message) {
      //TODO: IMPLEMENT POSSIBILITY OF ADHOC REQUEST
      this.connections__rate(connUri, won.WON.binaryRatingGood);
      this.needs__connect(this.postUri, connUri, remoteNeedUri, message);
    }

    toggleShowGeneral() {
      this.needs__toggleGeneralInfo(this.postUri);
    }

    /**
     * This function checks if there is at least one detail present that is displayable
     */
    hasVisibleDetails(contentBranchImm) {
      return (
        contentBranchImm &&
        contentBranchImm.find(
          (detailValue, detailKey) =>
            detailKey != "type" &&
            detailKey != "facets" &&
            detailKey != "defaultFacet"
        )
      );
    }
  }

  Controller.$inject = serviceDependencies;
  return {
    restrict: "E",
    controller: Controller,
    controllerAs: "self",
    bindToController: true, //scope-bindings -> ctrl
    template: template,
    scope: {
      postUri: "=",
    },
  };
}

export default angular
  .module("won.owner.components.postContent", [
    ngAnimate,
    postIsOrSeeksInfoModule,
    labelledHrModule,
    postContentGeneral,
    postHeaderModule,
    trigModule,
  ])
  .directive("wonPostContent", genComponentConf).name;
<|endoftext|>


<commit_before>/**
 * Created by ksinger on 29.06.2015.
 */

//TODO switch to requirejs for dependency mngmt (so this lib isn't angular-bound)
//TODO replace calls to `won` object to `require('util')`

(function(){ // <message-builder-js> scope
    if(!won) won = {};

    /**
     * Builds the dataset that makes up the message. The set consists of several named
     * graphs (usually `args.msgUri + '#nameOfSubgraph'`), that contain the payload-
     * and meta-data.
     * @param needRdf
     * @param args
     * @returns {{@graph: Array, @context}}
     */
    won.buildMessageRdf = function (needRdf, args) {
        var needGraphId = args.msgUri + '#need';
        var msgDataUri = args.msgUri + '#envelope';
        var msgGraph = [];

        var attachmentGraphIds = args.attachments.map(function(a, i){ return args.msgUri + '#attachment-' + i })
        var nonEnvelopeGraphIds = Array.prototype.concat([needGraphId], attachmentGraphIds);

        msgGraph.push({
            // content
            '@id': needGraphId,
            '@graph': needRdf['@graph']
        });

        args.attachments.forEach(function(attachment, i) {
            msgGraph.push({
                '@id' : attachmentGraphIds[i],
                '@graph' : [
                    {
                        // link to attachment metadata (e.g. signatures, autor-info,...)
                        // and b64-encoded attachment
                        '@id': attachment.uri,
                        // + .png to get image later (but without crypto-signature).

                        // using ContentAsBase64: http://www.w3.org/TR/Content-in-RDF10/#ContentAsBase64Class
                        'cnt:ContentAsBase64' : {
                            'cnt:bytes': attachment.data,
                            'msg:contentType': attachment.type
                            //'dct:isFormatOf : { '@id' : 'http://...png' }
                            //'dct:format' : { '@id' : 'mime:png' }
                        }
                    }
                ]
            });
        });

        var attachmentBlankNodes = args.attachments.map(function(a, i) {
            return {
                '@id': '_:attachment-' + i,
                'msg:hasDestinationUri': {'@id' : a.uri},
                'msg:hasAttachmentGraphUri': {'@id' : attachmentGraphIds[i]}
            }
        });

        var envelopeGraph = [
            {
                '@id': args.msgUri,
                '@type' : 'msg:FromOwner',
                'msg:hasSentTimestamp' : (new Date().getTime()),
                'msg:hasMessageType': { '@id': args.msgType },
                'msg:hasContent': nonEnvelopeGraphIds.map(function(graphId) {return {'@id': graphId} }),
                'msg:hasReceiverNode': { '@id': args.receiverNode },
                'msg:hasSenderNeed': { '@id': args.publishedContentUri },
                'msg:hasAttachment': attachmentBlankNodes.map(function(n) {return {'@id' : n['@id']} }),
            },
            {
                '@id': msgDataUri,
                '@type': 'msg:EnvelopeGraph',
                'rdfg:subGraphOf': { '@id': args.msgUri }
            }
        ];

        console.log('message-builder.js:buildMessageRdf:attachmentBlankNodes: ', attachmentBlankNodes);
        console.log('message-builder.js:buildMessageRdf:envelopeGraph: ', envelopeGraph.concat(attachmentBlankNodes));

        msgGraph.push({
            // msg envelope
            '@id': msgDataUri,
            '@graph': envelopeGraph.concat(attachmentBlankNodes)
        });

        /*
         //TODO in need: links to both unsigned (plain pngs) and signed (in rdf) attachments
         */

        return {
            '@graph': msgGraph,
            '@context': won.merge(
                won.defaultContext,
                needRdf['@context'],
                getTypesForContext()
            )
        }
    }

    function getTypesForContext(){
        var o = {
            //'mime' : 'http://purl.org/NET/mediatypes/',
            //'dct' : 'http://purl.org/dc/terms/',
            'cnt' : 'http://www.w3.org/2011/content#'
        };
        o[won.WONMSG.EnvelopeGraphCompacted] = {
            '@id': 'http://purl.org/webofneeds/message#EnvelopeGraph',
            '@type': '@id'
        };
        return o;
    }
})() // </message-builder-js> scope

// local loading should be fast enough -> take handles, load & resolve promises during (build()) TODO
/*

 STOPPED HERE
 1. generate uri
 2. serialise file into desired format
 3. push into arrays of uris and files (or an object or an array of objects)
 */

/*
 //TODO it should be possible to do the creation without initialising two message builders.
 --> CreateMessageBuilder that passes through calls to it's internal needmsgbuilder
 and then builds the messsage from that?
 */
/*

 problem: file-read is asynch, but i'd like to contain *all* the details
 of the message format in this class (e.g. the data's encoding) :|
 {need} --toCreateMsg--> {msg} //(async) functional instead of OO-style msgbuilder?

 where:

 need = { title: '...', ..., images: [fileHandle1, fileHandle2]  }

 this would be very implementation specific.

 */
/*
 TODO missing parameters for equivalence with old builder:

 see won-service:548f

 forEnvelopeData(?)

 hasSender
 hasSenderNode
 hasSenderNeed (used)

 hasReceiver
 hasReceiverNeed
 hasReceiverNode (used)

 hasFacet (used, in needbuilder)
 hasRemoteFacet

 hasTextMessage
 addContentGraphData(?) //who thought this was a good idea?
 */
<commit_msg>Renamed variable to communicate genericity.<commit_after>/**
 * Created by ksinger on 29.06.2015.
 */

//TODO switch to requirejs for dependency mngmt (so this lib isn't angular-bound)
//TODO replace calls to `won` object to `require('util')`

(function(){ // <message-builder-js> scope
    if(!won) won = {};

    /**
     * Builds the dataset that makes up the message. The set consists of several named
     * graphs (usually `args.msgUri + '#nameOfSubgraph'`), that contain the payload-
     * and meta-data.
     * @param contentRdf
     * @param args
     * @returns {{@graph: Array, @context}}
     */
    won.buildMessageRdf = function (contentRdf, args) {
        var needGraphId = args.msgUri + '#need';
        var msgDataUri = args.msgUri + '#envelope';
        var msgGraph = [];

        var attachmentGraphIds = args.attachments.map(function(a, i){ return args.msgUri + '#attachment-' + i })
        var nonEnvelopeGraphIds = Array.prototype.concat([needGraphId], attachmentGraphIds);

        msgGraph.push({
            // content
            '@id': needGraphId,
            '@graph': contentRdf['@graph']
        });

        args.attachments.forEach(function(attachment, i) {
            msgGraph.push({
                '@id' : attachmentGraphIds[i],
                '@graph' : [
                    {
                        // link to attachment metadata (e.g. signatures, autor-info,...)
                        // and b64-encoded attachment
                        '@id': attachment.uri,
                        // + .png to get image later (but without crypto-signature).

                        // using ContentAsBase64: http://www.w3.org/TR/Content-in-RDF10/#ContentAsBase64Class
                        'cnt:ContentAsBase64' : {
                            'cnt:bytes': attachment.data,
                            'msg:contentType': attachment.type
                            //'dct:isFormatOf : { '@id' : 'http://...png' }
                            //'dct:format' : { '@id' : 'mime:png' }
                        }
                    }
                ]
            });
        });

        var attachmentBlankNodes = args.attachments.map(function(a, i) {
            return {
                '@id': '_:attachment-' + i,
                'msg:hasDestinationUri': {'@id' : a.uri},
                'msg:hasAttachmentGraphUri': {'@id' : attachmentGraphIds[i]}
            }
        });

        var envelopeGraph = [
            {
                '@id': args.msgUri,
                '@type' : 'msg:FromOwner',
                'msg:hasSentTimestamp' : (new Date().getTime()),
                'msg:hasMessageType': { '@id': args.msgType },
                'msg:hasContent': nonEnvelopeGraphIds.map(function(graphId) {return {'@id': graphId} }),
                'msg:hasReceiverNode': { '@id': args.receiverNode },
                'msg:hasSenderNeed': { '@id': args.publishedContentUri },
                'msg:hasAttachment': attachmentBlankNodes.map(function(n) {return {'@id' : n['@id']} }),
            },
            {
                '@id': msgDataUri,
                '@type': 'msg:EnvelopeGraph',
                'rdfg:subGraphOf': { '@id': args.msgUri }
            }
        ];

        console.log('message-builder.js:buildMessageRdf:attachmentBlankNodes: ', attachmentBlankNodes);
        console.log('message-builder.js:buildMessageRdf:envelopeGraph: ', envelopeGraph.concat(attachmentBlankNodes));

        msgGraph.push({
            // msg envelope
            '@id': msgDataUri,
            '@graph': envelopeGraph.concat(attachmentBlankNodes)
        });

        /*
         //TODO in need: links to both unsigned (plain pngs) and signed (in rdf) attachments
         */

        return {
            '@graph': msgGraph,
            '@context': won.merge(
                won.defaultContext,
                contentRdf['@context'],
                getTypesForContext()
            )
        }
    }

    function getTypesForContext(){
        var o = {
            //'mime' : 'http://purl.org/NET/mediatypes/',
            //'dct' : 'http://purl.org/dc/terms/',
            'cnt' : 'http://www.w3.org/2011/content#'
        };
        o[won.WONMSG.EnvelopeGraphCompacted] = {
            '@id': 'http://purl.org/webofneeds/message#EnvelopeGraph',
            '@type': '@id'
        };
        return o;
    }
})() // </message-builder-js> scope

// local loading should be fast enough -> take handles, load & resolve promises during (build()) TODO
/*

 STOPPED HERE
 1. generate uri
 2. serialise file into desired format
 3. push into arrays of uris and files (or an object or an array of objects)
 */

/*
 //TODO it should be possible to do the creation without initialising two message builders.
 --> CreateMessageBuilder that passes through calls to it's internal needmsgbuilder
 and then builds the messsage from that?
 */
/*

 problem: file-read is asynch, but i'd like to contain *all* the details
 of the message format in this class (e.g. the data's encoding) :|
 {need} --toCreateMsg--> {msg} //(async) functional instead of OO-style msgbuilder?

 where:

 need = { title: '...', ..., images: [fileHandle1, fileHandle2]  }

 this would be very implementation specific.

 */
/*
 TODO missing parameters for equivalence with old builder:

 see won-service:548f

 forEnvelopeData(?)

 hasSender
 hasSenderNode
 hasSenderNeed (used)

 hasReceiver
 hasReceiverNeed
 hasReceiverNode (used)

 hasFacet (used, in needbuilder)
 hasRemoteFacet

 hasTextMessage
 addContentGraphData(?) //who thought this was a good idea?
 */
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const Q = require('q');
const _ = require('lodash');
const marked = require('marked');
const baseUtil = require('../../util');

const DEFAULT_MARKED_OPTIONS = {
    renderer: new marked.Renderer(),
    gfm: true,
    tables: true,
    breaks: false,
    pedantic: false,
    sanitize: true,
    smartLists: true,
    smartypants: false
};

/**
 * Transforms page content source files from markdown format to html
 * @param {Model} model - application model instance
 * @param {Object} options - task options
 * @param {Object} [options.markedOptions] - marked options for markdown parsing
 * @param {Number} [options.concurrency] - number of pages processed at the same time
 * @returns {Function}
 * @example
 * var Q = require('q');
 * var gorshochek = require('gorshochek');
 * var model = gorshochek.createModel();
 * Q()
 *    .then(tasks.core.mergeModels(model, {modelPath: './examples/model.ru.json'}))
 *    .then(tasks.docs.loadSourcesFromLocal(model))
 *    .then(tasks.docs.transformMdToHtml(model))
 *    .then(tasks.core.saveModel(model))
 *    .then(tasks.core.rsync(model, {
 *        dest: './data',
 *        exclude: ['*.meta.json', 'model.json', '*.md']
 *    }))
 *    .done();
 */
module.exports = (model, options) => {
    options = options || {};
    options.markedOptions = _.merge(DEFAULT_MARKED_OPTIONS, options.markedOptions || {});
    options.concurrency = options.concurrency || 20;

    /**
     * Returns true if given page has contentFile field
     * and value of this field ends on .md
     * @param {Object} page - model page object
     * @returns {Boolean}
     */
    function hasMarkdownSource(page) {
        return !!(page.contentFile && page.contentFile.match(/\.md$/));
    }

    /**
     * Transforms source text into html syntax.
     * @param {Object} page - page object
     * @param {String} md - markdown content of page
     * @returns {Promise}
     */
    function transform(page, md) {
        options.markedOptions.slugger && options.markedOptions.slugger.reset();

        return Q.denodeify(marked)(md, options.markedOptions)
            .catch(error => {
                console.error(`Error occur while transform md -> html for page: ${page.url}`);
                console.error(error.stack);
                throw error;
            });
    }

    function processHTML(page, html) {
        if (options.processHTML) {
            return options.processHTML(page, html);
        }

        return html;
    }

    /**
     * Transform md content of page source file into html syntax
     * @param {Model} model - data model
     * @param {Object} page - page object
     * @returns {Promise}
     */
    function processPage(model, page) {
        const sourceFilePath = page.contentFile;
        const mdFileDirectory = path.dirname(sourceFilePath);
        const htmlFilePath = path.join(mdFileDirectory, 'index.html');

        return Q(sourceFilePath)
            .then(baseUtil.readFileFromCache.bind(baseUtil))
            .then(transform.bind(null, page))
            .then(processHTML.bind(null, page))
            .then(baseUtil.writeFileToCache.bind(baseUtil, htmlFilePath))
            .then(() => {
                page.contentFile = htmlFilePath;
                return page;
            });
    }

    return () => {
        return baseUtil
            .processPagesAsync(model, hasMarkdownSource, processPage, options.concurrency)
            .thenResolve(model);
    };
};
<commit_msg>Do not sanitize markdown (#63)<commit_after>'use strict';

const path = require('path');
const Q = require('q');
const _ = require('lodash');
const marked = require('marked');
const baseUtil = require('../../util');

const DEFAULT_MARKED_OPTIONS = {
    renderer: new marked.Renderer(),
    gfm: true,
    tables: true,
    breaks: false,
    pedantic: false,
    sanitize: false,
    smartLists: true,
    smartypants: false
};

/**
 * Transforms page content source files from markdown format to html
 * @param {Model} model - application model instance
 * @param {Object} options - task options
 * @param {Object} [options.markedOptions] - marked options for markdown parsing
 * @param {Number} [options.concurrency] - number of pages processed at the same time
 * @returns {Function}
 * @example
 * var Q = require('q');
 * var gorshochek = require('gorshochek');
 * var model = gorshochek.createModel();
 * Q()
 *    .then(tasks.core.mergeModels(model, {modelPath: './examples/model.ru.json'}))
 *    .then(tasks.docs.loadSourcesFromLocal(model))
 *    .then(tasks.docs.transformMdToHtml(model))
 *    .then(tasks.core.saveModel(model))
 *    .then(tasks.core.rsync(model, {
 *        dest: './data',
 *        exclude: ['*.meta.json', 'model.json', '*.md']
 *    }))
 *    .done();
 */
module.exports = (model, options) => {
    options = options || {};
    options.markedOptions = _.merge(DEFAULT_MARKED_OPTIONS, options.markedOptions || {});
    options.concurrency = options.concurrency || 20;

    /**
     * Returns true if given page has contentFile field
     * and value of this field ends on .md
     * @param {Object} page - model page object
     * @returns {Boolean}
     */
    function hasMarkdownSource(page) {
        return !!(page.contentFile && page.contentFile.match(/\.md$/));
    }

    /**
     * Transforms source text into html syntax.
     * @param {Object} page - page object
     * @param {String} md - markdown content of page
     * @returns {Promise}
     */
    function transform(page, md) {
        options.markedOptions.slugger && options.markedOptions.slugger.reset();

        return Q.denodeify(marked)(md, options.markedOptions)
            .catch(error => {
                console.error(`Error occur while transform md -> html for page: ${page.url}`);
                console.error(error.stack);
                throw error;
            });
    }

    function processHTML(page, html) {
        if (options.processHTML) {
            return options.processHTML(page, html);
        }

        return html;
    }

    /**
     * Transform md content of page source file into html syntax
     * @param {Model} model - data model
     * @param {Object} page - page object
     * @returns {Promise}
     */
    function processPage(model, page) {
        const sourceFilePath = page.contentFile;
        const mdFileDirectory = path.dirname(sourceFilePath);
        const htmlFilePath = path.join(mdFileDirectory, 'index.html');

        return Q(sourceFilePath)
            .then(baseUtil.readFileFromCache.bind(baseUtil))
            .then(transform.bind(null, page))
            .then(processHTML.bind(null, page))
            .then(baseUtil.writeFileToCache.bind(baseUtil, htmlFilePath))
            .then(() => {
                page.contentFile = htmlFilePath;
                return page;
            });
    }

    return () => {
        return baseUtil
            .processPagesAsync(model, hasMarkdownSource, processPage, options.concurrency)
            .thenResolve(model);
    };
};
<|endoftext|>


<commit_before>/**
 * Internal healthful library API
 */

// System
var http = require('http')
var assert = require('assert')

function Healthful (opt) {
    // Options object
    opt = opt || {}
    this.service = opt.service
    this.statsd = opt.statsd || null
    this.http = opt.http || null
    this.interval = opt.interval || 60*1000
    this.healthy = false

    assert(this.service && this.service.length, "Service name is required")
    assert(this.service.match(/^[a-zA-Z0-9_.]+$/), "Service name may only "+
            "contain numbers, letters, underscores and dots.")
    assert(Number.isInteger(this.interval), "Check interval must be an integer")

    this._timeout = null

    this.init()
}
exports.Healthful = Healthful

/**
 * Initialize subclients and services.
 */
Healthful.prototype.init = function Healthful_init () {
    if (this.http) this.initHttp()
    if (this.statsd) this.initStatsd()

    if (!this.http && !this.statsd) {
        this.debug("Not initializing any healthcheck, not configured.")
    }

}

/**
 * Initialize Http check
 */
Healthful.prototype.initHttp = function Healthful_initHttp () {
    assert(this.http, "HTTP listener improperly configured")

    // Allow for enable http with all defaults by specifying `true`
    if (this.http === true) this.http = {}

    // Default the port to 3301, which is unused according to IANA
    if (!this.http.port) this.http.port = process.env.HEALTHFUL_PORT || 3301
    assert(Number.isInteger(this.http.port), "HTTP port must be an integer")

    // Default the binding to public
    if (!this.http.bind) this.http.bind = (process.env.HEALTHFUL_BIND
        || '0.0.0.0')
    assert(typeof this.http.bind == 'string', "HTTP bind must be a string")

    // Deafult the content type to JSON
    if (!this.http.content_type) this.http.content_type = (
        process.env.HEALTHFUL_CONTENT_TYPE || 'application/json')
    assert(typeof this.http.content_type == 'string',
        "HTTP content type must be a string")

    // Default the response to a JSON ok
    if (!this.http.response) this.http.response = (
        process.env.HEALTHFUL_RESPONSE ||
        '{"service": "{{service}}", "healthful": {{healthy}}}')
    assert(typeof this.http.response == 'string',
        "HTTP response must be a string")

    // Create the server
    try {
        // Bind our request listener while creating the server
        this.server = http.createServer(this.handleRequest.bind(this))
        // Start listening on the right IP bind and port
        this.server.listen(this.http.port, this.http.bind, function () {
            try {
                this.debug("Listening on " + this.http.bind + ':' +
                    this.http.port)
            }
            catch (err) {
                this.debug("Error:", err)
            }
        }.bind(this))
        // Unref the server so it doesn't cause process hangs
        this.server.unref()
    }
    catch (err) {
        this.debug("Error creating Healthful listener:", err)
    }
}

/**
 * Return a response JSON string with template like behavior.
 */
Healthful.prototype.getResponse = function Healthful_getResponse () {
    var res = '' + this.http.response
    res = res.replace(/{{ *service *}}/gi, this.service)
    res = res.replace(/{{ *healthy *}}/gi, this.healthy)
    return res
}

/**
 * Health responder.
 */
Healthful.prototype.handleRequest = function Healthful_handleRequest (req, res) {
    res.setHeader('Content-type', this.http.content_type)
    res.setHeader('X-Healthful', Date.now().toString())
    res.writeHead(200)
    res.write(this.getResponse())
    res.end()
}

Healthful.prototype.initStatsd = function Healthful_initStatsd () {
    this.debug("Not implemented.")
}

Healthful.prototype.ping = function Healthful_ping () {
    this.debug("Ping")

    // Clear the previous timeout if it existed
    if (this._timeout) clearTimeout(this._timeout)

    // Update the healthy flag to be true
    this.healthy = true

    // Set the timeout to flip the healthy flag
    this._timeout = setTimeout(function Healthful_unhealhty () {
        this.debug("Ping timeout")
        this.healthy = false
    }.bind(this), this.interval)

    // Unref the timeout so we don't cause hangs
    this._timeout.unref()
}

Healthful.prototype.debug = function Healthful_debug () {
    // TODO: Filter this like the debug package
    // TODO: Add timestamp and name and color (?)
    var args = Array.prototype.slice.call(arguments)
    args.unshift('healthful:' + this.service)
    console.log.apply(console.log, args)
}

<commit_msg>lib: More comments.<commit_after>/**
 * Internal healthful library API
 */

// System
var http = require('http')
var assert = require('assert')

function Healthful (opt) {
    // Options object
    opt = opt || {}
    this.service = opt.service
    this.statsd = opt.statsd || null
    this.http = opt.http || null
    this.interval = opt.interval || 60*1000
    this.healthy = false

    assert(this.service && this.service.length, "Service name is required")
    assert(this.service.match(/^[a-zA-Z0-9_.]+$/), "Service name may only "+
            "contain numbers, letters, underscores and dots.")
    assert(Number.isInteger(this.interval), "Check interval must be an integer")

    this._timeout = null

    this.init()
}
exports.Healthful = Healthful

/**
 * Initialize subclients and services.
 */
Healthful.prototype.init = function Healthful_init () {
    if (this.http) this.initHttp()
    if (this.statsd) this.initStatsd()

    if (!this.http && !this.statsd) {
        this.debug("Not initializing any healthcheck, not configured.")
    }

}

/**
 * Initialize Http check
 */
Healthful.prototype.initHttp = function Healthful_initHttp () {
    assert(this.http, "HTTP listener improperly configured")

    // Allow for enable http with all defaults by specifying `true`
    if (this.http === true) this.http = {}

    // Default the port to 3301, which is unused according to IANA
    if (!this.http.port) this.http.port = process.env.HEALTHFUL_PORT || 3301
    assert(Number.isInteger(this.http.port), "HTTP port must be an integer")

    // Default the binding to public
    if (!this.http.bind) this.http.bind = (process.env.HEALTHFUL_BIND
        || '0.0.0.0')
    assert(typeof this.http.bind == 'string', "HTTP bind must be a string")

    // Deafult the content type to JSON
    if (!this.http.content_type) this.http.content_type = (
        process.env.HEALTHFUL_CONTENT_TYPE || 'application/json')
    assert(typeof this.http.content_type == 'string',
        "HTTP content type must be a string")

    // Default the response to a JSON ok
    if (!this.http.response) this.http.response = (
        process.env.HEALTHFUL_RESPONSE ||
        '{"service": "{{service}}", "healthful": {{healthy}}}')
    assert(typeof this.http.response == 'string',
        "HTTP response must be a string")

    // Create the server
    try {
        // Bind our request listener while creating the server
        this.server = http.createServer(this.handleRequest.bind(this))
        // Start listening on the right IP bind and port
        this.server.listen(this.http.port, this.http.bind, function () {
            try {
                this.debug("Listening on " + this.http.bind + ':' +
                    this.http.port)
            }
            catch (err) {
                this.debug("Error:", err)
            }
        }.bind(this))
        // Unref the server so it doesn't cause process hangs
        this.server.unref()
    }
    catch (err) {
        this.debug("Error creating Healthful listener:", err)
    }
}

/**
 * Return a response JSON string with template like behavior.
 */
Healthful.prototype.getResponse = function Healthful_getResponse () {
    var res = '' + this.http.response
    res = res.replace(/{{ *service *}}/gi, this.service)
    res = res.replace(/{{ *healthy *}}/gi, this.healthy)
    return res
}

/**
 * Health responder.
 */
Healthful.prototype.handleRequest = function Healthful_handleRequest (req, res) {
    res.setHeader('Content-type', this.http.content_type)
    res.setHeader('X-Healthful', Date.now().toString())
    res.writeHead(200)
    res.write(this.getResponse())
    res.end()
}

/**
 * Get StatsD going.
 */
Healthful.prototype.initStatsd = function Healthful_initStatsd () {
    this.debug("Not implemented.")
}

/**
 * Register a healthy state.
 */
Healthful.prototype.ping = function Healthful_ping () {
    this.debug("Ping")

    // Clear the previous timeout if it existed
    if (this._timeout) clearTimeout(this._timeout)

    // Update the healthy flag to be true
    this.healthy = true

    // Set the timeout to flip the healthy flag
    this._timeout = setTimeout(function Healthful_unhealhty () {
        this.debug("Ping timeout")
        this.healthy = false
    }.bind(this), this.interval)

    // Unref the timeout so we don't cause hangs
    this._timeout.unref()
}

/**
 * Provide helpful debug output.
 */
Healthful.prototype.debug = function Healthful_debug () {
    // TODO: Filter this like the debug package
    // TODO: Add timestamp and name and color (?)
    var args = Array.prototype.slice.call(arguments)
    args.unshift('healthful:' + this.service)
    console.log.apply(console.log, args)
}

<|endoftext|>


<commit_before>// Copyright 2011 Iris Couch
//
//    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.

exports.scrub_creds = function scrub_creds(url) {
  return url.replace(/^(https?:\/\/)[^:]+:[^@]+@(.*)$/, '$1$2'); // Scrub username and password
}

exports.JP = JSON.parse;
exports.JS = JSON.stringify;
exports.JDUP = function(obj) { return JSON.parse(JSON.stringify(obj)) };

// Wrap log4js so it will not be a dependency.
var VERBOSE;
if(require.isBrowser)
  VERBOSE = true;
else
  verbose = (process.env.verbose === 'true');

var noop = function() {};
var noops = { "trace": noop
            , "debug": VERBOSE ? console.log   : noop
            , "info" : VERBOSE ? console.info  : noop
            , "warn" : VERBOSE ? console.warn  : noop
            , "error": VERBOSE ? console.error : noop
            , "fatal": VERBOSE ? console.error : noop

            , "setLevel": noop
            }

try {
  exports.log4js = require('log4js');
} catch(e) {
  exports.log4js = null;
}

exports.log4js = exports.log4js || { 'getLogger': function() { return noops } }
<commit_msg>Allow avoiding log4js (for testing)<commit_after>// Copyright 2011 Iris Couch
//
//    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.

exports.scrub_creds = function scrub_creds(url) {
  return url.replace(/^(https?:\/\/)[^:]+:[^@]+@(.*)$/, '$1$2'); // Scrub username and password
}

exports.JP = JSON.parse;
exports.JS = JSON.stringify;
exports.JDUP = function(obj) { return JSON.parse(JSON.stringify(obj)) };

// Wrap log4js so it will not be a dependency.
var VERBOSE;
if(require.isBrowser)
  VERBOSE = true;
else
  verbose = (process.env.verbose === 'true');

var noop = function() {};
var noops = { "trace": noop
            , "debug": VERBOSE ? console.log   : noop
            , "info" : VERBOSE ? console.info  : noop
            , "warn" : VERBOSE ? console.warn  : noop
            , "error": VERBOSE ? console.error : noop
            , "fatal": VERBOSE ? console.error : noop

            , "setLevel": noop
            }

try {
  if(! process.env.log_plain)
    exports.log4js = require('log4js');
} catch(e) {
  exports.log4js = null;
}

exports.log4js = exports.log4js || { 'getLogger': function() { return noops } }
<|endoftext|>


<commit_before>var
    child_process = require('child_process')
    ,path = require('path')
    ,util = require('util')
    ;

/**
 * @param {string} pathToExecutable
 * @param {string[]} args
 * @returns {Buffer}
 */
function execCommandSync(pathToExecutable, args)
{
    return child_process.execSync(pathToExecutable + " " + args.join(" "));
}

function ResHackInstance(config)
{
    config = util._extend({}, config);
    if(config.pathToExecutable)
        this.pathToExecutable = config.pathToExecutable;
}

/**
 * Path to ResHack.exe (including the executable name)
 * If left untouched, it will be assumed ResHack.exe is on the PATH
 * @type {string}
 */
ResHackInstance.prototype.pathToExecutable = "ResHacker.exe";

/**
 * @param {string[]} args
 * @returns {Buffer}
 */
ResHackInstance.prototype.execSync = function(args)
{
    return execCommandSync(this.pathToExecutable, args);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} SaveAsFile - the output modified exe file
 * @param {string} ResourceFile - the input resource file
 * @param {string} ResourceMask - the path/mask selecting the resources to add
 * @returns {Buffer}
 */
ResHackInstance.prototype.addSync = function(ExeFile, SaveAsFile, ResourceFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-add',
        '\"'+ExeFile+'\",',
        '\"'+SaveAsFile+'\",',
        '\"'+ResourceFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} SaveAsFile - the output modified exe file
 * @param {string} ResourceFile - the input resource file
 * @param {string} ResourceMask - the path/mask selecting the resources to add (or skip when existent)
 * @returns {Buffer}
 */
ResHackInstance.prototype.addskipSync = function(ExeFile, SaveAsFile, ResourceFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-addskip',
        '\"'+ExeFile+'\",',
        '\"'+SaveAsFile+'\",',
        '\"'+ResourceFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} SaveAsFile - the output modified exe file
 * @param {string} ResourceFile - the input resource file
 * @param {string} ResourceMask - the path/mask selecting the resources to add (or overwrite when existent)
 * @returns {Buffer}
 */
ResHackInstance.prototype.addoverwriteSync = function(ExeFile, SaveAsFile, ResourceFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-addoverwrite',
        '\"'+ExeFile+'\",',
        '\"'+SaveAsFile+'\",',
        '\"'+ResourceFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} SaveAsFile - the output modified exe file
 * @param {string} ResourceFile - the input resource file
 * @param {string} ResourceMask - the path/mask selecting the resources to modify
 * @returns {Buffer}
 */
ResHackInstance.prototype.modifySync = function(ExeFile, SaveAsFile, ResourceFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-modify',
        '\"'+ExeFile+'\",',
        '\"'+SaveAsFile+'\",',
        '\"'+ResourceFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} ResourceFile - the output resource file
 * @param {string} ResourceMask - the path/mask selecting the resource to extract
 * @returns {Buffer}
 */
ResHackInstance.prototype.extractSync = function(ExeFile, ResourceFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-extract',
        '\"'+ExeFile+'\",',
        '\"'+ResourceFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} SaveAsFile - the output modified exe file
 * @param {string} ResourceMask - the path/mask selecting the resources to delete
 * @returns {Buffer}
 */
ResHackInstance.prototype.deleteSync = function(ExeFile, SaveAsFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-delete',
        '\"'+ExeFile+'\",',
        '\"'+SaveAsFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * Creates a fresh instance with custom configuration
 * @param config
 * @returns {ResHackInstance}
 */
ResHackInstance.configureInstance = function(config)
{
    return new ResHackInstance(config);
};

module.exports = new ResHackInstance();<commit_msg>Add method configureInstance to every instance. This allow creation of customly configured instances anywhere.<commit_after>var
    child_process = require('child_process')
    ,path = require('path')
    ,util = require('util')
    ;

/**
 * @param {string} pathToExecutable
 * @param {string[]} args
 * @returns {Buffer}
 */
function execCommandSync(pathToExecutable, args)
{
    return child_process.execSync(pathToExecutable + " " + args.join(" "));
}

function ResHackInstance(config)
{
    config = util._extend({}, config);
    if(config.pathToExecutable)
        this.pathToExecutable = config.pathToExecutable;
}

/**
 * Path to ResHack.exe (including the executable name)
 * If left untouched, it will be assumed ResHack.exe is on the PATH
 * @type {string}
 */
ResHackInstance.prototype.pathToExecutable = "ResHacker.exe";

/**
 * @param {string[]} args
 * @returns {Buffer}
 */
ResHackInstance.prototype.execSync = function(args)
{
    return execCommandSync(this.pathToExecutable, args);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} SaveAsFile - the output modified exe file
 * @param {string} ResourceFile - the input resource file
 * @param {string} ResourceMask - the path/mask selecting the resources to add
 * @returns {Buffer}
 */
ResHackInstance.prototype.addSync = function(ExeFile, SaveAsFile, ResourceFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-add',
        '\"'+ExeFile+'\",',
        '\"'+SaveAsFile+'\",',
        '\"'+ResourceFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} SaveAsFile - the output modified exe file
 * @param {string} ResourceFile - the input resource file
 * @param {string} ResourceMask - the path/mask selecting the resources to add (or skip when existent)
 * @returns {Buffer}
 */
ResHackInstance.prototype.addskipSync = function(ExeFile, SaveAsFile, ResourceFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-addskip',
        '\"'+ExeFile+'\",',
        '\"'+SaveAsFile+'\",',
        '\"'+ResourceFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} SaveAsFile - the output modified exe file
 * @param {string} ResourceFile - the input resource file
 * @param {string} ResourceMask - the path/mask selecting the resources to add (or overwrite when existent)
 * @returns {Buffer}
 */
ResHackInstance.prototype.addoverwriteSync = function(ExeFile, SaveAsFile, ResourceFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-addoverwrite',
        '\"'+ExeFile+'\",',
        '\"'+SaveAsFile+'\",',
        '\"'+ResourceFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} SaveAsFile - the output modified exe file
 * @param {string} ResourceFile - the input resource file
 * @param {string} ResourceMask - the path/mask selecting the resources to modify
 * @returns {Buffer}
 */
ResHackInstance.prototype.modifySync = function(ExeFile, SaveAsFile, ResourceFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-modify',
        '\"'+ExeFile+'\",',
        '\"'+SaveAsFile+'\",',
        '\"'+ResourceFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} ResourceFile - the output resource file
 * @param {string} ResourceMask - the path/mask selecting the resource to extract
 * @returns {Buffer}
 */
ResHackInstance.prototype.extractSync = function(ExeFile, ResourceFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-extract',
        '\"'+ExeFile+'\",',
        '\"'+ResourceFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * @param {string} ExeFile - the source exe file
 * @param {string} SaveAsFile - the output modified exe file
 * @param {string} ResourceMask - the path/mask selecting the resources to delete
 * @returns {Buffer}
 */
ResHackInstance.prototype.deleteSync = function(ExeFile, SaveAsFile, ResourceMask){

    if(!ResourceMask)
    {
        ResourceMask = ",,,"
    }

    return this.execSync([
        '-delete',
        '\"'+ExeFile+'\",',
        '\"'+SaveAsFile+'\",',
        ''+ResourceMask+''
    ]);
};

/**
 * Creates a fresh instance with custom configuration
 * @param config
 * @returns {ResHackInstance}
 */
ResHackInstance.prototype.configureInstance = function(config)
{
    return new ResHackInstance(config);
};

/**
 * @type {ResHackInstance}
 */
module.exports = new ResHackInstance();<|endoftext|>


<commit_before>var mongoose = require('mongoose');
var config = require('../config.json');
var Schema = mongoose.Schema;

var replies = mongoose.model(config.collection1, new Schema({
  reply: String,
  input: Array
}));

function greetingDate() {
  if ([6,7,8,9,10,11].indexOf(new Date().getHours()) > -1) {
    return '\ud83c\udf1d Buenos días';
  } else if ([12,13,14,15,16,17,18].indexOf(new Date().getHours()) > -1) {
    return '\ud83c\udf1d Buenas tardes';
  } else {
    return '\ud83c\udf1a Buenas noches';
  }
}

exports.reply = function(input, cb) {
  replies.findOne({ input: input.body.toLowerCase() }, (err, res) => {
    if (res === null) {
      replies.findOne({ input: 'greeting' }, (err, greeting) => {
        greeting.reply = `${greetingDate()} ${input.name} ${greeting.reply}`;
        cb(greeting);
      });
    } else { cb(res); }
  });
}
<commit_msg>add logs functions<commit_after>var mongoose = require('mongoose');
var config = require('../config.json');
var Schema = mongoose.Schema;

var replies = mongoose.model(config.collection1, new Schema({
  reply: String,
  input: Array
}));

var logs = mongoose.model(config.collection2, new Schema({
  from: String,
  data: Array
}));

function greetingDate() {
  if ([6,7,8,9,10,11].indexOf(new Date().getHours()) > -1) {
    return '\ud83c\udf1d Buenos días';
  } else if ([12,13,14,15,16,17,18].indexOf(new Date().getHours()) > -1) {
    return '\ud83c\udf1d Buenas tardes';
  } else {
    return '\ud83c\udf1a Buenas noches';
  }
}

exports.reply = function(input, cb) {
  replies.findOne({ input: input.body.toLowerCase() }, (err, res) => {
    if (res === null) {
      replies.findOne({ input: 'greeting' }, (err, greeting) => {
        greeting.reply = `${greetingDate()} ${input.name} ${greeting.reply}`;
        cb(greeting);
      });
    } else { cb(res); }
  });
}

exports.logs = function(input) {
  logs.findOneAndUpdate(
    { from: input.from },
    { $push: { 'data': (i => {delete i['from']; return i})(input) } },
    { safe: true, upsert: true },
    (err, res) => {
      // console.log(err, res);
    }
  );
}
<|endoftext|>


<commit_before>import { NativeModules } from 'react-native';

const NativeClient = NativeModules.BugsnagReactNative;

const BREADCRUMB_MAX_LENGTH = 30;
const CONSOLE_LOG_METHODS = [ 'log', 'debug', 'info', 'warn', 'error' ].filter(method =>
  typeof console[method] === 'function'
);

/**
 * A Bugsnag monitoring and reporting client
 */
export class Client {

  /**
   * Creates a new Bugsnag client
   */
  constructor(apiKeyOrConfig) {
    if (typeof apiKeyOrConfig === 'string' || typeof apiKeyOrConfig === 'undefined') {
      this.config = new Configuration(apiKeyOrConfig);
    } else if (apiKeyOrConfig instanceof Configuration) {
      this.config = apiKeyOrConfig;
    } else {
      throw new Error('Bugsnag: A client must be constructed with an API key or Configuration');
    }

    if (NativeClient) {
      NativeClient.startWithOptions(this.config.toJSON());
      this.handleUncaughtErrors();
      if (this.config.handlePromiseRejections)
        this.handlePromiseRejections();
      if (this.config.consoleBreadcrumbsEnabled)
        this.enableConsoleBreadcrumbs();
    } else {
      throw new Error('Bugsnag: No native client found. Is BugsnagReactNative installed in your native code project?');
    }
  }

  /**
   * Registers a global error handler which sends any uncaught error to
   * Bugsnag before invoking the previous handler, if any.
   */
  handleUncaughtErrors = () => {
    if (ErrorUtils) {
      const previousHandler = ErrorUtils.getGlobalHandler();

      ErrorUtils.setGlobalHandler((error, isFatal) => {
        if (this.config.autoNotify && this.config.shouldNotify()) {
          this.notify(error, null, !!NativeClient.notifyBlocking, (queued) => {
            if (previousHandler) {
              previousHandler(error, isFatal);
            }
          }, new HandledState('error', true, 'unhandledException'));
        } else if (previousHandler) {
          previousHandler(error, isFatal);
        }
      });
    }
  }

  handlePromiseRejections = () => {
    const tracking = require('promise/setimmediate/rejection-tracking'),
          client = this;
    tracking.enable({
      allRejections: true,
      onUnhandled: function(id, error) {
        client.notify(error, null, false, null, new HandledState('error', true, 'unhandledPromiseRejection'));
      },
      onHandled: function() {}
    });
  }

  /**
   * Sends an error report to Bugsnag
   * @param error               The error instance to report
   * @param beforeSendCallback  A callback invoked before the report is sent
   *                            so additional information can be added
   * @param blocking            When true, blocks the native thread execution
   *                            until complete. If unspecified, sends the
   *                            request asynchronously
   * @param postSendCallback    Callback invoked after request is queued
   */
  notify = async (error, beforeSendCallback, blocking, postSendCallback, _handledState) => {
    if (!(error instanceof Error)) {
      console.warn('Bugsnag could not notify: error must be of type Error');
      if (postSendCallback)
        postSendCallback(false);
      return;
    }
    if (!this.config.shouldNotify()) {
      if (postSendCallback)
        postSendCallback(false);
      return;
    }

    const report = new Report(this.config.apiKey, error, _handledState);
    report.addMetadata('app', 'codeBundleId', this.config.codeBundleId);

    for (callback of this.config.beforeSendCallbacks) {
      if (callback(report, error) === false) {
        if (postSendCallback)
          postSendCallback(false);
        return;
      }
    }
    if (beforeSendCallback) {
      beforeSendCallback(report);
    }

    const payload = report.toJSON();
    if (blocking && NativeClient.notifyBlocking) {
      NativeClient.notifyBlocking(payload, blocking, postSendCallback);
    } else {
      NativeClient.notify(payload);
      if (postSendCallback)
        postSendCallback(true);
    }
  }

  setUser = (id, name, email) => {
    NativeClient.setUser({id, name, email});
  }

  /**
   * Clear custom user data and reset to the default device identifier
   */
  clearUser = () => {
    NativeClient.clearUser();
  }

  startSession = () => {
    NativeClient.startSession();
  }

  /**
   * Leaves a 'breadcrumb' log message. The most recent breadcrumbs
   * are attached to subsequent error reports.
   */
  leaveBreadcrumb = (name, metadata) => {
    if (typeof name !== 'string') {
      console.warn(`Breadcrumb name must be a string, got '${name}'. Discarding.`);
      return;
    }

    if (name.length > BREADCRUMB_MAX_LENGTH) {
      console.warn(`Breadcrumb name exceeds ${BREADCRUMB_MAX_LENGTH} characters (it has ${name.length}): ${name}. It will be truncated.`);
    }

    // Checks for both `null` and `undefined`.
    if (metadata == undefined) {
      metadata = {};
    } else if (typeof metadata === 'string') {
      metadata = { 'message': metadata };
    } else if (typeof metadata !== 'object') {
      console.warn(`Breadcrumb metadata must be an object or string, got '${metadata}'. Discarding metadata.`);
      metadata = {};
    }

    let type = metadata['type'] || 'manual';
    const breadcrumbMetaData = { ...metadata };
    delete breadcrumbMetaData['type'];

    NativeClient.leaveBreadcrumb({
      name,
      type,
      metadata: typedMap(breadcrumbMetaData)
    });
  }

  /**
   * Wraps all console log functions with a function that will leave a breadcrumb for
   * each call, while continuing to call through to the original.
   *
   *   !!! Warning !!!
   *   This will cause all log messages to originate from Bugsnag, rather than the
   *   actual callsite of the log function in your source code.
   */
  enableConsoleBreadcrumbs = () => {
    CONSOLE_LOG_METHODS.forEach(method => {
      const originalFn = console[method];
      console[method] = (...args) => {
        try {
          this.leaveBreadcrumb('Console', {
            type: 'log',
            severity: /^group/.test(method) ? 'log' : method,
            message: args
              .map(arg => {
                let stringified
                // do the best/simplest stringification of each argument
                try { stringified = String(arg) } catch (e) {}
                // unless it stringifies to [object Object], use the toString() value
                if (stringified && stringified !== '[object Object]') return stringified
                // otherwise attempt to JSON stringify (with indents/spaces)
                try { stringified = JSON.stringify(arg, null, 2) } catch (e) {}
                // any errors, fallback to [object Object]
                return stringified
              })
              .join('\n')
          });
        } catch (error) {
          console.warn(`Unable to serialize console.${method} arguments to Bugsnag breadcrumb.`, error);
        }
        originalFn.apply(console, args);
      }
      console[method]._restore = () => { console[method] = originalFn }
    });
  }

  disableConsoleBreadCrumbs = () => {
    CONSOLE_LOG_METHODS.forEach(method => {
      if (typeof console[method]._restore === 'function') console[method]._restore()
    })
  }
}

/**
 * Configuration options for a Bugsnag client
 */
export class Configuration {

  constructor(apiKey) {
    const metadata = require('../package.json');
    this.version = metadata['version'];
    this.apiKey = apiKey;
    this.delivery = new StandardDelivery();
    this.beforeSendCallbacks = [];
    this.notifyReleaseStages = undefined;
    this.releaseStage = undefined;
    this.appVersion = undefined;
    this.codeBundleId = undefined;
    this.autoCaptureSessions = false;
    this.autoNotify = true;
    this.handlePromiseRejections = !__DEV__; // prefer banner in dev mode
    this.consoleBreadcrumbsEnabled = false;
    this.automaticallyCollectBreadcrumbs = true;
  }

  /**
   * Whether reports should be sent to Bugsnag, based on the release stage
   * configuration
   */
  shouldNotify = () => {
    return !this.releaseStage ||
      !this.notifyReleaseStages ||
      this.notifyReleaseStages.includes(this.releaseStage);
  }

  /**
   * Adds a function which is invoked after an error is reported but before
   * it is sent to Bugsnag. The function takes a single parameter which is
   * an instance of Report.
   */
  registerBeforeSendCallback = (callback) => {
    this.beforeSendCallbacks.push(callback)
  }

  /**
   * Remove a callback from the before-send pipeline
   */
  unregisterBeforeSendCallback = (callback) => {
    const index = this.beforeSendCallbacks.indexOf(callback);
    if (index != -1) {
      this.beforeSendCallbacks.splice(index, 1);
    }
  }

  /**
   * Remove all callbacks invoked before reports are sent to Bugsnag
   */
  clearBeforeSendCallbacks = () => {
    this.beforeSendCallbacks = []
  }

  toJSON = () => {
    return {
      apiKey: this.apiKey,
      codeBundleId: this.codeBundleId,
      releaseStage: this.releaseStage,
      notifyReleaseStages: this.notifyReleaseStages,
      endpoint: this.delivery.endpoint,
      sessionsEndpoint: this.delivery.sessionsEndpoint,
      appVersion: this.appVersion,
      autoNotify: this.autoNotify,
      version: this.version,
      autoCaptureSessions: this.autoCaptureSessions,
      automaticallyCollectBreadcrumbs: this.automaticallyCollectBreadcrumbs,
    };
  }
}

export class StandardDelivery {
  constructor(endpoint, sessionsEndpoint) {
    this.endpoint = endpoint;
    this.sessionsEndpoint = sessionsEndpoint;
  }
}

class HandledState {
  constructor(originalSeverity, unhandled, severityReason) {
    this.originalSeverity = originalSeverity;
    this.unhandled = unhandled;
    this.severityReason = severityReason;
  }
}

/**
 * A report generated from an error
 */
export class Report {

  constructor(apiKey, error, _handledState) {
    this.apiKey = apiKey;
    this.errorClass = error.constructor.name;
    this.errorMessage = error.message;
    this.context = undefined;
    this.groupingHash = undefined;
    this.metadata = {};
    this.stacktrace = error.stack;
    this.user = {};

    if (!_handledState || !(_handledState instanceof HandledState)) {
      _handledState = new HandledState('warning', false, 'handledException');
    }

    this.severity = _handledState.originalSeverity;
    this._handledState = _handledState;
  }

  /**
   * Attach additional diagnostic data to the report. The key/value pairs
   * are grouped into sections.
   */
  addMetadata = (section, key, value) => {
    if (!this.metadata[section]) {
      this.metadata[section] = {};
    }
    this.metadata[section][key] = value;
  }

  toJSON = () => {
    if (!this._handledState || !(this._handledState instanceof HandledState)) {
      this._handledState = new HandledState('warning', false, 'handledException');
    }
    // severityReason must be a string, and severity must match the original
    // state, otherwise we assume that the user has modified _handledState
    // in a callback
    const defaultSeverity = this._handledState.originalSeverity === this.severity;
    const isValidReason = (typeof this._handledState.severityReason === 'string');
    const severityType = defaultSeverity && isValidReason ?
     this._handledState.severityReason : 'userCallbackSetSeverity';

    // if unhandled not set, user has modified the report in a callback
    // or via notify, so default to false
    const isUnhandled = (typeof this._handledState.unhandled === 'boolean') ? this._handledState.unhandled : false;

    return {
      apiKey: this.apiKey,
      context: this.context,
      errorClass: this.errorClass,
      errorMessage: this.errorMessage,
      groupingHash: this.groupingHash,
      metadata: typedMap(this.metadata),
      severity: this.severity,
      stacktrace: this.stacktrace,
      user: this.user,
      defaultSeverity: defaultSeverity,
      unhandled: isUnhandled,
      severityReason: severityType
    }
  }
}

const allowedMapObjectTypes = ['string', 'number', 'boolean'];

/**
 * Convert an object into a structure with types suitable for serializing
 * across to native code.
 */
const typedMap = function(map) {
  const output = {};
  for (const key in map) {
    if (!{}.hasOwnProperty.call(map, key)) continue;

    const value = map[key];

    // Checks for `null`, NaN, and `undefined`.
    if (value == undefined || (typeof value === 'number' && isNaN(value))) {
      output[key] = {type: 'string', value: String(value)}
    } else if (typeof value === 'object') {
      output[key] = {type: 'map', value: typedMap(value)};
    } else {
      const type = typeof value;
      if (allowedMapObjectTypes.includes(type)) {
        output[key] = {type: type, value: value};
      } else {
        console.warn(`Could not serialize breadcrumb data for '${key}': Invalid type '${type}'`);
      }
    }
  }
  return output;
}
<commit_msg>Rework construction of breadcrumbMetaData<commit_after>import { NativeModules } from 'react-native';

const NativeClient = NativeModules.BugsnagReactNative;

const BREADCRUMB_MAX_LENGTH = 30;
const CONSOLE_LOG_METHODS = [ 'log', 'debug', 'info', 'warn', 'error' ].filter(method =>
  typeof console[method] === 'function'
);

/**
 * A Bugsnag monitoring and reporting client
 */
export class Client {

  /**
   * Creates a new Bugsnag client
   */
  constructor(apiKeyOrConfig) {
    if (typeof apiKeyOrConfig === 'string' || typeof apiKeyOrConfig === 'undefined') {
      this.config = new Configuration(apiKeyOrConfig);
    } else if (apiKeyOrConfig instanceof Configuration) {
      this.config = apiKeyOrConfig;
    } else {
      throw new Error('Bugsnag: A client must be constructed with an API key or Configuration');
    }

    if (NativeClient) {
      NativeClient.startWithOptions(this.config.toJSON());
      this.handleUncaughtErrors();
      if (this.config.handlePromiseRejections)
        this.handlePromiseRejections();
      if (this.config.consoleBreadcrumbsEnabled)
        this.enableConsoleBreadcrumbs();
    } else {
      throw new Error('Bugsnag: No native client found. Is BugsnagReactNative installed in your native code project?');
    }
  }

  /**
   * Registers a global error handler which sends any uncaught error to
   * Bugsnag before invoking the previous handler, if any.
   */
  handleUncaughtErrors = () => {
    if (ErrorUtils) {
      const previousHandler = ErrorUtils.getGlobalHandler();

      ErrorUtils.setGlobalHandler((error, isFatal) => {
        if (this.config.autoNotify && this.config.shouldNotify()) {
          this.notify(error, null, !!NativeClient.notifyBlocking, (queued) => {
            if (previousHandler) {
              previousHandler(error, isFatal);
            }
          }, new HandledState('error', true, 'unhandledException'));
        } else if (previousHandler) {
          previousHandler(error, isFatal);
        }
      });
    }
  }

  handlePromiseRejections = () => {
    const tracking = require('promise/setimmediate/rejection-tracking'),
          client = this;
    tracking.enable({
      allRejections: true,
      onUnhandled: function(id, error) {
        client.notify(error, null, false, null, new HandledState('error', true, 'unhandledPromiseRejection'));
      },
      onHandled: function() {}
    });
  }

  /**
   * Sends an error report to Bugsnag
   * @param error               The error instance to report
   * @param beforeSendCallback  A callback invoked before the report is sent
   *                            so additional information can be added
   * @param blocking            When true, blocks the native thread execution
   *                            until complete. If unspecified, sends the
   *                            request asynchronously
   * @param postSendCallback    Callback invoked after request is queued
   */
  notify = async (error, beforeSendCallback, blocking, postSendCallback, _handledState) => {
    if (!(error instanceof Error)) {
      console.warn('Bugsnag could not notify: error must be of type Error');
      if (postSendCallback)
        postSendCallback(false);
      return;
    }
    if (!this.config.shouldNotify()) {
      if (postSendCallback)
        postSendCallback(false);
      return;
    }

    const report = new Report(this.config.apiKey, error, _handledState);
    report.addMetadata('app', 'codeBundleId', this.config.codeBundleId);

    for (callback of this.config.beforeSendCallbacks) {
      if (callback(report, error) === false) {
        if (postSendCallback)
          postSendCallback(false);
        return;
      }
    }
    if (beforeSendCallback) {
      beforeSendCallback(report);
    }

    const payload = report.toJSON();
    if (blocking && NativeClient.notifyBlocking) {
      NativeClient.notifyBlocking(payload, blocking, postSendCallback);
    } else {
      NativeClient.notify(payload);
      if (postSendCallback)
        postSendCallback(true);
    }
  }

  setUser = (id, name, email) => {
    NativeClient.setUser({id, name, email});
  }

  /**
   * Clear custom user data and reset to the default device identifier
   */
  clearUser = () => {
    NativeClient.clearUser();
  }

  startSession = () => {
    NativeClient.startSession();
  }

  /**
   * Leaves a 'breadcrumb' log message. The most recent breadcrumbs
   * are attached to subsequent error reports.
   */
  leaveBreadcrumb = (name, metadata) => {
    if (typeof name !== 'string') {
      console.warn(`Breadcrumb name must be a string, got '${name}'. Discarding.`);
      return;
    }

    if (name.length > BREADCRUMB_MAX_LENGTH) {
      console.warn(`Breadcrumb name exceeds ${BREADCRUMB_MAX_LENGTH} characters (it has ${name.length}): ${name}. It will be truncated.`);
    }

    // Checks for both `null` and `undefined`.
    if (metadata == undefined) {
      metadata = {};
    } else if (typeof metadata === 'string') {
      metadata = { 'message': metadata };
    } else if (typeof metadata !== 'object') {
      console.warn(`Breadcrumb metadata must be an object or string, got '${metadata}'. Discarding metadata.`);
      metadata = {};
    }

    const {
      type = 'manual',
      ...breadcrumbMetaData
    } = metadata;

    NativeClient.leaveBreadcrumb({
      name,
      type,
      metadata: typedMap(breadcrumbMetaData)
    });
  }

  /**
   * Wraps all console log functions with a function that will leave a breadcrumb for
   * each call, while continuing to call through to the original.
   *
   *   !!! Warning !!!
   *   This will cause all log messages to originate from Bugsnag, rather than the
   *   actual callsite of the log function in your source code.
   */
  enableConsoleBreadcrumbs = () => {
    CONSOLE_LOG_METHODS.forEach(method => {
      const originalFn = console[method];
      console[method] = (...args) => {
        try {
          this.leaveBreadcrumb('Console', {
            type: 'log',
            severity: /^group/.test(method) ? 'log' : method,
            message: args
              .map(arg => {
                let stringified
                // do the best/simplest stringification of each argument
                try { stringified = String(arg) } catch (e) {}
                // unless it stringifies to [object Object], use the toString() value
                if (stringified && stringified !== '[object Object]') return stringified
                // otherwise attempt to JSON stringify (with indents/spaces)
                try { stringified = JSON.stringify(arg, null, 2) } catch (e) {}
                // any errors, fallback to [object Object]
                return stringified
              })
              .join('\n')
          });
        } catch (error) {
          console.warn(`Unable to serialize console.${method} arguments to Bugsnag breadcrumb.`, error);
        }
        originalFn.apply(console, args);
      }
      console[method]._restore = () => { console[method] = originalFn }
    });
  }

  disableConsoleBreadCrumbs = () => {
    CONSOLE_LOG_METHODS.forEach(method => {
      if (typeof console[method]._restore === 'function') console[method]._restore()
    })
  }
}

/**
 * Configuration options for a Bugsnag client
 */
export class Configuration {

  constructor(apiKey) {
    const metadata = require('../package.json');
    this.version = metadata['version'];
    this.apiKey = apiKey;
    this.delivery = new StandardDelivery();
    this.beforeSendCallbacks = [];
    this.notifyReleaseStages = undefined;
    this.releaseStage = undefined;
    this.appVersion = undefined;
    this.codeBundleId = undefined;
    this.autoCaptureSessions = false;
    this.autoNotify = true;
    this.handlePromiseRejections = !__DEV__; // prefer banner in dev mode
    this.consoleBreadcrumbsEnabled = false;
    this.automaticallyCollectBreadcrumbs = true;
  }

  /**
   * Whether reports should be sent to Bugsnag, based on the release stage
   * configuration
   */
  shouldNotify = () => {
    return !this.releaseStage ||
      !this.notifyReleaseStages ||
      this.notifyReleaseStages.includes(this.releaseStage);
  }

  /**
   * Adds a function which is invoked after an error is reported but before
   * it is sent to Bugsnag. The function takes a single parameter which is
   * an instance of Report.
   */
  registerBeforeSendCallback = (callback) => {
    this.beforeSendCallbacks.push(callback)
  }

  /**
   * Remove a callback from the before-send pipeline
   */
  unregisterBeforeSendCallback = (callback) => {
    const index = this.beforeSendCallbacks.indexOf(callback);
    if (index != -1) {
      this.beforeSendCallbacks.splice(index, 1);
    }
  }

  /**
   * Remove all callbacks invoked before reports are sent to Bugsnag
   */
  clearBeforeSendCallbacks = () => {
    this.beforeSendCallbacks = []
  }

  toJSON = () => {
    return {
      apiKey: this.apiKey,
      codeBundleId: this.codeBundleId,
      releaseStage: this.releaseStage,
      notifyReleaseStages: this.notifyReleaseStages,
      endpoint: this.delivery.endpoint,
      sessionsEndpoint: this.delivery.sessionsEndpoint,
      appVersion: this.appVersion,
      autoNotify: this.autoNotify,
      version: this.version,
      autoCaptureSessions: this.autoCaptureSessions,
      automaticallyCollectBreadcrumbs: this.automaticallyCollectBreadcrumbs,
    };
  }
}

export class StandardDelivery {
  constructor(endpoint, sessionsEndpoint) {
    this.endpoint = endpoint;
    this.sessionsEndpoint = sessionsEndpoint;
  }
}

class HandledState {
  constructor(originalSeverity, unhandled, severityReason) {
    this.originalSeverity = originalSeverity;
    this.unhandled = unhandled;
    this.severityReason = severityReason;
  }
}

/**
 * A report generated from an error
 */
export class Report {

  constructor(apiKey, error, _handledState) {
    this.apiKey = apiKey;
    this.errorClass = error.constructor.name;
    this.errorMessage = error.message;
    this.context = undefined;
    this.groupingHash = undefined;
    this.metadata = {};
    this.stacktrace = error.stack;
    this.user = {};

    if (!_handledState || !(_handledState instanceof HandledState)) {
      _handledState = new HandledState('warning', false, 'handledException');
    }

    this.severity = _handledState.originalSeverity;
    this._handledState = _handledState;
  }

  /**
   * Attach additional diagnostic data to the report. The key/value pairs
   * are grouped into sections.
   */
  addMetadata = (section, key, value) => {
    if (!this.metadata[section]) {
      this.metadata[section] = {};
    }
    this.metadata[section][key] = value;
  }

  toJSON = () => {
    if (!this._handledState || !(this._handledState instanceof HandledState)) {
      this._handledState = new HandledState('warning', false, 'handledException');
    }
    // severityReason must be a string, and severity must match the original
    // state, otherwise we assume that the user has modified _handledState
    // in a callback
    const defaultSeverity = this._handledState.originalSeverity === this.severity;
    const isValidReason = (typeof this._handledState.severityReason === 'string');
    const severityType = defaultSeverity && isValidReason ?
     this._handledState.severityReason : 'userCallbackSetSeverity';

    // if unhandled not set, user has modified the report in a callback
    // or via notify, so default to false
    const isUnhandled = (typeof this._handledState.unhandled === 'boolean') ? this._handledState.unhandled : false;

    return {
      apiKey: this.apiKey,
      context: this.context,
      errorClass: this.errorClass,
      errorMessage: this.errorMessage,
      groupingHash: this.groupingHash,
      metadata: typedMap(this.metadata),
      severity: this.severity,
      stacktrace: this.stacktrace,
      user: this.user,
      defaultSeverity: defaultSeverity,
      unhandled: isUnhandled,
      severityReason: severityType
    }
  }
}

const allowedMapObjectTypes = ['string', 'number', 'boolean'];

/**
 * Convert an object into a structure with types suitable for serializing
 * across to native code.
 */
const typedMap = function(map) {
  const output = {};
  for (const key in map) {
    if (!{}.hasOwnProperty.call(map, key)) continue;

    const value = map[key];

    // Checks for `null`, NaN, and `undefined`.
    if (value == undefined || (typeof value === 'number' && isNaN(value))) {
      output[key] = {type: 'string', value: String(value)}
    } else if (typeof value === 'object') {
      output[key] = {type: 'map', value: typedMap(value)};
    } else {
      const type = typeof value;
      if (allowedMapObjectTypes.includes(type)) {
        output[key] = {type: type, value: value};
      } else {
        console.warn(`Could not serialize breadcrumb data for '${key}': Invalid type '${type}'`);
      }
    }
  }
  return output;
}
<|endoftext|>


<commit_before>/**
 * @fileoverview An API for building JavaScript
 * @author Thomas Allen <thomasmallen@gmail.com>
 */
Coca = {};
;(function() {
    /**
     * Usage:
     *     var s = new Coca.Builder.Group(),
     *         fn = s.addFunction('doSomething', ['a', 'b', 'c']);
     *     fn.addVariables([['a'], ['b', new Coca.Builder.Function('hello')]])
     *     fn.endStatement();
     *     fn.addIf('x < 2').addElse().withIf('y > 1');
     *     print(s);
     *     -> (function doSomething(a, b, c) {var a, b = function hello() {};if (x < 2) {}else if (y > 1) {}})
     */
    Coca.Builder = {
        /**
         * Base source builder.
         *
         * Does not perform validation; it is the responsibility of the user
         * to ensure that the API is used to create valid JavaScript code.
         */
        Source: function() {
            this.bits = [];
        },

        addType: function(type, fn, toString, ps) {
            var P = Coca.Builder.Source,
                C = function() {
                    P.apply(this);
                    if (fn)
                        if (typeof fn != 'function') {
                            this.push(fn);
                            this.endStatement();
                        } else fn.apply(this, arguments);
                };
            C.prototype = new P();
            C.prototype.toString = function() {
                var s = P.prototype.toString.apply(this);
                if (toString)
                    s = toString.call(this, s);
                return s;
            };
            if (ps)
                for (var p in ps)
                    if (ps.hasOwnProperty(p))
                        C.prototype[p] = ps[p];
            Coca.Builder[type] = C;
            P.prototype['add' + type] = function() {
                var o = new C();
                C.apply(o, arguments);
                return this.push(o);
            };
        }
    };

    Coca.Builder.Source.prototype.push = function(p) {
        this.bits.push(p);
        return p;
    };
    Coca.Builder.Source.prototype.toString = function() {
        return this.bits.join('');
    };
    Coca.Builder.Source.prototype.endStatement = function() {
        return this.push(';');
    };

    // Simple types
    Coca.Builder.addType('Empty', '');
    Coca.Builder.addType('Continue', 'continue');
    Coca.Builder.addType('Break', 'break');

    Coca.Builder.addType('Comment', function(c) {
        this.push('/* ' + c + '*/');
    });

    Coca.Builder.addType('String', function(s) {
        // This will go much better if we simply require JSON.stringify
        // and use that here, but I did not want to introduce that
        // requirement right now.
        this.push('"' + this.s.replace(/"/g, '\"') + '"');
    });

    Coca.Builder.addType('Array', function(ms) {
        this.members = ms || [];
    }, function(s) {
        return '[' + this.members.join(', ') + ']';
    }, {
        addMember: function(m) {
            this.members.push(m);
        }
    });

    Coca.Builder.addType('Object', function(o) {
        this.properties = o || {};
    }, function(s) {
        var ps = [];
        for (var p in this.properties)
            if (this.properties.hasOwnProperty(p))
                ps.push("'" + p + "':" + this.properties[p]);
        return '{' + ps.join(',') + '}';
    });

    Coca.Builder.addType('Group', null, function(s) {
        return '(' + s + ')';
    });

    Coca.Builder.addType('Function', function(name, args) {
        this.name = name || '';
        this.args = args || [];
    }, function(s) {
        return 'function ' + this.name + '(' + this.args.join(', ') + ') {' + s + '}';
    });

    Coca.Builder.addType('Invocation', function(args) {
        this.args = args || [];
    }, function(s) {
        return '(' + this.args.join(', ') + ')';
    });

    Coca.Builder.addType('Variables', function(vars) {
        this.vars = vars;
    }, function(s) {
        var vars = [];
        for (var i = 0, l = this.vars.length, v; i <  l; i++) {
            v = this.vars[i][0];
            if (this.vars[i].length > 1)
                v += ' = ' + this.vars[i][1];
            vars.push(v);
        }
        return 'var ' + vars.join(', ');
    });

    Coca.Builder.addType('Return', function(v) {
        this.push('return ');
        this.push(v);
        this.endStatement();
    });

    Coca.Builder.addType('If', function(e) {
        this.expr = e;
    }, function(s) {
        var src = 'if (' + this.expr + ') {' + s + '}';
        if (this['else'])
            src += this['else'];
        return src;
    }, {
        addElse: function() {
            return (this['else'] = new Coca.Builder.Else());
        }
    });

    Coca.Builder.addType('Else', null, function(s) {
        var src = 'else ';
        if (this['if'])
            src += this['if'];
        else
            src += '{' + s + '}';
        return src;
    }, {
        withIf: function(e) {
            return (this['if'] = new Coca.Builder.If(e));
        }
    });

    Coca.Builder.addType('For', function(init, test, step) {
        this.exprs = [init || '', test || '', step || ''];
    }, function(s) {
        return 'for (' + this.exprs.join(';') + ') {' + s + '}';
    });

    Coca.Builder.addType('ForIn', function(lh, e) {
        this.lh = lh;
        this.expr = e;
    }, function(s) {
        return 'for (' + this.lh + ' in ' + this.expr + ') {' + s + '}';
    });

    Coca.Builder.addType('Do', null, function(s) {
        var src = 'do {' + s + '}';
        if (this['while']) {
            src += this['while'];
            this.endStatement();
        }
        return src;
    }, {
        withWhile: function(e) {
            return (this['while'] = new Coca.Builder.While(e, true));
        }
    });

    Coca.Builder.addType('While', function(e, empty) {
        this.expr = e;
        this.empty = empty;
    }, function(s) {
        var src = 'while (' + this.expr + ')';
        if (this.empty)
            this.endStatement();
        else
            src += '{' + s + '}';
        return src;
    });

    Coca.Builder.addType('Switch', function(e) {
        this.expr = e;
    }, function(s) {
        return 'switch (' + this.expr + ') { ' + s + ' }';
    });

    Coca.Builder.addType('Case', function(e) {
        this.push('case ' + e + ':');
    });

    Coca.Builder.addType('Label', function(s) {
        this.push(s + ':');
    });

    Coca.Builder.addType('Throw', function(e) {
        this.push('throw ' + e);
        this.endStatement();
    });

    Coca.Builder.addType('Try', null, function(s) {
        var src = 'try {' + s + '}';
        if (this['catch'])
            src += this['catch'];
        if (this['finally'])
            src += this['finally'];
        return src;
    });

    Coca.Builder.addType('Catch', function(id) {
        this.id = id;
    }, function(s) {
        return 'catch (' + this.id + ') {' + s + '}';
    });

    Coca.Builder.addType('Finally', null, function(s) {
        return 'finally {' + s + '}';
    });

    Coca.Builder.addType('With', function(e) {
        this.expr = e;
    }, function(s) {
        return 'with (' + e + ') {' + s + '}';
    });
})();
<commit_msg>Builder: cleanup<commit_after>/**
 * @fileoverview An API for building JavaScript
 * @author Thomas Allen <thomasmallen@gmail.com>
 */
;(function() {
    /**
     * Usage:
     *     var s = new Coca.Builder.Group(),
     *         fn = s.addFunction('doSomething', ['a', 'b', 'c']);
     *     fn.addVariables([['a'], ['b', new Coca.Builder.Function('hello')]])
     *     fn.endStatement();
     *     fn.addIf('x < 2').addElse().withIf('y > 1');
     *     print(s);
     *     -> (function doSomething(a, b, c) {var a, b = function hello() {};if (x < 2) {}else if (y > 1) {}})
     */
    Coca.Builder = {
        /**
         * Base source builder.
         *
         * Does not perform validation; it is the responsibility of the user
         * to ensure that the API is used to create valid JavaScript code.
         */
        Source: function() {
            this.bits = [];
        },

        addType: function(type, fn, toString, ps) {
            var P = Coca.Builder.Source,
                C = function() {
                    P.apply(this);
                    if (fn)
                        if (typeof fn != 'function') {
                            this.push(fn);
                            this.endStatement();
                        } else fn.apply(this, arguments);
                };
            C.prototype = new P();
            C.prototype.toString = function() {
                var s = P.prototype.toString.apply(this);
                if (toString)
                    s = toString.call(this, s);
                return s;
            };
            if (ps)
                for (var p in ps)
                    if (ps.hasOwnProperty(p))
                        C.prototype[p] = ps[p];
            Coca.Builder[type] = C;
            P.prototype['add' + type] = function() {
                var o = new C();
                C.apply(o, arguments);
                return this.push(o);
            };
        }
    };

    Coca.Builder.Source.prototype.push = function(p) {
        this.bits.push(p);
        return p;
    };
    Coca.Builder.Source.prototype.toString = function() {
        return this.bits.join('');
    };
    Coca.Builder.Source.prototype.endStatement = function() {
        return this.push(';');
    };

    // Simple types
    Coca.Builder.addType('Empty', '');
    Coca.Builder.addType('Continue', 'continue');
    Coca.Builder.addType('Break', 'break');

    Coca.Builder.addType('Comment', function(c) {
        this.push('/* ' + c + '*/');
    });

    Coca.Builder.addType('String', function(s) {
        // This will go much better if we simply require JSON.stringify
        // and use that here, but I did not want to introduce that
        // requirement right now.
        this.push('"' + s.replace(/"/g, '\"') + '"');
    });

    Coca.Builder.addType('Array', function(ms) {
        this.members = ms || [];
    }, function(s) {
        return '[' + this.members.join(', ') + ']';
    }, {
        addMember: function(m) {
            this.members.push(m);
        }
    });

    Coca.Builder.addType('Object', function(o) {
        this.properties = o || {};
    }, function(s) {
        var ps = [];
        for (var p in this.properties)
            if (this.properties.hasOwnProperty(p))
                ps.push("'" + p + "':" + this.properties[p]);
        return '{' + ps.join(',') + '}';
    });

    Coca.Builder.addType('Group', null, function(s) {
        return '(' + s + ')';
    });

    Coca.Builder.addType('Function', function(name, args) {
        this.name = name || '';
        this.args = args || [];
    }, function(s) {
        return 'function ' + this.name + '(' + this.args.join(', ') + ') {' + s + '}';
    });

    Coca.Builder.addType('Invocation', function(args) {
        this.args = args || [];
    }, function(s) {
        return '(' + this.args.join(', ') + ')';
    });

    Coca.Builder.addType('Variables', function(vars) {
        this.vars = vars;
    }, function(s) {
        var vars = [];
        for (var i = 0, l = this.vars.length, v; i <  l; i++) {
            v = this.vars[i][0];
            if (this.vars[i].length > 1)
                v += ' = ' + this.vars[i][1];
            vars.push(v);
        }
        return 'var ' + vars.join(', ');
    });

    Coca.Builder.addType('Return', function(v) {
        this.push('return ');
        this.push(v);
        this.endStatement();
    });

    Coca.Builder.addType('If', function(e) {
        this.expr = e;
    }, function(s) {
        var src = 'if (' + this.expr + ') {' + s + '}';
        if (this['else'])
            src += this['else'];
        return src;
    }, {
        addElse: function() {
            return (this['else'] = new Coca.Builder.Else());
        }
    });

    Coca.Builder.addType('Else', null, function(s) {
        var src = 'else ';
        if (this['if'])
            src += this['if'];
        else
            src += '{' + s + '}';
        return src;
    }, {
        withIf: function(e) {
            return (this['if'] = new Coca.Builder.If(e));
        }
    });

    Coca.Builder.addType('For', function(init, test, step) {
        this.exprs = [init || '', test || '', step || ''];
    }, function(s) {
        return 'for (' + this.exprs.join(';') + ') {' + s + '}';
    });

    Coca.Builder.addType('ForIn', function(lh, e) {
        this.lh = lh;
        this.expr = e;
    }, function(s) {
        return 'for (' + this.lh + ' in ' + this.expr + ') {' + s + '}';
    });

    Coca.Builder.addType('Do', null, function(s) {
        var src = 'do {' + s + '}';
        if (this['while']) {
            src += this['while'];
            this.endStatement();
        }
        return src;
    }, {
        withWhile: function(e) {
            return (this['while'] = new Coca.Builder.While(e, true));
        }
    });

    Coca.Builder.addType('While', function(e, empty) {
        this.expr = e;
        this.empty = empty;
    }, function(s) {
        var src = 'while (' + this.expr + ')';
        if (this.empty)
            this.endStatement();
        else
            src += '{' + s + '}';
        return src;
    });

    Coca.Builder.addType('Switch', function(e) {
        this.expr = e;
    }, function(s) {
        return 'switch (' + this.expr + ') { ' + s + ' }';
    });

    Coca.Builder.addType('Case', function(e) {
        this.push('case ' + e + ':');
    });

    Coca.Builder.addType('Label', function(s) {
        this.push(s + ':');
    });

    Coca.Builder.addType('Throw', function(e) {
        this.push('throw ' + e);
        this.endStatement();
    });

    Coca.Builder.addType('Try', null, function(s) {
        var src = 'try {' + s + '}';
        if (this['catch'])
            src += this['catch'];
        if (this['finally'])
            src += this['finally'];
        return src;
    });

    Coca.Builder.addType('Catch', function(id) {
        this.id = id;
    }, function(s) {
        return 'catch (' + this.id + ') {' + s + '}';
    });

    Coca.Builder.addType('Finally', null, function(s) {
        return 'finally {' + s + '}';
    });

    Coca.Builder.addType('With', function(e) {
        this.expr = e;
    }, function(s) {
        return 'with (' + e + ') {' + s + '}';
    });
})();
<|endoftext|>