<commit_before>// Copyright 2002-2012, University of Colorado

var scenery = scenery || {};

(function(){
  "use strict";

  scenery.GraphPath = function( nodes ) {
    // TODO: consider adding index information
    this.nodes = nodes || [];
  };
  var GraphPath = scenery.GraphPath;

  GraphPath.prototype = {
    constructor: GraphPath,

    copy: function() {
      return new scenery.GraphPath( this.nodes.slice( 0 ) );
    },

    isEmpty: function() {
      return this.nodes.length === 0;
    },

    addAncestor: function( node ) {
      this.nodes.unshift( node );
    },

    removeAncestor: function() {
      this.nodes.shift();
    },

    addDescendant: function( node ) {
      this.nodes.push( node );
    },

    removeDescendant: function() {
      this.nodes.pop();
    },

    equals: function( other ) {
      if ( this.nodes.length !== other.nodes.length ) {
        return false;
      }

      for ( var i = 0; i < this.nodes.length; i++ ) {
        if ( this.nodes[i] !== other.nodes[i] ) {
          return false;
        }
      }

      return true;
    },

    /*
     * Iterates between this graph path and the other one, calling listener.enter( node ) and listener.exit( node ).
     * This will be bounded by listener.exit( startNode ) and listener.enter( endNode )
     */
    eachBetween: function( other, listener, reverseIfNecessary ) {
      var minPath = this;
      var maxPath = other;

      if ( reverseIfNecessary ) {
        var comparison = this.compare( other );
        minPath = comparison === -1 ? this : other;
        maxPath = comparison === -1 ? other : this;
      }

      var minSharedLength = Math.min( minPath.nodes.length, maxPath.nodes.length );

      // set to the length so if we don't find a first split, it is after the shared region
      var splitIndex = minSharedLength;
      for ( var i = 0; i < minSharedLength; i++ ) {
        if ( minPath.nodes[i] !== maxPath.nodes[i] ) {
          splitIndex = i;
          break;
        }
      }

      function recurse( node, depth, hasLowBound, hasHighBound ) {
        if ( !hasLowBound && !hasHighBound ) {
          listener.enter( node );
          _.each( node.children, function( child ) {
            recurse( child, depth + 1, false, false );
          } );
          listener.exit( node );
        } else {
          // we are now assured that minPath.nodes[depth] !== maxPath.nodes[depth] (at least as subpaths), so each child is either high-bounded or low-bounded

          if ( !hasLowBound ) {
            listener.enter( node );
          }

          var passedLowBound = !hasLowBound;

          for ( var i = 0; i < node.children.length; i++ ) {
            var child = node.children[i];

            if ( !passedLowBound ) {
              // if we haven't passed the low bound, it MUST exist, and we are either (a) not rendered, or (b) low-bounded

              if ( startPath[depth] === child ) {
                // only recursively render if the switch is "before" the node
                if ( startPath[depth]._layerBeforeRender === layer ) {
                  recursivePartialRender( child, depth + 1, startPath.length !== depth, false ); // if it has a low-bound, it can't have a high bound
                }

                // for later children, we have passed the low bound.
                passedLowBound = true;
              }

              // either way, go on to the next nodes
              continue;
            }

            if ( hasHighBound && endPath[depth] === child ) {
              // only recursively render if the switch is "after" the node
              if ( endPath[depth]._layerAfterRender === layer ) {
                // high-bounded here
                recursivePartialRender( child, depth + 1, false, endPath.length !== depth ); // if it has a high-bound, it can't have a low bound
              }

              // don't render any more children, since we passed the high bound
              break;
            }

          }
          if ( !hasHighBound ) {
            listener.exit( node );
          }
        }
      }

      recurse( minPath[splitIndex-1], splitIndex, minPath.nodes.length !== splitIndex, maxPath.nodes.length !== splitIndex );
    },

    /* Standard Java-style compare. -1 means this graph path is before (under) the other path, 0 means equal, and 1 means this path is
     * after (on top of) the other path.
     * A shorter subpath will compare as -1.
     */
    compare: function( other ) {
      phet.assert( !this.isEmpty() );
      phet.assert( !other.isEmpty() );
      phet.assert( this.nodes[0] === other.nodes[0] );

      var minIndex = Math.min( this.nodes.length, other.nodes.length );
      for ( var i = 1; i < minIndex; i++ ) {
        if ( this.nodes[i] !== other.nodes[i] ) {
          var myIndex = _.indexOf( this.nodes[i-1].children, this.nodes[i] );
          var otherIndex = _.indexOf( other.nodes[i-1].children, other.nodes[i] );
          phet.assert( myIndex !== otherIndex ); // they should be different if the nodes are different
          if ( myIndex < otherIndex ) {
            return -1;
          } else {
            return 1;
          }
        }
      }

      // we scanned through and no nodes were different (one is a subpath of the other)
      if ( this.nodes.length < other.nodes.length ) {
        return -1;
      } else if ( this.nodes.length > other.nodes.length ) {
        return 1;
      } else {
        return 0;
      }
    }
  };

})();

<commit_msg>GraphPath.eachBetween somewhat copied and not verified yet<commit_after>// Copyright 2002-2012, University of Colorado

var scenery = scenery || {};

(function(){
  "use strict";

  scenery.GraphPath = function( nodes ) {
    // TODO: consider adding index information
    this.nodes = nodes || [];
  };
  var GraphPath = scenery.GraphPath;

  GraphPath.prototype = {
    constructor: GraphPath,

    copy: function() {
      return new scenery.GraphPath( this.nodes.slice( 0 ) );
    },

    isEmpty: function() {
      return this.nodes.length === 0;
    },

    addAncestor: function( node ) {
      this.nodes.unshift( node );
    },

    removeAncestor: function() {
      this.nodes.shift();
    },

    addDescendant: function( node ) {
      this.nodes.push( node );
    },

    removeDescendant: function() {
      this.nodes.pop();
    },

    equals: function( other ) {
      if ( this.nodes.length !== other.nodes.length ) {
        return false;
      }

      for ( var i = 0; i < this.nodes.length; i++ ) {
        if ( this.nodes[i] !== other.nodes[i] ) {
          return false;
        }
      }

      return true;
    },

    /*
     * Iterates between this graph path and the other one, calling listener.enter( node ) and listener.exit( node ).
     * This will be bounded by listener.exit( startNode ) and listener.enter( endNode )
     */
    eachBetween: function( other, listener, reverseIfNecessary ) {
      var minPath = this;
      var maxPath = other;

      if ( reverseIfNecessary ) {
        var comparison = this.compare( other );
        minPath = comparison === -1 ? this : other;
        maxPath = comparison === -1 ? other : this;
      }

      var minSharedLength = Math.min( minPath.nodes.length, maxPath.nodes.length );

      // set to the length so if we don't find a first split, it is after the shared region
      var splitIndex = minSharedLength;
      for ( var i = 0; i < minSharedLength; i++ ) {
        if ( minPath.nodes[i] !== maxPath.nodes[i] ) {
          splitIndex = i;
          break;
        }
      }

      function recurse( node, depth, hasLowBound, hasHighBound ) {
        if ( !hasLowBound && !hasHighBound ) {
          listener.enter( node );
          _.each( node.children, function( child ) {
            recurse( child, depth + 1, false, false );
          } );
          listener.exit( node );
        } else {
          // we are now assured that minPath.nodes[depth] !== maxPath.nodes[depth] (at least as subpaths), so each child is either high-bounded or low-bounded

          if ( !hasLowBound ) {
            listener.enter( node );
          }

          var passedLowBound = !hasLowBound;

          for ( var i = 0; i < node.children.length; i++ ) {
            var child = node.children[i];

            if ( !passedLowBound ) {
              // if we haven't passed the low bound, it MUST exist, and we are either (a) not rendered, or (b) low-bounded

              if ( minPath.nodes[depth] === child ) {
                recurse( child, depth + 1, minPath.nodes.length !== depth, false ); // if it has a low-bound, it can't have a high bound

                // for later children, we have passed the low bound.
                passedLowBound = true;
              }

              // either way, go on to the next nodes
              continue;
            }

            if ( hasHighBound && maxPath.nodes[depth] === child ) {
              recurse( child, depth + 1, false, maxPath.nodes.length !== depth ); // if it has a high-bound, it can't have a low bound

              // don't handle any more children, since we passed the high bound
              break;
            }
          }

          if ( !hasHighBound ) {
            listener.exit( node );
          }
        }
      }

      recurse( minPath[splitIndex-1], splitIndex, minPath.nodes.length !== splitIndex, maxPath.nodes.length !== splitIndex );
    },

    /* Standard Java-style compare. -1 means this graph path is before (under) the other path, 0 means equal, and 1 means this path is
     * after (on top of) the other path.
     * A shorter subpath will compare as -1.
     */
    compare: function( other ) {
      phet.assert( !this.isEmpty() );
      phet.assert( !other.isEmpty() );
      phet.assert( this.nodes[0] === other.nodes[0] );

      var minIndex = Math.min( this.nodes.length, other.nodes.length );
      for ( var i = 1; i < minIndex; i++ ) {
        if ( this.nodes[i] !== other.nodes[i] ) {
          var myIndex = _.indexOf( this.nodes[i-1].children, this.nodes[i] );
          var otherIndex = _.indexOf( other.nodes[i-1].children, other.nodes[i] );
          phet.assert( myIndex !== otherIndex ); // they should be different if the nodes are different
          if ( myIndex < otherIndex ) {
            return -1;
          } else {
            return 1;
          }
        }
      }

      // we scanned through and no nodes were different (one is a subpath of the other)
      if ( this.nodes.length < other.nodes.length ) {
        return -1;
      } else if ( this.nodes.length > other.nodes.length ) {
        return 1;
      } else {
        return 0;
      }
    }
  };

})();

<|endoftext|>


<commit_before>import Frame from './Frame';
import {ReactComponent as CloseIcon} from '../images/icons/close.svg';
import {hasMode} from '../utils/check-mode';
import AppContext from '../AppContext';
import FrameStyle from './Frame.styles';
import Pages, {getActivePage} from '../pages';

const React = require('react');

const StylesWrapper = ({member}) => {
    return {
        modalContainer: {
            zIndex: '1000',
            position: 'fixed',
            left: '0',
            top: '0',
            width: '100%',
            height: '100%',
            overflow: 'hidden'
        },
        frame: {
            common: {
                margin: 'auto',
                position: 'relative',
                padding: '0',
                outline: '0',
                width: '100%',
                opacity: '1',
                overflow: 'hidden',
                height: '100%'
            }
        },
        page: {
            links: {
                width: '600px'
            }
        }
    };
};

class PopupContent extends React.Component {
    static contextType = AppContext;

    constructor(props) {
        super(props);
        this.state = { };
        this.container = React.createRef();
    }

    renderActivePage() {
        const {page} = this.context;
        getActivePage({page});
        const PageComponent = Pages[page];

        return (
            <PageComponent />
        );
    }

    renderPopupClose() {
        return (

                <CloseIcon className='gh-portal-closeicon' onClick = {() => this.context.onAction('closePopup')} />

        );
    }

    render() {
        const {page} = this.context;
        getActivePage({page});
        const Styles = StylesWrapper({page});
        const pageStyle = {
            ...Styles.page[page]
        };
        return (

                {this.renderPopupClose()}
                {this.renderActivePage()}

        );
    }
}

export default class PopupModal extends React.Component {
    static contextType = AppContext;

    constructor(props) {
        super(props);
        this.state = {
            height: null
        };
    }

    renderCurrentPage(page) {
        const PageComponent = Pages[page];

        return (
            <PageComponent />
        );
    }

    onHeightChange(height) {
        this.setState({height});
    }

    renderPopupClose() {
        return (

                <CloseIcon className='gh-portal-closeicon' onClick = {() => this.context.onAction('closePopup')} />

        );
    }

    handlePopupClose(e) {
        e.preventDefault();
        if (e.target === e.currentTarget) {
            this.context.onAction('closePopup');
        }
    }

    renderFrameStyles() {
        const styles = `
            :root {
                --brandcolor: ${this.context.brandColor}
            }
        ` + FrameStyle;
        return (


<commit_before>define(function () {
  // Czech
  function small (count, masc) {
    switch(count) {
      case 2:
        return masc ? "dva" : "dvě";
      case 3:
        return "tři";
      case 4:
        return "čtyři";
    }
    return "";
  }
  return {
    errorLoading: function () {
      return 'Výsledky nemohly být načteny.';
    },
    inputTooLong: function (args) {
      var n = args.input.length - args.maximum;

      if (n == 1) {
        return "Prosím zadejte o jeden znak méně";
      } else if (n <= 4) {
        return "Prosím zadejte o " + small(n, true) + " znaky méně";
      } else {
        return "Prosím zadejte o " + n + " znaků méně";
      }
    },
    inputTooShort: function (args) {
      var n = args.minimum - args.input.length;

      if (n == 1) {
        return "Prosím zadejte ještě jeden znak";
      } else if (n <= 4) {
        return "Prosím zadejte ještě další " + small(n, true) + " znaky";
      } else {
        return "Prosím zadejte ještě dalších " + n + " znaků";
      }
    },
    loadingMore: function () {
      return 'Načítají se další výsledky…';
    },
    maximumSelected: function (args) {
      var n = args.maximum;

      if (n == 1) {
        return "Můžete zvolit jen jednu položku";
      } else if (n <= 4) {
        return "Můžete zvolit maximálně " + small(n, false) + " položky";
      } else {
        return "Můžete zvolit maximálně " + n + " položek";
      }
    },
    noResults: function () {
      return 'Nenalezeny žádné položky';
    },
    searching: function () {
      return 'Vyhledávání…';
    }
  };
});
<commit_msg>Added czech translations - fix<commit_after>define(function () {
  // Czech
  function small (count, masc) {
    switch(count) {
      case 2:
        return masc ? 'dva' : 'dvě';
      case 3:
        return 'tři';
      case 4:
        return 'čtyři';
    }
    return '';
  }
  return {
    errorLoading: function () {
      return 'Výsledky nemohly být načteny.';
    },
    inputTooLong: function (args) {
      var n = args.input.length - args.maximum;

      if (n == 1) {
        return 'Prosím zadejte o jeden znak méně';
      } else if (n <= 4) {
        return 'Prosím zadejte o ' + small(n, true) + ' znaky méně';
      } else {
        return 'Prosím zadejte o ' + n + ' znaků méně';
      }
    },
    inputTooShort: function (args) {
      var n = args.minimum - args.input.length;

      if (n == 1) {
        return 'Prosím zadejte ještě jeden znak';
      } else if (n <= 4) {
        return 'Prosím zadejte ještě další ' + small(n, true) + ' znaky';
      } else {
        return 'Prosím zadejte ještě dalších ' + n + ' znaků';
      }
    },
    loadingMore: function () {
      return 'Načítají se další výsledky…';
    },
    maximumSelected: function (args) {
      var n = args.maximum;

      if (n == 1) {
        return 'Můžete zvolit jen jednu položku';
      } else if (n <= 4) {
        return 'Můžete zvolit maximálně ' + small(n, false) + ' položky';
      } else {
        return 'Můžete zvolit maximálně ' + n + ' položek';
      }
    },
    noResults: function () {
      return 'Nenalezeny žádné položky';
    },
    searching: function () {
      return 'Vyhledávání…';
    }
  };
});
<|endoftext|>


<commit_before>// consts
var GLOBAL = this;
var B_HOST = 'b.hatena.ne.jp';
var B_HTTP = 'http://' + B_HOST + '/';
var B_STATIC_HOST = 'cdn-ak.b.st-hatena.com';
var B_STATIC_HTTP = 'http://' + B_STATIC_HOST + '/';
var B_API_STATIC_HOST = 'api.b.st-hatena.com';
var B_API_STATIC_HTTP = 'http://' + B_API_STATIC_HOST + '/';

// utility
var p = function() {
    // console.log(JSON.stringify(Array.prototype.slice.call(arguments, 0, arguments.length)));
}

var sprintf = function (str) {
    var args = Array.prototype.slice.call(arguments, 1);
    return str.replace(/%0(\d+)d/g, function(m, num) {
        var r = String(args.shift());
        var c = '';
        num = parseInt(num, 10) - r.length;
        while (--num >= 0) c += '0';
        return c + r;
    }).replace(/%[sdf]/g, function(m) { return sprintf._SPRINTF_HASH[m](args.shift()) });
};

sprintf._SPRINTF_HASH = {
    '%s': String,
    '%d': function (n) { return parseInt(n, 10); },
    '%f': parseFloat
};

var $K = function(i) { return function() { return i } };

var Utils = {
    inject: function(source, names, target) {
        if (!target) target = GLOBAL;
        for (var i = 0;  i < names.length; i++) {
            var name = names[i];
            if (source[name]) {
                target[name] = source[name];
            } else {
                throw new Error('' + name + ' is not found');
            }
        }
    },
    truncate: function(str, size, suffix) {
        if (!str) str = '';
        if (!size) size = 32;
        if (!suffix) suffix = '...';
        var b = 0;
        for (var i = 0;  i < str.length; i++) {
            b += str.charCodeAt(i) <= 255 ? 1 : 2;
            if (b > size) {
                return str.substr(0, i) + suffix;
            }
        }
        return str;
    },
    isString: function(obj) {
        return typeof obj === 'string' || obj instanceof String;
    },
    strToDate: function(dateStr) {
        // dateStr // yyyymmddhhmmss
        return new Date(
            dateStr.substr(0,4),
            parseInt(dateStr.substr(4,2), 10) - 1,
            dateStr.substr(6,2),
            dateStr.substr(8,2),
            dateStr.substr(10,2),
            dateStr.substr(12,2)
        );
    },
    coolURL: function(url, len) {
        var u = url.
          replace(/^https?:\/\//, '').
          replace(/\.[^\/]+$/, '');
        return Utils.truncate(u, len || 40);
    },
    randomString: function(len) {
        var str = '01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        var sLen = str.length;
        var res = '';
        for (var i = 0; i < len; i++) {
            res += str.charAt(Math.floor(Math.random() * sLen));
        }
        return res;
    },
    escapeHTML: function(str) {
        return str.replace(/&/g, '&').
                   replace(/</g, '<').
                   replace(/>/g, '>');
    },
    countCommentToBytes: function(comment) {
        var bytes = 0;
        for (var i = 0;  i < comment.length; i++) {
            bytes += comment.charCodeAt(i) <= 255 ? 1 : 3;
        }
        return bytes;
    },
    ljust: function(str, len, char) {
        str = str.toString();
        char = char.toString();
        if (char.length == 0)
            char = '0';
        while (str.length < len) {
            str = char + str;
        }
        return str;
    },
    entryURL: function(url) {
        return B_HTTP + 'entry/' + url.replace('#', '%23');
    },
    entryImage: function(url) {
        return B_STATIC_HTTP + 'entry/image/' + url.replace('#', '%23');
    },
    faviconUrl: function(url) {
        return 'http://favicon.hatena.ne.jp/?url=' + encodeURIComponent(url.replace('#', '%23'));
    },
    createElementSimply: function(name, attr) {
        var children = Array.prototype.slice.call(arguments, 2);
        var e = document.createElement(name);
        if (attr)
            for (var key in attr)
                e[key] = attr[key];

        children.map(function(el) { return el.nodeType > 0 ? el : document.createTextNode(el) }).
            forEach(function(el) { return e.appendChild(el) });
        return e;
    },
    createElementFromString: function (str, opts) {
        // original code by cho45 - http://gist.github.com/3239
        if (!opts) opts = { data: {} };
        var document = opts.document || window.document;
        if (!opts.data) opts.data = { };
        var t, cur = opts.parent || document.createDocumentFragment(), root, stack = [cur];
        while (str.length) {
            if (str.indexOf("<") == 0) {
                if ((t = str.match(/^\s*<(\/?[^\s>\/]+)([^>]+?)?(\/)?>/))) {
                    var tag = t[1], attrs = t[2], isempty = !!t[3];
                    if (tag.indexOf("/") == -1) {
                        child = document.createElement(tag);
                        if (attrs) attrs.replace(/([a-z]+)=(?:'([^']+)'|"([^"]+)")/gi,
                            function (m, name, v1, v2) {
                                var v = text(v1 || v2);
                                if (name == "class") root && (root[v] = child), child.className = v;
                                child.setAttribute(name, v);
                            }
                        );
                        cur.appendChild(root ? child : (root = child));
                        if (!isempty) {
                            stack.push(cur);
                            cur = child;
                        }
                    } else cur = stack.pop();
                } else throw("Parse Error: " + str);
            } else {
                if ((t = str.match(/^([^<]+)/))) cur.appendChild(document.createTextNode(text(t[0])));
            }
            str = str.substring(t[0].length);
        }
        function text (str) {
            return str
                .replace(/&(#(x)?)?([^;]+);/g, function (_, isNumRef, isHex, ref) {
                    return isNumRef ? String.fromCharCode(parseInt(ref, isHex ? 16 : 10)):
                                      {"lt":"<","gt":"<","amp":"&"}[ref];
                })
                .replace(/#\{([^}]+)\}/g, function (_, name) {
                    return (typeof(opts.data[name]) == "undefined") ? _ : opts.data[name];
                });
        }
        return root;
    }
}

Utils.createElementSimply.t = function(text) { return document.createTextNode(text) }

if (typeof Deferred != 'undefined') {
    if (Deferred.WebDatabase) {
        var Database = Deferred.WebDatabase;
        // Database.debugMessage = true;
        var Model = Database.Model, SQL = Database.SQL;
    }

    Deferred.onerror = function(e) { console.error(e);console.error(e.stack) };

    Deferred.retry = function(retryCount, funcDeffered/* funcDeffered() return Deferred */, options) {
        if (typeof retryCount == 'undefined')
            retryCount == 1;
        if (!options) options = {};

        var wait = options.wait || 0;
        var d = new Deferred();
        var retry = function() {
            var m = funcDeffered(retryCount);
            m.next(function(mes) {
                d.call(mes);
            }).error(function(e) {
                if (--retryCount <= 0) {
                    d.fail(['retry failed', e]);
                } else {
                    setTimeout(retry, wait * 1000);
                }
            });
        };
        setTimeout(retry, 0);
        return d;
    }
}

if (typeof jQuery != 'undefined') {
    // setter/getter extend version
    jQuery.extend = jQuery.fn.extend = function() {
        // copy reference to target object
        var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;

        // Handle a deep copy situation
        if ( typeof target === "boolean" ) {
            deep = target;
            target = arguments[1] || {};
            // skip the boolean and the target
            i = 2;
        }

        // Handle case when target is a string or something (possible in deep copy)
        if ( typeof target !== "object" && !jQuery.isFunction(target) )
            target = {};

        // extend jQuery itself if only one argument is passed
        if ( length == i ) {
            target = this;
            --i;
        }

        for ( ; i < length; i++ )
            // Only deal with non-null/undefined values
            if ( (options = arguments[ i ]) != null )
                // Extend the base object
                for ( var name in options ) {
                    var getterFlag = false;
                    var src, copy;
                    if ( options.__lookupGetter__ &&  options.__lookupGetter__(name) !== undefined ) {
                        target.__defineGetter__(name, options.__lookupGetter__(name));
                        getterFlag = true;
                    } else {
                        copy = options[ name ];
                    }

                    // Prevent never-ending loop
                    if ( target === copy )
                        continue;

                    // Recurse if we're merging object values
                    if ( deep && !getterFlag && copy && typeof copy === "object" && !copy.nodeType ) {
                        src = target[ name ];
                        target[ name ] = jQuery.extend( deep,
                            // Never move original objects, clone them
                            src || ( copy.length != null ? [ ] : { } )
                        , copy );

                    // Don't bring in undefined values
                    } else {
                        if ( options.__lookupSetter__ && options.__lookupSetter__(name) !== undefined ) {
                            target.__defineSetter__(name, options.__lookupSetter__(name));
                        }
                        if ( copy !== undefined && !getterFlag) {
                            target[ name ] = copy;
                        }
                    }

                }

        // Return the modified object
        return target;
    };

    jQuery.httpSuccess = function( xhr ) {
        try {
            // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
            return !xhr.status && (location.protocol == "file:" || location.protocol == "chrome-extension:") ||
                ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223;
        } catch(e){}
        return false;
    };

}
<commit_msg>画像修正。<commit_after>// consts
var GLOBAL = this;
var B_HOST = 'b.hatena.ne.jp';
var B_HTTP = 'http://' + B_HOST + '/';
var B_STATIC_HOST = 'cdn-ak.b.st-hatena.com';
var B_STATIC_HTTP = 'http://' + B_STATIC_HOST + '/';
var B_API_STATIC_HOST = 'api.b.st-hatena.com';
var B_API_STATIC_HTTP = 'http://' + B_API_STATIC_HOST + '/';

// utility
var p = function() {
    // console.log(JSON.stringify(Array.prototype.slice.call(arguments, 0, arguments.length)));
}

var sprintf = function (str) {
    var args = Array.prototype.slice.call(arguments, 1);
    return str.replace(/%0(\d+)d/g, function(m, num) {
        var r = String(args.shift());
        var c = '';
        num = parseInt(num, 10) - r.length;
        while (--num >= 0) c += '0';
        return c + r;
    }).replace(/%[sdf]/g, function(m) { return sprintf._SPRINTF_HASH[m](args.shift()) });
};

sprintf._SPRINTF_HASH = {
    '%s': String,
    '%d': function (n) { return parseInt(n, 10); },
    '%f': parseFloat
};

var $K = function(i) { return function() { return i } };

var Utils = {
    inject: function(source, names, target) {
        if (!target) target = GLOBAL;
        for (var i = 0;  i < names.length; i++) {
            var name = names[i];
            if (source[name]) {
                target[name] = source[name];
            } else {
                throw new Error('' + name + ' is not found');
            }
        }
    },
    truncate: function(str, size, suffix) {
        if (!str) str = '';
        if (!size) size = 32;
        if (!suffix) suffix = '...';
        var b = 0;
        for (var i = 0;  i < str.length; i++) {
            b += str.charCodeAt(i) <= 255 ? 1 : 2;
            if (b > size) {
                return str.substr(0, i) + suffix;
            }
        }
        return str;
    },
    isString: function(obj) {
        return typeof obj === 'string' || obj instanceof String;
    },
    strToDate: function(dateStr) {
        // dateStr // yyyymmddhhmmss
        return new Date(
            dateStr.substr(0,4),
            parseInt(dateStr.substr(4,2), 10) - 1,
            dateStr.substr(6,2),
            dateStr.substr(8,2),
            dateStr.substr(10,2),
            dateStr.substr(12,2)
        );
    },
    coolURL: function(url, len) {
        var u = url.
          replace(/^https?:\/\//, '').
          replace(/\.[^\/]+$/, '');
        return Utils.truncate(u, len || 40);
    },
    randomString: function(len) {
        var str = '01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        var sLen = str.length;
        var res = '';
        for (var i = 0; i < len; i++) {
            res += str.charAt(Math.floor(Math.random() * sLen));
        }
        return res;
    },
    escapeHTML: function(str) {
        return str.replace(/&/g, '&').
                   replace(/</g, '<').
                   replace(/>/g, '>');
    },
    countCommentToBytes: function(comment) {
        var bytes = 0;
        for (var i = 0;  i < comment.length; i++) {
            bytes += comment.charCodeAt(i) <= 255 ? 1 : 3;
        }
        return bytes;
    },
    ljust: function(str, len, char) {
        str = str.toString();
        char = char.toString();
        if (char.length == 0)
            char = '0';
        while (str.length < len) {
            str = char + str;
        }
        return str;
    },
    entryURL: function(url) {
        return B_HTTP + 'entry/' + url.replace('#', '%23');
    },
    entryImage: function(url) {
        return 'http://b.st-hatena.com/entry/image/' + url.replace('#', '%23');
    },
    faviconUrl: function(url) {
        return 'http://cdn-ak.favicon.st-hatena.com/?url=' + encodeURIComponent(url.replace('#', '%23'));
    },
    createElementSimply: function(name, attr) {
        var children = Array.prototype.slice.call(arguments, 2);
        var e = document.createElement(name);
        if (attr)
            for (var key in attr)
                e[key] = attr[key];

        children.map(function(el) { return el.nodeType > 0 ? el : document.createTextNode(el) }).
            forEach(function(el) { return e.appendChild(el) });
        return e;
    },
    createElementFromString: function (str, opts) {
        // original code by cho45 - http://gist.github.com/3239
        if (!opts) opts = { data: {} };
        var document = opts.document || window.document;
        if (!opts.data) opts.data = { };
        var t, cur = opts.parent || document.createDocumentFragment(), root, stack = [cur];
        while (str.length) {
            if (str.indexOf("<") == 0) {
                if ((t = str.match(/^\s*<(\/?[^\s>\/]+)([^>]+?)?(\/)?>/))) {
                    var tag = t[1], attrs = t[2], isempty = !!t[3];
                    if (tag.indexOf("/") == -1) {
                        child = document.createElement(tag);
                        if (attrs) attrs.replace(/([a-z]+)=(?:'([^']+)'|"([^"]+)")/gi,
                            function (m, name, v1, v2) {
                                var v = text(v1 || v2);
                                if (name == "class") root && (root[v] = child), child.className = v;
                                child.setAttribute(name, v);
                            }
                        );
                        cur.appendChild(root ? child : (root = child));
                        if (!isempty) {
                            stack.push(cur);
                            cur = child;
                        }
                    } else cur = stack.pop();
                } else throw("Parse Error: " + str);
            } else {
                if ((t = str.match(/^([^<]+)/))) cur.appendChild(document.createTextNode(text(t[0])));
            }
            str = str.substring(t[0].length);
        }
        function text (str) {
            return str
                .replace(/&(#(x)?)?([^;]+);/g, function (_, isNumRef, isHex, ref) {
                    return isNumRef ? String.fromCharCode(parseInt(ref, isHex ? 16 : 10)):
                                      {"lt":"<","gt":"<","amp":"&"}[ref];
                })
                .replace(/#\{([^}]+)\}/g, function (_, name) {
                    return (typeof(opts.data[name]) == "undefined") ? _ : opts.data[name];
                });
        }
        return root;
    }
}

Utils.createElementSimply.t = function(text) { return document.createTextNode(text) }

if (typeof Deferred != 'undefined') {
    if (Deferred.WebDatabase) {
        var Database = Deferred.WebDatabase;
        // Database.debugMessage = true;
        var Model = Database.Model, SQL = Database.SQL;
    }

    Deferred.onerror = function(e) { console.error(e);console.error(e.stack) };

    Deferred.retry = function(retryCount, funcDeffered/* funcDeffered() return Deferred */, options) {
        if (typeof retryCount == 'undefined')
            retryCount == 1;
        if (!options) options = {};

        var wait = options.wait || 0;
        var d = new Deferred();
        var retry = function() {
            var m = funcDeffered(retryCount);
            m.next(function(mes) {
                d.call(mes);
            }).error(function(e) {
                if (--retryCount <= 0) {
                    d.fail(['retry failed', e]);
                } else {
                    setTimeout(retry, wait * 1000);
                }
            });
        };
        setTimeout(retry, 0);
        return d;
    }
}

if (typeof jQuery != 'undefined') {
    // setter/getter extend version
    jQuery.extend = jQuery.fn.extend = function() {
        // copy reference to target object
        var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;

        // Handle a deep copy situation
        if ( typeof target === "boolean" ) {
            deep = target;
            target = arguments[1] || {};
            // skip the boolean and the target
            i = 2;
        }

        // Handle case when target is a string or something (possible in deep copy)
        if ( typeof target !== "object" && !jQuery.isFunction(target) )
            target = {};

        // extend jQuery itself if only one argument is passed
        if ( length == i ) {
            target = this;
            --i;
        }

        for ( ; i < length; i++ )
            // Only deal with non-null/undefined values
            if ( (options = arguments[ i ]) != null )
                // Extend the base object
                for ( var name in options ) {
                    var getterFlag = false;
                    var src, copy;
                    if ( options.__lookupGetter__ &&  options.__lookupGetter__(name) !== undefined ) {
                        target.__defineGetter__(name, options.__lookupGetter__(name));
                        getterFlag = true;
                    } else {
                        copy = options[ name ];
                    }

                    // Prevent never-ending loop
                    if ( target === copy )
                        continue;

                    // Recurse if we're merging object values
                    if ( deep && !getterFlag && copy && typeof copy === "object" && !copy.nodeType ) {
                        src = target[ name ];
                        target[ name ] = jQuery.extend( deep,
                            // Never move original objects, clone them
                            src || ( copy.length != null ? [ ] : { } )
                        , copy );

                    // Don't bring in undefined values
                    } else {
                        if ( options.__lookupSetter__ && options.__lookupSetter__(name) !== undefined ) {
                            target.__defineSetter__(name, options.__lookupSetter__(name));
                        }
                        if ( copy !== undefined && !getterFlag) {
                            target[ name ] = copy;
                        }
                    }

                }

        // Return the modified object
        return target;
    };

    jQuery.httpSuccess = function( xhr ) {
        try {
            // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
            return !xhr.status && (location.protocol == "file:" || location.protocol == "chrome-extension:") ||
                ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223;
        } catch(e){}
        return false;
    };

}
<|endoftext|>


<commit_before>'use strict';

angular.module('copayApp.services')
  .factory('trezor', function($log, $timeout, gettext, lodash, bitcore, hwWallet) {
    var root = {};

    var SETTLE_TIME = 3000;
    root.callbacks = {};

    root.getEntropySource = function(isMultisig, account, callback) {
      root.getXPubKey(hwWallet.getEntropyPath('trezor', isMultisig, account), function(data) {
        if (!data.success)
          return callback(hwWallet._err(data));

        return callback(null,  hwWallet.pubKeyToEntropySource(data.xpubkey));
      });
    };

    root.getXPubKey = function(path, callback) {
      $log.debug('TREZOR deriving xPub path:', path);
      TrezorConnect.getXPubKey(path, callback);
    };

    root.getInfoForNewWallet = function(isMultisig, account, callback) {
      var opts = {};
      root.getEntropySource(isMultisig, account, function(err, data) {
        if (err) return callback(err);
        opts.entropySource = data;
        $log.debug('Waiting TREZOR to settle...');
        $timeout(function() {

          root.getXPubKey(hwWallet.getAddressPath('trezor', isMultisig, account), function(data) {
            if (!data.success)
              return callback(hwWallet._err(data));

            opts.extendedPublicKey = data.xpubkey;
            opts.externalSource = 'trezor';
            opts.account = account;

            if (isMultisig)
              opts.derivationStrategy = 'BIP48';

            return callback(null, opts);
          });
        }, SETTLE_TIME);
      });
    };

    root._orderPubKeys = function(xPub, np) {
      var xPubKeys = lodash.clone(xPub);
      var path = lodash.clone(np);
      path.unshift('m');
      path = path.join('/');

      var keys = lodash.map(xPubKeys, function(x) {
        var pub = (new bitcore.HDPublicKey(x)).derive(path).publicKey;
        return {
          xpub: x,
          pub: pub.toString('hex'),
        };
      });

      var sorted = lodash.sortBy(keys, function(x) {
        return x.pub;
      });

      return lodash.pluck(sorted, 'xpub');
    };

    root.signTx = function(xPubKeys, txp, account, callback) {

      var inputs = [],
        outputs = [];
      var tmpOutputs = [];

      if (txp.type != 'simple')
        return callback('Only TXPs type SIMPLE are supported in TREZOR');

      var toScriptType = 'PAYTOADDRESS';
      if (txp.toAddress.charAt(0) == '2' || txp.toAddress.charAt(0) == '3')
        toScriptType = 'PAYTOSCRIPTHASH';

      // Add to
      tmpOutputs.push({
        address: txp.toAddress,
        amount: txp.amount,
        script_type: toScriptType,
      });

      if (txp.addressType == 'P2PKH') {

        $log.debug("Trezor signing uni-sig p2pkh. Account:", account);

        var inAmount = 0;
        inputs = lodash.map(txp.inputs, function(i) {
          $log.debug("Trezor TX input path:", i.path);
          var pathArr = i.path.split('/');
          var n = [hwWallet.UNISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])];
          inAmount += i.satoshis;
          return {
            address_n: n,
            prev_index: i.vout,
            prev_hash: i.txid,
          };
        });

        var change = inAmount - txp.fee - txp.amount;
        if (change > 0) {
          $log.debug("Trezor TX change path:", txp.changeAddress.path);
          var pathArr = txp.changeAddress.path.split('/');
          var n = [hwWallet.UNISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])];

          tmpOutputs.push({
            address_n: n,
            amount: change,
            script_type: 'PAYTOADDRESS'
          });
        }

      } else {

        // P2SH Wallet, multisig wallet
        var inAmount = 0;
        $log.debug("Trezor signing multi-sig p2sh. Account:", account);

        var sigs = xPubKeys.map(function(v) {
          return '';
        });

        inputs = lodash.map(txp.inputs, function(i) {
          $log.debug("Trezor TX input path:", i.path);
          var pathArr = i.path.split('/');
          var n = [hwWallet.MULTISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])];
          var np = n.slice(3);

          inAmount += i.satoshis;

          var orderedPubKeys = root._orderPubKeys(xPubKeys, np);
          var pubkeys = lodash(orderedPubKeys.map(function(v) {
            return {
              node: v,
              address_n: np,
            };
          }));

          return {
            address_n: n,
            prev_index: i.vout,
            prev_hash: i.txid,
            script_type: 'SPENDMULTISIG',
            multisig: {
              pubkeys: pubkeys,
              signatures: sigs,
              m: txp.requiredSignatures,
            }
          };
        });

        var change = inAmount - txp.fee - txp.amount;
        if (change > 0) {
          $log.debug("Trezor TX change path:", txp.changeAddress.path);
          var pathArr = txp.changeAddress.path.split('/');
          var n = [hwWallet.MULTISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])];
          var np = n.slice(3);

          var orderedPubKeys = root._orderPubKeys(xPubKeys, np);
          var pubkeys = lodash(orderedPubKeys.map(function(v) {
            return {
              node: v,
              address_n: np,
            };
          }));

          tmpOutputs.push({
            address_n: n,
            amount: change,
            script_type: 'PAYTOMULTISIG',
            multisig: {
              pubkeys: pubkeys,
              signatures: sigs,
              m: txp.requiredSignatures,
            }
          });
        }
      }

      // Shuffle outputs for improved privacy
      if (tmpOutputs.length > 1) {
        outputs = new Array(tmpOutputs.length);
        lodash.each(txp.outputOrder, function(order) {
          outputs[order] = tmpOutputs.shift();
        });

        if (tmpOutputs.length)
          return cb("Error creating transaction: tmpOutput order");
      } else {
        outputs = tmpOutputs;
      }

      // Prevents: Uncaught DataCloneError: Failed to execute 'postMessage' on 'Window': An object could not be cloned.
      inputs = JSON.parse(JSON.stringify(inputs));
      outputs = JSON.parse(JSON.stringify(outputs));

      $log.debug('Signing with TREZOR', inputs, outputs);
      TrezorConnect.signTx(inputs, outputs, function(res) {
        if (!res.success)
          return callback(hwWallet._err(res));

        callback(null, res);
      });
    };

    return root;
  });
<commit_msg>fix trezor<commit_after>'use strict';

angular.module('copayApp.services')
  .factory('trezor', function($log, $timeout, gettext, lodash, bitcore, hwWallet) {
    var root = {};

    var SETTLE_TIME = 3000;
    root.callbacks = {};

    root.getEntropySource = function(isMultisig, account, callback) {
      root.getXPubKey(hwWallet.getEntropyPath('trezor', isMultisig, account), function(data) {
        if (!data.success)
          return callback(hwWallet._err(data));

        return callback(null, hwWallet.pubKeyToEntropySource(data.xpubkey));
      });
    };

    root.getXPubKey = function(path, callback) {
      $log.debug('TREZOR deriving xPub path:', path);
      TrezorConnect.getXPubKey(path, callback);
    };

    root.getInfoForNewWallet = function(isMultisig, account, callback) {
      var opts = {};
      root.getEntropySource(isMultisig, account, function(err, data) {
        if (err) return callback(err);
        opts.entropySource = data;
        $log.debug('Waiting TREZOR to settle...');
        $timeout(function() {

          root.getXPubKey(hwWallet.getAddressPath('trezor', isMultisig, account), function(data) {
            if (!data.success)
              return callback(hwWallet._err(data));

            opts.extendedPublicKey = data.xpubkey;
            opts.externalSource = 'trezor';
            opts.account = account;

            if (isMultisig)
              opts.derivationStrategy = 'BIP48';

            return callback(null, opts);
          });
        }, SETTLE_TIME);
      });
    };

    root._orderPubKeys = function(xPub, np) {
      var xPubKeys = lodash.clone(xPub);
      var path = lodash.clone(np);
      path.unshift('m');
      path = path.join('/');

      var keys = lodash.map(xPubKeys, function(x) {
        var pub = (new bitcore.HDPublicKey(x)).derive(path).publicKey;
        return {
          xpub: x,
          pub: pub.toString('hex'),
        };
      });

      var sorted = lodash.sortBy(keys, function(x) {
        return x.pub;
      });

      return lodash.pluck(sorted, 'xpub');
    };

    root.signTx = function(xPubKeys, txp, account, callback) {

      var inputs = [],
        outputs = [];
      var tmpOutputs = [];

      if (txp.type && txp.type != 'simple') {
        return callback('Only TXPs type SIMPLE are supported in TREZOR');
      } else if (txp.outputs) {
        if (txp.outputs.length > 1)
          return callback('Only single output TXPs are supported in TREZOR');
      } else {
          return callback('Unknown TXP at TREZOR');
      }

      if (txp.outputs) {

        if (!txp.toAddress)
          txp.toAddress = txp.outputs[0].toAddress;

        if (!txp.amount)
          txp.amount = txp.outputs[0].amount;
      }

      if (!txp.toAddress || !txp.amount)
        return callback('No address or amount at TREZOR signing');

      var toScriptType = 'PAYTOADDRESS';
      if (txp.toAddress.charAt(0) == '2' || txp.toAddress.charAt(0) == '3')
        toScriptType = 'PAYTOSCRIPTHASH';

      // Add to
      tmpOutputs.push({
        address: txp.toAddress,
        amount: txp.amount,
        script_type: toScriptType,
      });

      if (txp.addressType == 'P2PKH') {

        $log.debug("Trezor signing uni-sig p2pkh. Account:", account);

        var inAmount = 0;
        inputs = lodash.map(txp.inputs, function(i) {
          $log.debug("Trezor TX input path:", i.path);
          var pathArr = i.path.split('/');
          var n = [hwWallet.UNISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])];
          inAmount += i.satoshis;
          return {
            address_n: n,
            prev_index: i.vout,
            prev_hash: i.txid,
          };
        });

        var change = inAmount - txp.fee - txp.amount;
        if (change > 0) {
          $log.debug("Trezor TX change path:", txp.changeAddress.path);
          var pathArr = txp.changeAddress.path.split('/');
          var n = [hwWallet.UNISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])];

          tmpOutputs.push({
            address_n: n,
            amount: change,
            script_type: 'PAYTOADDRESS'
          });
        }

      } else {

        // P2SH Wallet, multisig wallet
        var inAmount = 0;
        $log.debug("Trezor signing multi-sig p2sh. Account:", account);

        var sigs = xPubKeys.map(function(v) {
          return '';
        });

        inputs = lodash.map(txp.inputs, function(i) {
          $log.debug("Trezor TX input path:", i.path);
          var pathArr = i.path.split('/');
          var n = [hwWallet.MULTISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])];
          var np = n.slice(3);

          inAmount += i.satoshis;

          var orderedPubKeys = root._orderPubKeys(xPubKeys, np);
          var pubkeys = lodash(orderedPubKeys.map(function(v) {
            return {
              node: v,
              address_n: np,
            };
          }));

          return {
            address_n: n,
            prev_index: i.vout,
            prev_hash: i.txid,
            script_type: 'SPENDMULTISIG',
            multisig: {
              pubkeys: pubkeys,
              signatures: sigs,
              m: txp.requiredSignatures,
            }
          };
        });

        var change = inAmount - txp.fee - txp.amount;
        if (change > 0) {
          $log.debug("Trezor TX change path:", txp.changeAddress.path);
          var pathArr = txp.changeAddress.path.split('/');
          var n = [hwWallet.MULTISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])];
          var np = n.slice(3);

          var orderedPubKeys = root._orderPubKeys(xPubKeys, np);
          var pubkeys = lodash(orderedPubKeys.map(function(v) {
            return {
              node: v,
              address_n: np,
            };
          }));

          tmpOutputs.push({
            address_n: n,
            amount: change,
            script_type: 'PAYTOMULTISIG',
            multisig: {
              pubkeys: pubkeys,
              signatures: sigs,
              m: txp.requiredSignatures,
            }
          });
        }
      }

      // Shuffle outputs for improved privacy
      if (tmpOutputs.length > 1) {
        outputs = new Array(tmpOutputs.length);
        lodash.each(txp.outputOrder, function(order) {
          outputs[order] = tmpOutputs.shift();
        });

        if (tmpOutputs.length)
          return cb("Error creating transaction: tmpOutput order");
      } else {
        outputs = tmpOutputs;
      }

      // Prevents: Uncaught DataCloneError: Failed to execute 'postMessage' on 'Window': An object could not be cloned.
      inputs = JSON.parse(JSON.stringify(inputs));
      outputs = JSON.parse(JSON.stringify(outputs));

      $log.debug('Signing with TREZOR', inputs, outputs);
      TrezorConnect.signTx(inputs, outputs, function(res) {
        if (!res.success)
          return callback(hwWallet._err(res));

        callback(null, res);
      });
    };

    return root;
  });
<|endoftext|>