<commit_before>window.iD = function(container) {
    var connection = iD.Connection(),
        history = iD.History(),
        map = iD.Map()
            .connection(connection)
            .history(history),
        controller = iD.Controller(map, history);

    map.background.source(iD.BackgroundSource.Bing);

    function editor(container) {
        if (!iD.supported()) {
            container.html('This editor is supported in Firefox, Chrome, Safari, Opera, ' +
                      'and Internet Explorer 9 and above. Please upgrade your browser ' +
                      'or use Potlatch 2 to edit the map.')
                .style('text-align:center;font-style:italic;');
            return;
        }

        var m = container.append('div')
            .attr('id', 'map')
            .call(map);

        var bar = container.append('div')
            .attr('id', 'bar')
            .attr('class','pad1 fillD');

        var limiter = bar.append('div')
            .attr('class', 'limiter');

        var buttons_joined = limiter.append('div')
            .attr('class', 'button-wrap joined col4');

        var buttons = buttons_joined.selectAll('button.add-button')
            .data([iD.modes.Browse(), iD.modes.AddPoint(), iD.modes.AddLine(), iD.modes.AddArea()])
            .enter().append('button')
                .attr('tabindex', -1)
                .attr('class', function (mode) { return mode.title + ' add-button col3'; })
            .attr('data-original-title', function (mode) { return mode.description; })
            .call(bootstrap.tooltip().placement('bottom'))
            .on('click.editor', function (mode) { controller.enter(mode); });

        function disableTooHigh() {
            if (map.editable()) {
                notice.message('');
                buttons.attr('disabled', null);
            } else {
                buttons.attr('disabled', 'disabled');
                notice.message('Zoom in to edit the map');
                controller.enter(iD.modes.Browse());
            }
        }

        var notice = iD.ui.notice(limiter).message(null);

        map.on('move.editor', _.debounce(function() {
            disableTooHigh();
            contributors.call(iD.ui.contributors(map));
        }, 500));

        buttons.append('span')
            .attr('class', function(d) {
                return d.id + ' icon icon-pre-text';
            });

        buttons.append('span').attr('class', 'label').text(function (mode) { return mode.title; });

        controller.on('enter.editor', function (entered) {
            buttons.classed('active', function (mode) { return entered.button === mode.button; });
            container.classed("mode-" + entered.id, true);
        });

        controller.on('exit.editor', function (exited) {
            container.classed("mode-" + exited.id, false);
        });

        var undo_buttons = limiter.append('div')
            .attr('class', 'button-wrap joined col1'),
            undo_tooltip = bootstrap.tooltip().placement('bottom');

        undo_buttons.append('button')
            .attr({ id: 'undo', 'class': 'col6' })
            .property('disabled', true)
            .html("")
            .on('click.editor', history.undo)
            .call(undo_tooltip);

        undo_buttons.append('button')
            .attr({ id: 'redo', 'class': 'col6' })
            .property('disabled', true)
            .html("")
            .on('click.editor', history.redo)
            .call(undo_tooltip);

        var save_button = limiter.append('div').attr('class','button-wrap col1').append('button')
            .attr('class', 'save col12')
            .call(iD.ui.save().map(map).controller(controller));

        var zoom = container.append('div')
            .attr('class', 'zoombuttons map-control')
            .selectAll('button')
                .data([['zoom-in', '+', map.zoomIn, 'Zoom In'], ['zoom-out', '-', map.zoomOut, 'Zoom Out']])
                .enter()
                .append('button')
                .attr('tabindex', -1)
                .attr('class', function(d) { return d[0]; })
                .attr('title', function(d) { return d[3]; })
                .on('click.editor', function(d) { return d[2](); })
                .append('span')
                    .attr('class', function(d) {
                        return d[0] + ' icon';
                    });

        if (navigator.geolocation) {
            container.append('div')
                .call(iD.ui.geolocate(map));
        }

        var gc = container.append('div').attr('class', 'geocode-control map-control')
            .call(iD.ui.geocoder().map(map));

        container.append('div').attr('class', 'map-control layerswitcher-control')
            .call(iD.ui.layerswitcher(map));

        container.append('div')
            .style('display', 'none')
            .attr('class', 'inspector-wrap fr col5');

        var about = container.append('div')
            .attr('class','col12 about-block fillD pad1');

        about.append('div')
            .attr('class', 'user-container')
            .append('div')
                .attr('class', 'hello');

        var aboutList = about.append('ul')
                .attr('id','about')
                .attr('class','link-list');

        aboutList.append('ul')
            .attr('id','about')
            .attr('class','pad1 fillD about-block link-list');
        aboutList.append('li').append('a').attr('target', '_blank')
            .attr('href', 'http://github.com/systemed/iD').text('view code');
        aboutList.append('li').append('a').attr('target', '_blank')
            .attr('href', 'http://github.com/systemed/iD/issues').text('report a bug');

        var imagery = aboutList.append('li').attr('id', 'attribution');
        imagery.append('span').text('imagery');
        imagery.append('a').attr('target', '_blank')
            .attr('href', 'http://opengeodata.org/microsoft-imagery-details').text(' provided by bing');

        aboutList.append('li').attr('class', 'source-switch').append('a').attr('href', '#')
            .text('dev')
            .on('click.editor', function() {
                d3.event.preventDefault();
                if (d3.select(this).classed('live')) {
                    map.flush().connection()
                        .url('http://api06.dev.openstreetmap.org');
                    d3.select(this).text('dev').classed('live', false);
                } else {
                    map.flush().connection()
                        .url('http://www.openstreetmap.org');
                    d3.select(this).text('live').classed('live', true);
                }
            });

        var contributors = aboutList.append('li')
            .attr('id', 'user-list');
        contributors.append('span')
            .attr('class', 'icon nearby icon-pre-text');
        contributors.append('span')
            .text('Viewing contributions by ');
        contributors.append('span')
            .attr('class', 'contributor-list');
        contributors.append('span')
            .attr('class', 'contributor-count');

        history.on('change.editor', function() {
            window.onbeforeunload = history.hasChanges() ? function() {
                return 'You have unsaved changes.';
            } : null;

            var undo = history.undoAnnotation(),
                redo = history.redoAnnotation();

            function refreshTooltip(selection) {
                if (selection.property('tooltipVisible')) {
                    selection.call(undo_tooltip.show);
                }
            }

            limiter.select('#undo')
                .property('disabled', !undo)
                .attr('data-original-title', undo)
                .call(undo ? refreshTooltip : undo_tooltip.hide);

            limiter.select('#redo')
                .property('disabled', !redo)
                .attr('data-original-title', redo)
                .call(redo ? refreshTooltip : undo_tooltip.hide);
        });

        d3.select(window).on('resize.editor', function() {
            map.size(m.size());
        });

        var keybinding = d3.keybinding('main')
            .on('P', function() { if (map.editable()) controller.enter(iD.modes.AddPoint()); })
            .on('L', function() { if (map.editable()) controller.enter(iD.modes.AddLine()); })
            .on('A', function() { if (map.editable()) controller.enter(iD.modes.AddArea()); })
            .on('⌘+Z', function() { history.undo(); })
            .on('⌃+Z', function() { history.undo(); })
            .on('⌘+⇧+Z', function() { history.redo(); })
            .on('⌃+⇧+Z', function() { history.redo(); })
            .on('⌫', function() { d3.event.preventDefault(); });

        d3.select(document)
            .call(keybinding);

        var hash = iD.Hash().controller(controller).map(map);

        if (!hash.hadHash) {
            map.centerZoom([-77.02271, 38.90085], 20);
        }

        d3.select('.user-container').call(iD.ui.userpanel(connection)
            .on('logout.editor', connection.logout)
            .on('login.editor', connection.authenticate));

        controller.enter(iD.modes.Browse());
    }

    editor.connection = function(_) {
        if (!arguments.length) return connection;
        connection = _;
        return editor;
    };

    editor.map = function() {
        return map;
    };

    editor.controller = function() {
        return controller;
    };

    if (arguments.length) {
        d3.select(container).call(editor);
    }

    return editor;
};

iD.supported = function() {
    if (navigator.appName !== 'Microsoft Internet Explorer') {
        return true;
    } else {
        var ua = navigator.userAgent;
        var re = new RegExp("MSIE ([0-9]{1,}[\\.0-9]{0,})");
        if (re.exec(ua) !== null) {
            rv = parseFloat( RegExp.$1 );
        }
        if (rv && rv < 9) return false;
        else return true;
    }
};
<commit_msg>Fix link list structure. Fixes #472<commit_after>window.iD = function(container) {
    var connection = iD.Connection(),
        history = iD.History(),
        map = iD.Map()
            .connection(connection)
            .history(history),
        controller = iD.Controller(map, history);

    map.background.source(iD.BackgroundSource.Bing);

    function editor(container) {
        if (!iD.supported()) {
            container.html('This editor is supported in Firefox, Chrome, Safari, Opera, ' +
                      'and Internet Explorer 9 and above. Please upgrade your browser ' +
                      'or use Potlatch 2 to edit the map.')
                .style('text-align:center;font-style:italic;');
            return;
        }

        var m = container.append('div')
            .attr('id', 'map')
            .call(map);

        var bar = container.append('div')
            .attr('id', 'bar')
            .attr('class','pad1 fillD');

        var limiter = bar.append('div')
            .attr('class', 'limiter');

        var buttons_joined = limiter.append('div')
            .attr('class', 'button-wrap joined col4');

        var buttons = buttons_joined.selectAll('button.add-button')
            .data([iD.modes.Browse(), iD.modes.AddPoint(), iD.modes.AddLine(), iD.modes.AddArea()])
            .enter().append('button')
                .attr('tabindex', -1)
                .attr('class', function (mode) { return mode.title + ' add-button col3'; })
            .attr('data-original-title', function (mode) { return mode.description; })
            .call(bootstrap.tooltip().placement('bottom'))
            .on('click.editor', function (mode) { controller.enter(mode); });

        function disableTooHigh() {
            if (map.editable()) {
                notice.message('');
                buttons.attr('disabled', null);
            } else {
                buttons.attr('disabled', 'disabled');
                notice.message('Zoom in to edit the map');
                controller.enter(iD.modes.Browse());
            }
        }

        var notice = iD.ui.notice(limiter).message(null);

        map.on('move.editor', _.debounce(function() {
            disableTooHigh();
            contributors.call(iD.ui.contributors(map));
        }, 500));

        buttons.append('span')
            .attr('class', function(d) {
                return d.id + ' icon icon-pre-text';
            });

        buttons.append('span').attr('class', 'label').text(function (mode) { return mode.title; });

        controller.on('enter.editor', function (entered) {
            buttons.classed('active', function (mode) { return entered.button === mode.button; });
            container.classed("mode-" + entered.id, true);
        });

        controller.on('exit.editor', function (exited) {
            container.classed("mode-" + exited.id, false);
        });

        var undo_buttons = limiter.append('div')
            .attr('class', 'button-wrap joined col1'),
            undo_tooltip = bootstrap.tooltip().placement('bottom');

        undo_buttons.append('button')
            .attr({ id: 'undo', 'class': 'col6' })
            .property('disabled', true)
            .html("")
            .on('click.editor', history.undo)
            .call(undo_tooltip);

        undo_buttons.append('button')
            .attr({ id: 'redo', 'class': 'col6' })
            .property('disabled', true)
            .html("")
            .on('click.editor', history.redo)
            .call(undo_tooltip);

        var save_button = limiter.append('div').attr('class','button-wrap col1').append('button')
            .attr('class', 'save col12')
            .call(iD.ui.save().map(map).controller(controller));

        var zoom = container.append('div')
            .attr('class', 'zoombuttons map-control')
            .selectAll('button')
                .data([['zoom-in', '+', map.zoomIn, 'Zoom In'], ['zoom-out', '-', map.zoomOut, 'Zoom Out']])
                .enter()
                .append('button')
                .attr('tabindex', -1)
                .attr('class', function(d) { return d[0]; })
                .attr('title', function(d) { return d[3]; })
                .on('click.editor', function(d) { return d[2](); })
                .append('span')
                    .attr('class', function(d) {
                        return d[0] + ' icon';
                    });

        if (navigator.geolocation) {
            container.append('div')
                .call(iD.ui.geolocate(map));
        }

        var gc = container.append('div').attr('class', 'geocode-control map-control')
            .call(iD.ui.geocoder().map(map));

        container.append('div').attr('class', 'map-control layerswitcher-control')
            .call(iD.ui.layerswitcher(map));

        container.append('div')
            .style('display', 'none')
            .attr('class', 'inspector-wrap fr col5');

        var about = container.append('div')
            .attr('class','col12 about-block fillD pad1');

        about.append('div')
            .attr('class', 'user-container')
            .append('div')
                .attr('class', 'hello');

        var aboutList = about.append('ul')
                .attr('id','about')
                .attr('class','link-list');

        var linkList = aboutList.append('ul')
            .attr('id','about')
            .attr('class','pad1 fillD about-block link-list');
        linkList.append('li').append('a').attr('target', '_blank')
            .attr('href', 'http://github.com/systemed/iD').text('view code');
        linkList.append('li').append('a').attr('target', '_blank')
            .attr('href', 'http://github.com/systemed/iD/issues').text('report a bug');

        var imagery = linkList.append('li').attr('id', 'attribution');
        imagery.append('span').text('imagery');
        imagery.append('a').attr('target', '_blank')
            .attr('href', 'http://opengeodata.org/microsoft-imagery-details').text(' provided by bing');

        linkList.append('li').attr('class', 'source-switch').append('a').attr('href', '#')
            .text('dev')
            .on('click.editor', function() {
                d3.event.preventDefault();
                if (d3.select(this).classed('live')) {
                    map.flush().connection()
                        .url('http://api06.dev.openstreetmap.org');
                    d3.select(this).text('dev').classed('live', false);
                } else {
                    map.flush().connection()
                        .url('http://www.openstreetmap.org');
                    d3.select(this).text('live').classed('live', true);
                }
            });

        var contributors = linkList.append('li')
            .attr('id', 'user-list');
        contributors.append('span')
            .attr('class', 'icon nearby icon-pre-text');
        contributors.append('span')
            .text('Viewing contributions by ');
        contributors.append('span')
            .attr('class', 'contributor-list');
        contributors.append('span')
            .attr('class', 'contributor-count');

        history.on('change.editor', function() {
            window.onbeforeunload = history.hasChanges() ? function() {
                return 'You have unsaved changes.';
            } : null;

            var undo = history.undoAnnotation(),
                redo = history.redoAnnotation();

            function refreshTooltip(selection) {
                if (selection.property('tooltipVisible')) {
                    selection.call(undo_tooltip.show);
                }
            }

            limiter.select('#undo')
                .property('disabled', !undo)
                .attr('data-original-title', undo)
                .call(undo ? refreshTooltip : undo_tooltip.hide);

            limiter.select('#redo')
                .property('disabled', !redo)
                .attr('data-original-title', redo)
                .call(redo ? refreshTooltip : undo_tooltip.hide);
        });

        d3.select(window).on('resize.editor', function() {
            map.size(m.size());
        });

        var keybinding = d3.keybinding('main')
            .on('P', function() { if (map.editable()) controller.enter(iD.modes.AddPoint()); })
            .on('L', function() { if (map.editable()) controller.enter(iD.modes.AddLine()); })
            .on('A', function() { if (map.editable()) controller.enter(iD.modes.AddArea()); })
            .on('⌘+Z', function() { history.undo(); })
            .on('⌃+Z', function() { history.undo(); })
            .on('⌘+⇧+Z', function() { history.redo(); })
            .on('⌃+⇧+Z', function() { history.redo(); })
            .on('⌫', function() { d3.event.preventDefault(); });

        d3.select(document)
            .call(keybinding);

        var hash = iD.Hash().controller(controller).map(map);

        if (!hash.hadHash) {
            map.centerZoom([-77.02271, 38.90085], 20);
        }

        d3.select('.user-container').call(iD.ui.userpanel(connection)
            .on('logout.editor', connection.logout)
            .on('login.editor', connection.authenticate));

        controller.enter(iD.modes.Browse());
    }

    editor.connection = function(_) {
        if (!arguments.length) return connection;
        connection = _;
        return editor;
    };

    editor.map = function() {
        return map;
    };

    editor.controller = function() {
        return controller;
    };

    if (arguments.length) {
        d3.select(container).call(editor);
    }

    return editor;
};

iD.supported = function() {
    if (navigator.appName !== 'Microsoft Internet Explorer') {
        return true;
    } else {
        var ua = navigator.userAgent;
        var re = new RegExp("MSIE ([0-9]{1,}[\\.0-9]{0,})");
        if (re.exec(ua) !== null) {
            rv = parseFloat( RegExp.$1 );
        }
        if (rv && rv < 9) return false;
        else return true;
    }
};
<|endoftext|>


<commit_before>/**
 *	@author Félix Girault <felix.girault@gmail.com>
 */
'use strict';

var co = require('co');
var OEmbed = require('./oembed');

/**
 *	{@inheritDoc}
 */
var Youtube = function(endpoint, format) {
	OEmbed.call(this, endpoint, format);
};

/**
 *	Subclassing.
 */
Youtube.prototype = new OEmbed();
Youtube.prototype.constructor = Youtube;

/**
 *	{@inheritDoc}
 */
Youtube.prototype.prepareUrl = function(url, options) {
	url = url.trim();
	matches = /(?:v=|v\/|embed\/|youtu\.be\/)([a-z0-9_-]+)/i.exec(url);

	if (matches && matches[1]) {
		url = 'http://www.youtube.com/watch?v=' + matches[1];
	}

	return url;
};

module.exports = Youtube;
<commit_msg>Fixed declaration<commit_after>/**
 *	@author Félix Girault <felix.girault@gmail.com>
 */
'use strict';

var co = require('co');
var OEmbed = require('./oembed');

/**
 *	{@inheritDoc}
 */
var Youtube = function(endpoint, format) {
	OEmbed.call(this, endpoint, format);
};

/**
 *	Subclassing.
 */
Youtube.prototype = new OEmbed();
Youtube.prototype.constructor = Youtube;

/**
 *	{@inheritDoc}
 */
Youtube.prototype.prepareUrl = function(url, options) {
	url = url.trim();
	var matches = /(?:v=|v\/|embed\/|youtu\.be\/)([a-z0-9_-]+)/i.exec(url);

	if (matches && matches[1]) {
		url = 'http://www.youtube.com/watch?v=' + matches[1];
	}

	return url;
};

module.exports = Youtube;
<|endoftext|>


<commit_before>$(loaded);

let windowBottom;
let userScroll = 0;

function loaded() {
  setTimeout(() => demo.init(), 1500);

  window.addEventListener('resize', demo.resize);
  window.addEventListener('scroll', getWindowHeight);
  window.addEventListener('resize', getWindowHeight);

  $('.burger').on('click', handleBurgerClick);
  $('.side-menu li, .fa-sort-down').on('click', scrollToSection);

  $('.quote-carousel').slick({
    dots: true,
    arrows: false,
    infinite: true,
    autoplay: false,
    autoplaySpeed: 10000,
    speed: 500,
    fade: true,
    cssEase: 'linear'
  });
}

function scrollToSection() {
  const element = $(this).attr('id');

    $('.burger').removeClass('open');
    $('.side-menu').removeClass('show-side-menu');
    $('.shader').removeClass('dim');
    $('body').removeClass('disable-scroll');

    $('html, body').animate({
      scrollTop: ($(`.${element}`).offset().top)
    }, 2000);
}

function handleBurgerClick() {
  $(this).toggleClass('open');
  $('.side-menu').toggleClass('show-side-menu');
  $('.shader').toggleClass('dim');
  $('body').toggleClass('disable-scroll');
}

function getWindowHeight() {
  userScroll = $(window).scrollTop();
  windowBottom = userScroll + $(window).height() - 100;

  animateNavbar();
  animateSection('portfolio');
  animateSection('experience');
}

function animateNavbar() {
  const landingHeight = $('.landing').height();

  userScroll > landingHeight ? $('nav').addClass('nav-small') : $('nav').removeClass('nav-small');
}

function animateSection(element) {
  const elementTop = $(`.${element}`).offset().top;
  const elemementBottom = elementTop + $(`.${element}`).height();

  if(elemementBottom <= windowBottom) {
    $(`.${element} .left, .${element} h4`)
      .removeClass('hidden')
      .addClass('animated fadeInLeft');

    $(`.${element} .right`)
      .removeClass('hidden')
      .addClass('animated fadeInRight');
  }
}<commit_msg>changing animation height<commit_after>$(loaded);

let windowBottom;
let userScroll = 0;

function loaded() {
  setTimeout(() => demo.init(), 1500);

  window.addEventListener('resize', demo.resize);
  window.addEventListener('scroll', getWindowHeight);
  window.addEventListener('resize', getWindowHeight);

  $('.burger').on('click', handleBurgerClick);
  $('.side-menu li, .fa-sort-down').on('click', scrollToSection);

  $('.quote-carousel').slick({
    dots: true,
    arrows: false,
    infinite: true,
    autoplay: false,
    autoplaySpeed: 10000,
    speed: 500,
    fade: true,
    cssEase: 'linear'
  });
}

function scrollToSection() {
  const element = $(this).attr('id');

    $('.burger').removeClass('open');
    $('.side-menu').removeClass('show-side-menu');
    $('.shader').removeClass('dim');
    $('body').removeClass('disable-scroll');

    $('html, body').animate({
      scrollTop: ($(`.${element}`).offset().top)
    }, 2000);
}

function handleBurgerClick() {
  $(this).toggleClass('open');
  $('.side-menu').toggleClass('show-side-menu');
  $('.shader').toggleClass('dim');
  $('body').toggleClass('disable-scroll');
}

function getWindowHeight() {
  userScroll = $(window).scrollTop();
  windowBottom = userScroll + $(window).height() - 50;

  animateNavbar();
  animateSection('portfolio');
  animateSection('experience');
}

function animateNavbar() {
  const landingHeight = $('.landing').height();

  userScroll > landingHeight ? $('nav').addClass('nav-small') : $('nav').removeClass('nav-small');
}

function animateSection(element) {
  const elementTop = $(`.${element}`).offset().top;
  const elemementBottom = elementTop + $(`.${element}`).height();

  if(elemementBottom <= windowBottom) {
    $(`.${element} .left, .${element} h4`)
      .removeClass('hidden')
      .addClass('animated fadeInLeft');

    $(`.${element} .right`)
      .removeClass('hidden')
      .addClass('animated fadeInRight');
  }
}<|endoftext|>


<commit_before>iD.ui = function(context) {
    return function(container) {
        context.container(container);

        var history = context.history(),
            map = context.map();

        if (iD.detect().opera) container.classed('opera', true);

        var hash = iD.behavior.Hash(context);

        hash();

        if (!hash.hadHash) {
            map.centerZoom([-77.02271, 38.90085], 20);
        }

        var m = container.append('div')
            .attr('id', 'map')
            .call(map);

        var bar = container.append('div')
            .attr('id', 'bar')
            .attr('class','fillD');

        var limiter = bar.append('div')
            .attr('class', 'limiter');

        limiter.append('div')
            .attr('class', 'button-wrap joined col3')
            .call(iD.ui.Modes(context), limiter);

        limiter.append('div')
            .attr('class', 'button-wrap joined col1')
            .call(iD.ui.UndoRedo(context));

        limiter.append('div')
            .attr('class', 'button-wrap col1')
            .call(iD.ui.Save(context));

        bar.append('div')
            .attr('class', 'spinner')
            .call(iD.ui.Spinner(context));

        container.append('idv')
            .attr('class', 'attribution')
            .attr('tabindex', -1)
            .call(iD.ui.Attribution(context));

        container.append('div')
            .style('display', 'none')
            .attr('class', 'help-wrap fillL col5 content');

        container.append('div')
            .attr('class', 'map-control zoombuttons')
            .call(iD.ui.Zoom(context));

        container.append('div')
            .attr('class', 'map-control geocode-control')
            .call(iD.ui.Geocoder(context));

        container.append('div')
            .attr('class', 'map-control background-control')
            .call(iD.ui.Background(context));

        container.append('div')
            .attr('class', 'map-control geolocate-control')
            .call(iD.ui.Geolocate(map));

        container.append('div')
            .attr('class', 'map-control help-control')
            .call(iD.ui.Help(context));

        container.append('div')
            .style('display', 'none')
            .attr('class', 'inspector-wrap fr content col4');

        var about = container.append('div')
            .attr('class','col12 about-block fillD');

        if (!context.embed()) {
            about.append('div')
                .attr('class', 'account')
                .call(iD.ui.Account(context));
        }

        var linkList = about.append('ul')
            .attr('id', 'about')
            .attr('class', 'link-list');

        linkList.append('li')
            .append('a')
            .attr('target', '_blank')
            .attr('tabindex', -1)
            .attr('href', 'http://github.com/systemed/iD')
            .text(iD.version);

        linkList.append('li')
            .append('a')
            .attr('target', '_blank')
            .attr('tabindex', -1)
            .attr('href', 'https://help.openstreetmap.org/questions/ask/')
            .text(t('report_a_bug'));

        linkList.append('li')
            .attr('class', 'user-list')
            .attr('tabindex', -1)
            .call(iD.ui.Contributors(context));

        window.onbeforeunload = function() {
            history.save();
            if (history.hasChanges()) return t('save.unsaved_changes');
        };

        d3.select(window).on('resize.editor', function() {
            map.size(m.size());
        });

        function pan(d) {
            return function() {
                context.pan(d);
            };
        }

        // pan amount
        var pa = 5;

        var keybinding = d3.keybinding('main')
            .on('⌫', function() { d3.event.preventDefault(); })
            .on('←', pan([pa, 0]))
            .on('↑', pan([0, pa]))
            .on('→', pan([-pa, 0]))
            .on('↓', pan([0, -pa]));

        d3.select(document)
            .call(keybinding);

        context.enter(iD.modes.Browse(context));

        context.container()
            .call(iD.ui.Splash(context))
            .call(iD.ui.Restore(context));

    };
};

iD.ui.tooltipHtml = function(text, key) {
    return '' + text + '' + '
 ' + key + '
';
};
<commit_msg>switch back to github for bug reporting<commit_after>iD.ui = function(context) {
    return function(container) {
        context.container(container);

        var history = context.history(),
            map = context.map();

        if (iD.detect().opera) container.classed('opera', true);

        var hash = iD.behavior.Hash(context);

        hash();

        if (!hash.hadHash) {
            map.centerZoom([-77.02271, 38.90085], 20);
        }

        var m = container.append('div')
            .attr('id', 'map')
            .call(map);

        var bar = container.append('div')
            .attr('id', 'bar')
            .attr('class','fillD');

        var limiter = bar.append('div')
            .attr('class', 'limiter');

        limiter.append('div')
            .attr('class', 'button-wrap joined col3')
            .call(iD.ui.Modes(context), limiter);

        limiter.append('div')
            .attr('class', 'button-wrap joined col1')
            .call(iD.ui.UndoRedo(context));

        limiter.append('div')
            .attr('class', 'button-wrap col1')
            .call(iD.ui.Save(context));

        bar.append('div')
            .attr('class', 'spinner')
            .call(iD.ui.Spinner(context));

        container.append('idv')
            .attr('class', 'attribution')
            .attr('tabindex', -1)
            .call(iD.ui.Attribution(context));

        container.append('div')
            .style('display', 'none')
            .attr('class', 'help-wrap fillL col5 content');

        container.append('div')
            .attr('class', 'map-control zoombuttons')
            .call(iD.ui.Zoom(context));

        container.append('div')
            .attr('class', 'map-control geocode-control')
            .call(iD.ui.Geocoder(context));

        container.append('div')
            .attr('class', 'map-control background-control')
            .call(iD.ui.Background(context));

        container.append('div')
            .attr('class', 'map-control geolocate-control')
            .call(iD.ui.Geolocate(map));

        container.append('div')
            .attr('class', 'map-control help-control')
            .call(iD.ui.Help(context));

        container.append('div')
            .style('display', 'none')
            .attr('class', 'inspector-wrap fr content col4');

        var about = container.append('div')
            .attr('class','col12 about-block fillD');

        if (!context.embed()) {
            about.append('div')
                .attr('class', 'account')
                .call(iD.ui.Account(context));
        }

        var linkList = about.append('ul')
            .attr('id', 'about')
            .attr('class', 'link-list');

        linkList.append('li')
            .append('a')
            .attr('target', '_blank')
            .attr('tabindex', -1)
            .attr('href', 'http://github.com/systemed/iD')
            .text(iD.version);

        linkList.append('li')
            .append('a')
            .attr('target', '_blank')
            .attr('tabindex', -1)
            .attr('href', 'https://github.com/systemed/iD/issues')
            .text(t('report_a_bug'));

        linkList.append('li')
            .attr('class', 'user-list')
            .attr('tabindex', -1)
            .call(iD.ui.Contributors(context));

        window.onbeforeunload = function() {
            history.save();
            if (history.hasChanges()) return t('save.unsaved_changes');
        };

        d3.select(window).on('resize.editor', function() {
            map.size(m.size());
        });

        function pan(d) {
            return function() {
                context.pan(d);
            };
        }

        // pan amount
        var pa = 5;

        var keybinding = d3.keybinding('main')
            .on('⌫', function() { d3.event.preventDefault(); })
            .on('←', pan([pa, 0]))
            .on('↑', pan([0, pa]))
            .on('→', pan([-pa, 0]))
            .on('↓', pan([0, -pa]));

        d3.select(document)
            .call(keybinding);

        context.enter(iD.modes.Browse(context));

        context.container()
            .call(iD.ui.Splash(context))
            .call(iD.ui.Restore(context));

    };
};

iD.ui.tooltipHtml = function(text, key) {
    return '' + text + '' + '
 ' + key + '
';
};
<|endoftext|>


<commit_before>const assert = require('assert')
const getByDot = require('lodash/get')
const setByDot = require('lodash/set')
const isEqual = require('lodash/isEqual')
const isFunction = require('lodash/isFunction')
const merge = require('lodash/merge')
const defaults = {
  include: undefined
}

module.exports = function (options) {
  options = Object.assign({}, defaults, options)

  // Make an array of includes
  const includes = [].concat(options.include || [])

  if (!includes.length) {
    throw new Error('shallowPopulate hook: You must provide one or more relationships in the `include` option.')
  }

  const requiredIncludeAttrs = [
    'service',
    'nameAs',
    'keyHere',
    'keyThere',
    'asArray',
    'params'
  ]
  includes.forEach(include => {
    // Create default `asArray` property
    if (!Object.prototype.hasOwnProperty.call(include, 'asArray')) {
      include.asArray = true
    }
    // Create default `params` property
    if (!Object.prototype.hasOwnProperty.call(include, 'params')) {
      include.params = {}
    }
    try {
      assert.deepStrictEqual(requiredIncludeAttrs.sort(), Object.keys(include).sort())
    } catch (error) {
      throw new Error('shallowPopulate hook: Every `include` must contain `service`, `nameAs`, `keyHere`, and `keyThere` properties')
    }
  })

  const requiredKeyMappings = includes.reduce((includes, include) => {
    if (!includes[include.keyHere]) {
      includes[include.keyHere] = include
    }
    return includes
  }, {})

  return function shallowPopulate (context) {
    const { app, type } = context
    let data = type === 'before' ? context.data : (context.result.data || context.result)
    data = [].concat(data || [])

    if (!data.length) {
      return Promise.resolve(context)
    }

    // data1: {
    //   id: '11',
    //   name: 'Dumb Stuff',
    //   trackIds: ['111', '222', '333']
    // }

    // const byKeyHere = {
    //   trackIds: {
    //     '111': [data1, data2],
    //     '222': [data1],
    //     '333': [data1]
    //   }
    // }

    const dataMap = data.reduce((byKeyHere, current) => {
      Object.keys(requiredKeyMappings).forEach(key => {
        byKeyHere[key] = byKeyHere[key] || {}
        const keyHere = getByDot(current, key)

        if (keyHere) {
          if (Array.isArray(keyHere)) {
            if (!requiredKeyMappings[key].asArray) {
              mapDataWithId(byKeyHere, key, keyHere[0], current)
            } else {
              keyHere.forEach(hereKey => mapDataWithId(byKeyHere, key, hereKey, current))
            }
          } else {
            mapDataWithId(byKeyHere, key, keyHere, current)
          }
        }
      })

      return byKeyHere
    }, {})

    // const dataMap = {
    //   keyHere: {
    //     trackIds: {
    //       1: [{}]
    //     }
    //   },
    //   keyThere: {
    //     foo: [...keyHeres].map(here => {
    //       here[nameAs] = tracksResponse[index]
    //     })
    //   }
    // }

    const params = includes.map(i => {
      const keyVals = dataMap[i.keyHere]
      let keysHere = Object.keys(keyVals) || []
      keysHere = keysHere.map(k => keyVals[k].key)
      let params = { query: { [i.keyThere]: { $in: keysHere } }, paginate: false }

      const providedParams = (isFunction(i.params)) ? i.params(params, context) : i.params

      if (providedParams && params !== providedParams) params = merge(params, providedParams)

      return params
    })

    const requests = includes.map((include, index) => app.service(include.service).find(params[index]))

    return Promise.all(requests)
      .then(responses => {
        responses.forEach((response, index) => {
          const include = includes[index]
          const relatedItems = response.data || response

          data.forEach(item => {
            const keyHere = getByDot(item, include.keyHere)

            if (keyHere) {
              if (Array.isArray(keyHere)) {
                if (!include.asArray) {
                  setByDot(item, include.nameAs, getRelatedItems(keyHere[0], relatedItems, include))
                } else {
                  setByDot(item, include.nameAs, getRelatedItems(keyHere, relatedItems, include))
                }
              } else {
                setByDot(item, include.nameAs, getRelatedItems(keyHere, relatedItems, include))
              }
            }
          })
        })
        return Promise.resolve(context)
      })
  }
}

function getRelatedItems (ids, relatedItems, include) {
  const { keyThere, asArray } = include
  ids = [].concat(ids || [])
  return relatedItems.reduce((items, currentItem) => {
    ids.forEach(id => {
      // id = typeof id === 'number' ? id.toString() : id
      let currentId
      // Allow populating on nested array of objects like key[0].name, key[1].name
      // If keyThere includes a dot, we're looking for a nested prop. This checks if that nested prop is an array.
      // If it's an array, we assume it to be an array of objects.
      // It splits the key only on the first dot which allows populating on nested keys inside the array of objects.
      if (keyThere.includes('.') && Array.isArray(currentItem[keyThere.slice(0, keyThere.indexOf('.'))])) {
        // The name of the array is everything leading up to the first dot.
        const arrayName = keyThere.split('.')[0]
        // The rest will be handed to getByDot as the path to the prop
        const nestedProp = keyThere.slice(keyThere.indexOf('.') + 1)
        // Map over the array to grab each nestedProp's value.
        currentId = currentItem[arrayName].map(nestedItem => {
          const keyThereVal = getByDot(nestedItem, nestedProp)
          return keyThereVal
        })
      } else {
        const keyThereVal = getByDot(currentItem, keyThere)
        currentId = keyThereVal
      }
      if (asArray) {
        if ((Array.isArray(currentId) && currentId.includes(id)) || isEqual(currentId, id)) {
          items.push(currentItem)
        }
      } else {
        if (isEqual(currentId, id)) {
          items = currentItem
        }
      }
    })
    return items
  }, asArray ? [] : {})
}

function mapDataWithId (byKeyHere, key, keyHere, current) {
  byKeyHere[key][keyHere] = byKeyHere[key][keyHere] || {
    key: keyHere,
    vals: []
  }
  byKeyHere[key][keyHere].vals.push(current)
  return byKeyHere
}
<commit_msg>bug fix when accessing result data for shallow populate<commit_after>const assert = require('assert')
const getByDot = require('lodash/get')
const setByDot = require('lodash/set')
const isEqual = require('lodash/isEqual')
const isFunction = require('lodash/isFunction')
const merge = require('lodash/merge')
const defaults = {
  include: undefined
}

module.exports = function (options) {
  options = Object.assign({}, defaults, options)

  // Make an array of includes
  const includes = [].concat(options.include || [])

  if (!includes.length) {
    throw new Error('shallowPopulate hook: You must provide one or more relationships in the `include` option.')
  }

  const requiredIncludeAttrs = [
    'service',
    'nameAs',
    'keyHere',
    'keyThere',
    'asArray',
    'params'
  ]
  includes.forEach(include => {
    // Create default `asArray` property
    if (!Object.prototype.hasOwnProperty.call(include, 'asArray')) {
      include.asArray = true
    }
    // Create default `params` property
    if (!Object.prototype.hasOwnProperty.call(include, 'params')) {
      include.params = {}
    }
    try {
      assert.deepStrictEqual(requiredIncludeAttrs.sort(), Object.keys(include).sort())
    } catch (error) {
      throw new Error('shallowPopulate hook: Every `include` must contain `service`, `nameAs`, `keyHere`, and `keyThere` properties')
    }
  })

  const requiredKeyMappings = includes.reduce((includes, include) => {
    if (!includes[include.keyHere]) {
      includes[include.keyHere] = include
    }
    return includes
  }, {})

  return function shallowPopulate (context) {
    const { app, type } = context
    let data = type === 'before'
        ? context.data :
        context.method === 'get'
        ? context.result :
        (context.result.data || context.result)
    data = [].concat(data || [])

    if (!data.length) {
      return Promise.resolve(context)
    }

    // data1: {
    //   id: '11',
    //   name: 'Dumb Stuff',
    //   trackIds: ['111', '222', '333']
    // }

    // const byKeyHere = {
    //   trackIds: {
    //     '111': [data1, data2],
    //     '222': [data1],
    //     '333': [data1]
    //   }
    // }

    const dataMap = data.reduce((byKeyHere, current) => {
      Object.keys(requiredKeyMappings).forEach(key => {
        byKeyHere[key] = byKeyHere[key] || {}
        const keyHere = getByDot(current, key)

        if (keyHere) {
          if (Array.isArray(keyHere)) {
            if (!requiredKeyMappings[key].asArray) {
              mapDataWithId(byKeyHere, key, keyHere[0], current)
            } else {
              keyHere.forEach(hereKey => mapDataWithId(byKeyHere, key, hereKey, current))
            }
          } else {
            mapDataWithId(byKeyHere, key, keyHere, current)
          }
        }
      })

      return byKeyHere
    }, {})

    // const dataMap = {
    //   keyHere: {
    //     trackIds: {
    //       1: [{}]
    //     }
    //   },
    //   keyThere: {
    //     foo: [...keyHeres].map(here => {
    //       here[nameAs] = tracksResponse[index]
    //     })
    //   }
    // }

    const params = includes.map(i => {
      const keyVals = dataMap[i.keyHere]
      let keysHere = Object.keys(keyVals) || []
      keysHere = keysHere.map(k => keyVals[k].key)
      let params = { query: { [i.keyThere]: { $in: keysHere } }, paginate: false }

      const providedParams = (isFunction(i.params)) ? i.params(params, context) : i.params

      if (providedParams && params !== providedParams) params = merge(params, providedParams)

      return params
    })

    const requests = includes.map((include, index) => app.service(include.service).find(params[index]))

    return Promise.all(requests)
      .then(responses => {
        responses.forEach((response, index) => {
          const include = includes[index]
          const relatedItems = response.data || response

          data.forEach(item => {
            const keyHere = getByDot(item, include.keyHere)

            if (keyHere) {
              if (Array.isArray(keyHere)) {
                if (!include.asArray) {
                  setByDot(item, include.nameAs, getRelatedItems(keyHere[0], relatedItems, include))
                } else {
                  setByDot(item, include.nameAs, getRelatedItems(keyHere, relatedItems, include))
                }
              } else {
                setByDot(item, include.nameAs, getRelatedItems(keyHere, relatedItems, include))
              }
            }
          })
        })
        return Promise.resolve(context)
      })
  }
}

function getRelatedItems (ids, relatedItems, include) {
  const { keyThere, asArray } = include
  ids = [].concat(ids || [])
  return relatedItems.reduce((items, currentItem) => {
    ids.forEach(id => {
      // id = typeof id === 'number' ? id.toString() : id
      let currentId
      // Allow populating on nested array of objects like key[0].name, key[1].name
      // If keyThere includes a dot, we're looking for a nested prop. This checks if that nested prop is an array.
      // If it's an array, we assume it to be an array of objects.
      // It splits the key only on the first dot which allows populating on nested keys inside the array of objects.
      if (keyThere.includes('.') && Array.isArray(currentItem[keyThere.slice(0, keyThere.indexOf('.'))])) {
        // The name of the array is everything leading up to the first dot.
        const arrayName = keyThere.split('.')[0]
        // The rest will be handed to getByDot as the path to the prop
        const nestedProp = keyThere.slice(keyThere.indexOf('.') + 1)
        // Map over the array to grab each nestedProp's value.
        currentId = currentItem[arrayName].map(nestedItem => {
          const keyThereVal = getByDot(nestedItem, nestedProp)
          return keyThereVal
        })
      } else {
        const keyThereVal = getByDot(currentItem, keyThere)
        currentId = keyThereVal
      }
      if (asArray) {
        if ((Array.isArray(currentId) && currentId.includes(id)) || isEqual(currentId, id)) {
          items.push(currentItem)
        }
      } else {
        if (isEqual(currentId, id)) {
          items = currentItem
        }
      }
    })
    return items
  }, asArray ? [] : {})
}

function mapDataWithId (byKeyHere, key, keyHere, current) {
  byKeyHere[key][keyHere] = byKeyHere[key][keyHere] || {
    key: keyHere,
    vals: []
  }
  byKeyHere[key][keyHere].vals.push(current)
  return byKeyHere
}
<|endoftext|>


<commit_before><commit_msg>Height<commit_after><|endoftext|>


<commit_before>var
  webpage = require('webpage'),
  fs      = require('fs'),
  system  = require('system'),
  margin          = system.args[5] || '0cm',
  orientation     = system.args[6] || 'portrait',
  cookie_file     = system.args[7],
  render_time     = system.args[8] || 10000 ,
  time_out        = system.args[9] || 90000 ,
  viewport_width  = system.args[10] || 600,
  viewport_height = system.args[11] || 600,
  redirects_num   = system.args[12] || 0,
  cookies = {},
  address, output, size;

function error(msg) {
  msg = msg || 'Unknown error';
  console.log(msg);
  phantom.exit(1);
  throw msg;
}

function print_usage() {
  console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom] [margin] [orientation] [cookie_file] [render_time] [time_out] [viewport_width] [viewport_height] [max_redirects_count]');
  console.log('  paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
}

window.setTimeout(function () {
  error("Shit's being weird no result within: " + time_out + "ms");
}, time_out);

function renderUrl(url, output, options) {
  options = options || {};

  var statusCode,
      page = webpage.create();

  for (var k in options) {
    if (options.hasOwnProperty(k)) {
      page[k] = options[k];
    }
  }

  // determine the statusCode
  page.onResourceReceived = function (resource) {
    if (resource.url == url) {
      statusCode = resource.status;
    }
  };

  page.onResourceError = function (resourceError) {
    error(resourceError.errorString + ' (URL: ' + resourceError.url + ')');
  };

  page.onNavigationRequested = function (redirect_url, type, willNavigate, main) {
    if (main) {
      if (redirect_url !== url) {
        page.close();

        if (redirects_num-- >= 0) {
          renderUrl(redirect_url, output, options);
        } else {
          error(url + ' redirects to ' + redirect_url + ' after maximum number of redirects reached');
        }
      }
    }
  };

  page.open(url, function (status) {
    if (status !== 'success' || (statusCode != 200 && statusCode != null)) {
      if (fs.exists(output)) {
        fs.remove(output);
      }
      try {
        fs.touch(output);
      } catch (e) {
        console.log(e);
      }

      error('Unable to load the URL: ' + url + ' (HTTP ' + statusCode + ')');
    } else {
      window.setTimeout(function () {
        page.render(output + '_tmp.pdf');

        if (fs.exists(output)) {
          fs.remove(output);
        }

        try {
          fs.move(output + '_tmp.pdf', output);
        } catch (e) {
          error(e);
        }
        console.log('Rendered to: ' + output, new Date().getTime());
        phantom.exit(0);
      }, render_time);
    }
  });
}

if (cookie_file) {
  try {
    f = fs.open(cookie_file, "r");
    cookies = JSON.parse(f.read());
    fs.remove(cookie_file);
  } catch (e) {
    console.log(e);
  }
  phantom.cookiesEnabled = true;
  phantom.cookies = cookies;
}

if (system.args.length < 3 || system.args.length > 13) {
  print_usage() && phantom.exit(2);
} else {
  address = system.args[1];
  output  = system.args[2];

  page_options = {
    viewportSize: {
      width:  viewport_width,
      height: viewport_height
    }
  };

  if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") {
    size = system.args[3].split('*');
    page_options.paperSize = size.length === 2 ? { width:size[0], height:size[1], margin:'0px' }
      : { format:system.args[3], orientation:orientation, margin:margin };
  }
  if (system.args.length > 4) {
    page_options.zoomFactor = system.args[4];
  }

  renderUrl(address, output, page_options);
}
<commit_msg>add header / footer args<commit_after>var
  webpage = require('webpage'),
  fs      = require('fs'),
  system  = require('system'),
  margin          = system.args[5] || '0cm',
  orientation     = system.args[6] || 'portrait',
  cookie_file     = system.args[7],
  render_time     = system.args[8] || 10000 ,
  time_out        = system.args[9] || 90000 ,
  viewport_width  = system.args[10] || 600,
  viewport_height = system.args[11] || 600,
  redirects_num   = system.args[12] || 0,
  header	  = system.args[13] || '',
  footer	  = system.args[14] || '',
  cookies = {},
  address, output, size;

function error(msg) {
  msg = msg || 'Unknown error';
  console.log(msg);
  phantom.exit(1);
  throw msg;
}

function print_usage() {
  console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom] [margin] [orientation] [cookie_file] [render_time] [time_out] [viewport_width] [viewport_height] [max_redirects_count]');
  console.log('  paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
}

window.setTimeout(function () {
  error("Shit's being weird no result within: " + time_out + "ms");
}, time_out);

function renderUrl(url, output, options) {
  options = options || {};

  var statusCode,
      page = webpage.create();

  for (var k in options) {
    if (options.hasOwnProperty(k)) {
      page[k] = options[k];
    }
  }

  // determine the statusCode
  page.onResourceReceived = function (resource) {
    if (resource.url == url) {
      statusCode = resource.status;
    }
  };

  page.onResourceError = function (resourceError) {
    error(resourceError.errorString + ' (URL: ' + resourceError.url + ')');
  };

  page.onNavigationRequested = function (redirect_url, type, willNavigate, main) {
    if (main) {
      if (redirect_url !== url) {
        page.close();

        if (redirects_num-- >= 0) {
          renderUrl(redirect_url, output, options);
        } else {
          error(url + ' redirects to ' + redirect_url + ' after maximum number of redirects reached');
        }
      }
    }
  };

  page.open(url, function (status) {
    if (status !== 'success' || (statusCode != 200 && statusCode != null)) {
      if (fs.exists(output)) {
        fs.remove(output);
      }
      try {
        fs.touch(output);
      } catch (e) {
        console.log(e);
      }

      error('Unable to load the URL: ' + url + ' (HTTP ' + statusCode + ')');
    } else {
      window.setTimeout(function () {
        page.render(output + '_tmp.pdf');

        if (fs.exists(output)) {
          fs.remove(output);
        }

        try {
          fs.move(output + '_tmp.pdf', output);
        } catch (e) {
          error(e);
        }
        console.log('Rendered to: ' + output, new Date().getTime());
        phantom.exit(0);
      }, render_time);
    }
  });
}

if (cookie_file) {
  try {
    f = fs.open(cookie_file, "r");
    cookies = JSON.parse(f.read());
    fs.remove(cookie_file);
  } catch (e) {
    console.log(e);
  }
  phantom.cookiesEnabled = true;
  phantom.cookies = cookies;
}

if (system.args.length < 3 || system.args.length > 15) {
  print_usage() && phantom.exit(2);
} else {
  address = system.args[1];
  output  = system.args[2];

  page_options = {
    viewportSize: {
      width:  viewport_width,
      height: viewport_height
    }
  };

  if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") {
    size = system.args[3].split('*');
    page_options.paperSize = size.length === 2 ? { width:size[0], height:size[1], margin:'0px' }
      : { format:system.args[3], orientation:orientation, margin:margin };
  }
  if (system.args.length > 4) {
    page_options.zoomFactor = system.args[4];
  }

  renderUrl(address, output, page_options);
}
<|endoftext|>


<commit_before>$(function() {
  var $D = $(document),
      $main = $('#main'),
      version = '0.1.1',
      gistListTpl = $('#gist-list-tpl').html(),
      gistDetailTpl = $('#gist-detail-tpl').html(),
      routers = [
        [/^\/blog\/([^\/]*)/, blogDetailHandler],
        [/^\/$/, homeHandler]
      ];
  marked.setOptions({
    highlight: function (code) {
      return hljs.highlightAuto(code).value;
    }
  });
  function getPromise(opt) {
    var promise = $.ajax({
      url: opt.url,
      type: opt.type || 'GET'
    });
    return promise;
  }
  function addLoading() {
    removeLoading();
    var $loadingBg = $('

');
    var $loading = $('
正在加载...
');
    $('body').append($loadingBg)
      .append($loading);
  }
  function removeLoading() {
    $('#loading-bg').remove();
    $('#loading').remove();
  }
  var CacheService = (function() {
    function CacheService(prefix, version) {
      this.prefix = prefix || '';
      this.version = version || '0.1';
    }
    var proto = CacheService.prototype;
    proto.genKey = function(key) {
      return this.prefix + ':' + key + ':' + this.version;
    }
    proto.get = function(key) {
      var self = this;
      var key = self.genKey(key);
      return localStorage.getItem(key);
    };
    proto.set = function(key, value) {
      var self = this;
      var key = self.genKey(key);
      return localStorage.setItem(key, value);
    };
    return CacheService;
  })();
  var listCacheService = new CacheService('list', new Date() - 0),
      detailCacheService = new CacheService('detail', gistDetailTpl.length + version),
      fileCacheService = new CacheService('file', gistDetailTpl.length + version);
  function getList(page, cbk) {
    var cache = listCacheService.get(page);
    if (cache) {
      cbk(cache);
    } else {
      addLoading();
    }
    var gistsPromise = getPromise({
      url: 'https://api.github.com/users/yetone/gists?page=' + page,
      type: 'GET'
    });
    gistsPromise.done(function(jsn) {
      var render = shani.compile(gistListTpl);
      var html = render({
        gists: jsn.filter(function(item) {
          return !!item.description && !!item.files['gistfile1.md'] && (item.files['gistfile1.md'].language === 'Markdown');
        })
      });
      listCacheService.set(page, html);
      cbk(html);
    });
  }
  function getDetail(id, cbk) {
    cbk = cbk || function() {};
    var cache = detailCacheService.get(id);
    if (cache) {
      cbk(cache);
    } else {
      addLoading();
    }
    function renderData(data) {
      var render = shani.compile(gistDetailTpl);
      var html = render(data);
      detailCacheService.set(id, html);
      return cbk(html);
    }
    var detailPromise = getPromise({
      url: 'https://api.github.com/gists/' + id,
      type: 'GET'
    });
    detailPromise.done(function(jsn) {
      if (!jsn.description || !jsn.files['gistfile1.md'] || (jsn.files['gistfile1.md'].language !== 'Markdown')) {
        console.log('not a Markdown file!!!');
        return;
      }
      var rawUrl = jsn.files['gistfile1.md'].raw_url;
      var key = rawUrl + ':' + (new Date(jsn.updated_at) - 0);
      var _cache = fileCacheService.get(key);
      if (_cache) {
        var data = {
          title: jsn.description,
          content: _cache,
          created_at: jsn.created_at
        };
        return renderData(data);
      }
      var filePromise = getPromise({
        url: rawUrl,
        type: 'GET'
      });
      filePromise.done(function(txt) {
        var content = marked(txt);
        var data = {
          title: jsn.description,
          content: content,
          created_at: jsn.created_at
        };
        fileCacheService.set(key, content);
        renderData(data);
      });
    });
  }
  function cacheAll() {
    var $gistItemList = $('.gist-item');
    $gistItemList.each(function(_, item) {
      var $item = $(item);
      var id = $item.data('id');
      getDetail(id);
    });
  }
  function homeHandler(request) {
    getList(request.params.page || '1', function(html) {
      var $gistList = $main.find('#gist-list');
      if (!$gistList.length) {
        $main.html('
' + html + '
');
      } else {
        $gistList.html(html);
      }
      removeLoading();
      cacheAll();
    });
  }
  function blogDetailHandler(request, id) {
    getDetail(id, function(html) {
      $main.html(html);
      removeLoading();
    });
  }
  router(routers);
});
<commit_msg>fix bug<commit_after>$(function() {
  var $D = $(document),
      $main = $('#main'),
      version = '0.1.1',
      gistListTpl = $('#gist-list-tpl').html(),
      gistDetailTpl = $('#gist-detail-tpl').html(),
      routers = [
        [/^\/blog\/([^\/]*)/, blogDetailHandler],
        [/^\/$/, homeHandler]
      ];
  marked.setOptions({
    highlight: function (code) {
      return hljs.highlightAuto(code).value;
    }
  });
  function getPromise(opt) {
    var promise = $.ajax({
      url: opt.url,
      type: opt.type || 'GET'
    });
    return promise;
  }
  function addLoading() {
    removeLoading();
    var $loadingBg = $('

');
    var $loading = $('
正在加载...
');
    $('body').append($loadingBg)
      .append($loading);
  }
  function removeLoading() {
    $('#loading-bg').remove();
    $('#loading').remove();
  }
  var CacheService = (function() {
    function CacheService(prefix, version) {
      this.prefix = prefix || '';
      this.version = version || '0.1';
    }
    var proto = CacheService.prototype;
    proto.genKey = function(key) {
      return this.prefix + ':' + key + ':' + this.version;
    }
    proto.get = function(key) {
      var self = this;
      var key = self.genKey(key);
      return localStorage.getItem(key);
    };
    proto.set = function(key, value) {
      var self = this;
      var key = self.genKey(key);
      return localStorage.setItem(key, value);
    };
    return CacheService;
  })();
  var listCacheService = new CacheService('list', new Date() - 0),
      detailCacheService = new CacheService('detail', gistDetailTpl.length + version),
      fileCacheService = new CacheService('file', gistDetailTpl.length + version);
  function getList(page, cbk) {
    var cache = listCacheService.get(page);
    if (cache) {
      cbk(cache);
    } else {
      addLoading();
    }
    var gistsPromise = getPromise({
      url: 'https://api.github.com/users/yetone/gists?page=' + page,
      type: 'GET'
    });
    gistsPromise.done(function(jsn) {
      var render = shani.compile(gistListTpl);
      var html = render({
        gists: jsn.filter(function(item) {
          return !!item.description && !!item.files['gistfile1.md'] && (item.files['gistfile1.md'].language === 'Markdown');
        })
      });
      listCacheService.set(page, html);
      cbk(html);
    });
  }
  function getDetail(id, cbk) {
    var justCache = !cbk;
    cbk = cbk || function() {};
    var cache = detailCacheService.get(id);
    if (cache) {
      cbk(cache);
    } else if (!justCache) {
      addLoading();
    }
    function renderData(data) {
      var render = shani.compile(gistDetailTpl);
      var html = render(data);
      detailCacheService.set(id, html);
      return cbk(html);
    }
    var detailPromise = getPromise({
      url: 'https://api.github.com/gists/' + id,
      type: 'GET'
    });
    detailPromise.done(function(jsn) {
      if (!jsn.description || !jsn.files['gistfile1.md'] || (jsn.files['gistfile1.md'].language !== 'Markdown')) {
        console.log('not a Markdown file!!!');
        return;
      }
      var rawUrl = jsn.files['gistfile1.md'].raw_url;
      var key = rawUrl + ':' + (new Date(jsn.updated_at) - 0);
      var _cache = fileCacheService.get(key);
      if (_cache) {
        var data = {
          title: jsn.description,
          content: _cache,
          created_at: jsn.created_at
        };
        return renderData(data);
      }
      var filePromise = getPromise({
        url: rawUrl,
        type: 'GET'
      });
      filePromise.done(function(txt) {
        var content = marked(txt);
        var data = {
          title: jsn.description,
          content: content,
          created_at: jsn.created_at
        };
        fileCacheService.set(key, content);
        renderData(data);
      });
    });
  }
  function cacheAll() {
    var $gistItemList = $('.gist-item');
    $gistItemList.each(function(_, item) {
      var $item = $(item);
      var id = $item.data('id');
      getDetail(id);
    });
  }
  function homeHandler(request) {
    getList(request.params.page || '1', function(html) {
      var $gistList = $main.find('#gist-list');
      if (!$gistList.length) {
        $main.html('
' + html + '
');
      } else {
        $gistList.html(html);
      }
      removeLoading();
      cacheAll();
    });
  }
  function blogDetailHandler(request, id) {
    getDetail(id, function(html) {
      $main.html(html);
      removeLoading();
    });
  }
  router(routers);
});
<|endoftext|>


<commit_before>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ExchangeError, ArgumentsRequired } = require ('./base/errors');

//  ---------------------------------------------------------------------------

module.exports = class mercado extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'mercado',
            'name': 'Mercado Bitcoin',
            'countries': ['BR'], // Brazil
            'rateLimit': 1000,
            'version': 'v3',
            'has': {
                'CORS': true,
                'createMarketOrder': true,
                'fetchOrder': true,
                'withdraw': true,
                'fetchOHLCV': true,
                'fetchOrders': true,
                'fetchOpenOrders': true,
                'fetchTicker': true,
                'fetchTickers': false,
            },
            'timeframes': {
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '6h': '6h',
                '12h': '12h',
                '1d': '1d',
                '3d': '3d',
                '1w': '1w',
                '2w': '2w',
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27837060-e7c58714-60ea-11e7-9192-f05e86adb83f.jpg',
                'api': {
                    'public': 'https://www.mercadobitcoin.net/api',
                    'private': 'https://www.mercadobitcoin.net/tapi',
                    'v4Public': 'https://www.mercadobitcoin.com.br/v4',
                },
                'www': 'https://www.mercadobitcoin.com.br',
                'doc': [
                    'https://www.mercadobitcoin.com.br/api-doc',
                    'https://www.mercadobitcoin.com.br/trade-api',
                ],
            },
            'api': {
                'public': {
                    'get': [
                        '{coin}/orderbook/', // last slash critical
                        '{coin}/ticker/',
                        '{coin}/trades/',
                        '{coin}/trades/{from}/',
                        '{coin}/trades/{from}/{to}',
                        '{coin}/day-summary/{year}/{month}/{day}/',
                    ],
                },
                'private': {
                    'post': [
                        'cancel_order',
                        'get_account_info',
                        'get_order',
                        'get_withdrawal',
                        'list_system_messages',
                        'list_orders',
                        'list_orderbook',
                        'place_buy_order',
                        'place_sell_order',
                        'place_market_buy_order',
                        'place_market_sell_order',
                        'withdraw_coin',
                    ],
                },
                'v4Public': {
                    'get': [
                        '{coin}/candle/',
                    ],
                },
            },
            'markets': {
                'BTC/BRL': { 'id': 'BRLBTC', 'symbol': 'BTC/BRL', 'base': 'BTC', 'quote': 'BRL', 'suffix': 'Bitcoin' },
                'LTC/BRL': { 'id': 'BRLLTC', 'symbol': 'LTC/BRL', 'base': 'LTC', 'quote': 'BRL', 'suffix': 'Litecoin' },
                'BCH/BRL': { 'id': 'BRLBCH', 'symbol': 'BCH/BRL', 'base': 'BCH', 'quote': 'BRL', 'suffix': 'BCash' },
                'XRP/BRL': { 'id': 'BRLXRP', 'symbol': 'XRP/BRL', 'base': 'XRP', 'quote': 'BRL', 'suffix': 'Ripple' },
                'ETH/BRL': { 'id': 'BRLETH', 'symbol': 'ETH/BRL', 'base': 'ETH', 'quote': 'BRL', 'suffix': 'Ethereum' },
            },
            'fees': {
                'trading': {
                    'maker': 0.3 / 100,
                    'taker': 0.7 / 100,
                },
            },
        });
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        let market = this.market (symbol);
        let orderbook = await this.publicGetCoinOrderbook (this.extend ({
            'coin': market['base'],
        }, params));
        return this.parseOrderBook (orderbook);
    }

    async fetchTicker (symbol, params = {}) {
        let market = this.market (symbol);
        let response = await this.publicGetCoinTicker (this.extend ({
            'coin': market['base'],
        }, params));
        let ticker = response['ticker'];
        let timestamp = parseInt (ticker['date']) * 1000;
        let last = this.safeFloat (ticker, 'last');
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': this.safeFloat (ticker, 'high'),
            'low': this.safeFloat (ticker, 'low'),
            'bid': this.safeFloat (ticker, 'buy'),
            'bidVolume': undefined,
            'ask': this.safeFloat (ticker, 'sell'),
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': this.safeFloat (ticker, 'vol'),
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    parseTrade (trade, market) {
        let timestamp = trade['date'] * 1000;
        return {
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': market['symbol'],
            'id': trade['tid'].toString (),
            'order': undefined,
            'type': undefined,
            'side': trade['type'],
            'price': trade['price'],
            'amount': trade['amount'],
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        let market = this.market (symbol);
        let method = 'publicGetCoinTrades';
        let request = {
            'coin': market['base'],
        };
        if (since !== undefined) {
            method += 'From';
            request['from'] = parseInt (since / 1000);
        }
        let to = this.safeInteger (params, 'to');
        if (to !== undefined)
            method += 'To';
        let response = await this[method] (this.extend (request, params));
        return this.parseTrades (response, market, since, limit);
    }

    async fetchBalance (params = {}) {
        let response = await this.privatePostGetAccountInfo ();
        let balances = response['response_data']['balance'];
        let result = { 'info': response };
        let currencies = Object.keys (this.currencies);
        for (let i = 0; i < currencies.length; i++) {
            let currency = currencies[i];
            let lowercase = currency.toLowerCase ();
            let account = this.account ();
            if (lowercase in balances) {
                account['free'] = parseFloat (balances[lowercase]['available']);
                account['total'] = parseFloat (balances[lowercase]['total']);
                account['used'] = account['total'] - account['free'];
            }
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        let order = {
            'coin_pair': this.marketId (symbol),
        };
        let method = 'privatePostPlace' + this.capitalize (side) + 'Order';
        if (type === 'limit') {
            order['limit_price'] = price;
            order['quantity'] = amount;
        } else {
            method = 'privatePostPlaceMarket' + this.capitalize (side) + 'Order';
            if (side === 'buy') {
                order['cost'] = (amount * price).toFixed (5);
            } else {
                order['quantity'] = amount;
            }
        }
        let response = await this[method] (this.extend (order, params));
        return {
            'info': response,
            'id': response['response_data']['order']['order_id'].toString (),
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        if (symbol === undefined)
            throw new ArgumentsRequired (this.id + ' cancelOrder () requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.privatePostCancelOrder (this.extend ({
            'coin_pair': market['id'],
            'order_id': id,
        }, params));
        return this.parseOrder (response['response_data']['order'], market);
    }

    parseOrderStatus (status) {
        const statuses = {
            '2': 'open',
            '3': 'canceled',
            '4': 'closed',
        };
        return this.safeString (statuses, status, status);
    }

    parseOrder (order, market = undefined) {
        const id = this.safeString (order, 'order_id');
        let side = undefined;
        if ('order_type' in order)
            side = (order['order_type'] === 1) ? 'buy' : 'sell';
        let status = this.parseOrderStatus (this.safeString (order, 'status'));
        let symbol = undefined;
        if (market === undefined) {
            let marketId = this.safeString (order, 'coin_pair');
            market = this.safeValue (this.markets_by_id, marketId);
        }
        if (market !== undefined) {
            symbol = market['symbol'];
        }
        let timestamp = this.safeInteger (order, 'created_timestamp');
        if (timestamp !== undefined) {
            timestamp = timestamp * 1000;
        }
        let fee = {
            'cost': this.safeFloat (order, 'fee'),
            'currency': market['quote'],
        };
        let price = this.safeFloat (order, 'limit_price');
        // price = this.safeFloat (order, 'executed_price_avg', price);
        let average = this.safeFloat (order, 'executed_price_avg');
        let amount = this.safeFloat (order, 'quantity');
        let filled = this.safeFloat (order, 'executed_quantity');
        let remaining = amount - filled;
        let cost = amount * average;
        let lastTradeTimestamp = this.safeInteger (order, 'updated_timestamp');
        if (lastTradeTimestamp !== undefined) {
            lastTradeTimestamp = lastTradeTimestamp * 1000;
        }
        let result = {
            'info': order,
            'id': id,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'lastTradeTimestamp': lastTradeTimestamp,
            'symbol': symbol,
            'type': 'limit',
            'side': side,
            'price': price,
            'cost': cost,
            'average': average,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'status': status,
            'fee': fee,
            'trades': undefined, // todo parse trades (operations)
        };
        return result;
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchOrder () requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'coin_pair': market['id'],
            'order_id': parseInt (id),
        };
        const response = await this.privatePostGetOrder (this.extend (request, params));
        const responseData = this.safeValue (response, 'response_data', {});
        const order = this.safeValue (responseData, 'order');
        return this.parseOrder (order);
    }

    async withdraw (code, amount, address, tag = undefined, params = {}) {
        this.checkAddress (address);
        await this.loadMarkets ();
        let currency = this.currency (code);
        let request = {
            'coin': currency['id'],
            'quantity': amount.toFixed (10),
            'address': address,
        };
        if (code === 'BRL') {
            let account_ref = ('account_ref' in params);
            if (!account_ref) {
                throw new ExchangeError (this.id + ' requires account_ref parameter to withdraw ' + code);
            }
        } else if (code !== 'LTC') {
            let tx_fee = ('tx_fee' in params);
            if (!tx_fee) {
                throw new ExchangeError (this.id + ' requires tx_fee parameter to withdraw ' + code);
            }
            if (code === 'XRP') {
                if (tag === undefined) {
                    if (!('destination_tag' in params)) {
                        throw new ExchangeError (this.id + ' requires a tag argument or destination_tag parameter to withdraw ' + code);
                    }
                } else {
                    request['destination_tag'] = tag;
                }
            }
        }
        let response = await this.privatePostWithdrawCoin (this.extend (request, params));
        return {
            'info': response,
            'id': response['response_data']['withdrawal']['id'],
        };
    }

    parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
        return [
            ohlcv['timestamp'] * 1000,
            parseFloat (ohlcv['open']),
            parseFloat (ohlcv['high']),
            parseFloat (ohlcv['low']),
            parseFloat (ohlcv['close']),
            parseFloat (ohlcv['volume']),
        ];
    }

    async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'precision': this.timeframes[timeframe],
            'coin': market.id.toLowerCase (),
        };
        if (since !== undefined) {
            request['from'] = parseInt (since / 1000);
            if (limit !== undefined) {
                request['to'] = (this.sum (request['from'], limit * this.parseTimeframe (timeframe)));
            } else {
                request['to'] = this.sum (this.seconds (), 1);
            }
        }
        let response = await this.v4PublicGetCoinCandle (this.extend (request, params));
        return this.parseOHLCVs (response.candles, market, timeframe, since, limit);
    }

    async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchOrders () requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'coin_pair': market['base'],
        };
        const response = await this.privatePostListOrders (this.extend (request, params));
        const responseData = this.safeValue (response, 'response_data', {});
        const orders = this.safeValue (responseData, 'orders', []);
        return this.parseOrders (orders, market, since, limit);
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api'][api] + '/';
        let query = this.omit (params, this.extractParams (path));
        if (api === 'public' || (api === 'v4Public')) {
            url += this.implodeParams (path, params);
            if (Object.keys (query).length)
                url += '?' + this.urlencode (query);
        } else {
            this.checkRequiredCredentials ();
            url += this.version + '/';
            let nonce = this.nonce ();
            body = this.urlencode (this.extend ({
                'tapi_method': path,
                'tapi_nonce': nonce,
            }, params));
            let auth = '/tapi/' + this.version + '/' + '?' + body;
            headers = {
                'Content-Type': 'application/x-www-form-urlencoded',
                'TAPI-ID': this.apiKey,
                'TAPI-MAC': this.hmac (this.encode (auth), this.encode (this.secret), 'sha512'),
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let response = await this.fetch2 (path, api, method, params, headers, body);
        if ('error_message' in response)
            throw new ExchangeError (this.id + ' ' + this.json (response));
        return response;
    }
};
<commit_msg>mercado cancelOrder rewrite + fetchOrder edits<commit_after>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ExchangeError, ArgumentsRequired } = require ('./base/errors');

//  ---------------------------------------------------------------------------

module.exports = class mercado extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'mercado',
            'name': 'Mercado Bitcoin',
            'countries': ['BR'], // Brazil
            'rateLimit': 1000,
            'version': 'v3',
            'has': {
                'CORS': true,
                'createMarketOrder': true,
                'fetchOrder': true,
                'withdraw': true,
                'fetchOHLCV': true,
                'fetchOrders': true,
                'fetchOpenOrders': true,
                'fetchTicker': true,
                'fetchTickers': false,
            },
            'timeframes': {
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '6h': '6h',
                '12h': '12h',
                '1d': '1d',
                '3d': '3d',
                '1w': '1w',
                '2w': '2w',
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27837060-e7c58714-60ea-11e7-9192-f05e86adb83f.jpg',
                'api': {
                    'public': 'https://www.mercadobitcoin.net/api',
                    'private': 'https://www.mercadobitcoin.net/tapi',
                    'v4Public': 'https://www.mercadobitcoin.com.br/v4',
                },
                'www': 'https://www.mercadobitcoin.com.br',
                'doc': [
                    'https://www.mercadobitcoin.com.br/api-doc',
                    'https://www.mercadobitcoin.com.br/trade-api',
                ],
            },
            'api': {
                'public': {
                    'get': [
                        '{coin}/orderbook/', // last slash critical
                        '{coin}/ticker/',
                        '{coin}/trades/',
                        '{coin}/trades/{from}/',
                        '{coin}/trades/{from}/{to}',
                        '{coin}/day-summary/{year}/{month}/{day}/',
                    ],
                },
                'private': {
                    'post': [
                        'cancel_order',
                        'get_account_info',
                        'get_order',
                        'get_withdrawal',
                        'list_system_messages',
                        'list_orders',
                        'list_orderbook',
                        'place_buy_order',
                        'place_sell_order',
                        'place_market_buy_order',
                        'place_market_sell_order',
                        'withdraw_coin',
                    ],
                },
                'v4Public': {
                    'get': [
                        '{coin}/candle/',
                    ],
                },
            },
            'markets': {
                'BTC/BRL': { 'id': 'BRLBTC', 'symbol': 'BTC/BRL', 'base': 'BTC', 'quote': 'BRL', 'suffix': 'Bitcoin' },
                'LTC/BRL': { 'id': 'BRLLTC', 'symbol': 'LTC/BRL', 'base': 'LTC', 'quote': 'BRL', 'suffix': 'Litecoin' },
                'BCH/BRL': { 'id': 'BRLBCH', 'symbol': 'BCH/BRL', 'base': 'BCH', 'quote': 'BRL', 'suffix': 'BCash' },
                'XRP/BRL': { 'id': 'BRLXRP', 'symbol': 'XRP/BRL', 'base': 'XRP', 'quote': 'BRL', 'suffix': 'Ripple' },
                'ETH/BRL': { 'id': 'BRLETH', 'symbol': 'ETH/BRL', 'base': 'ETH', 'quote': 'BRL', 'suffix': 'Ethereum' },
            },
            'fees': {
                'trading': {
                    'maker': 0.3 / 100,
                    'taker': 0.7 / 100,
                },
            },
        });
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        let market = this.market (symbol);
        let orderbook = await this.publicGetCoinOrderbook (this.extend ({
            'coin': market['base'],
        }, params));
        return this.parseOrderBook (orderbook);
    }

    async fetchTicker (symbol, params = {}) {
        let market = this.market (symbol);
        let response = await this.publicGetCoinTicker (this.extend ({
            'coin': market['base'],
        }, params));
        let ticker = response['ticker'];
        let timestamp = parseInt (ticker['date']) * 1000;
        let last = this.safeFloat (ticker, 'last');
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': this.safeFloat (ticker, 'high'),
            'low': this.safeFloat (ticker, 'low'),
            'bid': this.safeFloat (ticker, 'buy'),
            'bidVolume': undefined,
            'ask': this.safeFloat (ticker, 'sell'),
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': this.safeFloat (ticker, 'vol'),
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    parseTrade (trade, market) {
        let timestamp = trade['date'] * 1000;
        return {
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': market['symbol'],
            'id': trade['tid'].toString (),
            'order': undefined,
            'type': undefined,
            'side': trade['type'],
            'price': trade['price'],
            'amount': trade['amount'],
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        let market = this.market (symbol);
        let method = 'publicGetCoinTrades';
        let request = {
            'coin': market['base'],
        };
        if (since !== undefined) {
            method += 'From';
            request['from'] = parseInt (since / 1000);
        }
        let to = this.safeInteger (params, 'to');
        if (to !== undefined)
            method += 'To';
        let response = await this[method] (this.extend (request, params));
        return this.parseTrades (response, market, since, limit);
    }

    async fetchBalance (params = {}) {
        let response = await this.privatePostGetAccountInfo ();
        let balances = response['response_data']['balance'];
        let result = { 'info': response };
        let currencies = Object.keys (this.currencies);
        for (let i = 0; i < currencies.length; i++) {
            let currency = currencies[i];
            let lowercase = currency.toLowerCase ();
            let account = this.account ();
            if (lowercase in balances) {
                account['free'] = parseFloat (balances[lowercase]['available']);
                account['total'] = parseFloat (balances[lowercase]['total']);
                account['used'] = account['total'] - account['free'];
            }
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        let order = {
            'coin_pair': this.marketId (symbol),
        };
        let method = 'privatePostPlace' + this.capitalize (side) + 'Order';
        if (type === 'limit') {
            order['limit_price'] = price;
            order['quantity'] = amount;
        } else {
            method = 'privatePostPlaceMarket' + this.capitalize (side) + 'Order';
            if (side === 'buy') {
                order['cost'] = (amount * price).toFixed (5);
            } else {
                order['quantity'] = amount;
            }
        }
        let response = await this[method] (this.extend (order, params));
        return {
            'info': response,
            'id': response['response_data']['order']['order_id'].toString (),
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' cancelOrder () requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'coin_pair': market['id'],
            'order_id': id,
        };
        const response = await this.privatePostCancelOrder (this.extend (request, params));
        const responseData = this.safeValue (response, 'response_data', {});
        const order = this.safeValue (responseData, 'order', {})
        return this.parseOrder (order, market);
    }

    parseOrderStatus (status) {
        const statuses = {
            '2': 'open',
            '3': 'canceled',
            '4': 'closed',
        };
        return this.safeString (statuses, status, status);
    }

    parseOrder (order, market = undefined) {
        const id = this.safeString (order, 'order_id');
        let side = undefined;
        if ('order_type' in order)
            side = (order['order_type'] === 1) ? 'buy' : 'sell';
        let status = this.parseOrderStatus (this.safeString (order, 'status'));
        let symbol = undefined;
        if (market === undefined) {
            let marketId = this.safeString (order, 'coin_pair');
            market = this.safeValue (this.markets_by_id, marketId);
        }
        if (market !== undefined) {
            symbol = market['symbol'];
        }
        let timestamp = this.safeInteger (order, 'created_timestamp');
        if (timestamp !== undefined) {
            timestamp = timestamp * 1000;
        }
        let fee = {
            'cost': this.safeFloat (order, 'fee'),
            'currency': market['quote'],
        };
        let price = this.safeFloat (order, 'limit_price');
        // price = this.safeFloat (order, 'executed_price_avg', price);
        let average = this.safeFloat (order, 'executed_price_avg');
        let amount = this.safeFloat (order, 'quantity');
        let filled = this.safeFloat (order, 'executed_quantity');
        let remaining = amount - filled;
        let cost = amount * average;
        let lastTradeTimestamp = this.safeInteger (order, 'updated_timestamp');
        if (lastTradeTimestamp !== undefined) {
            lastTradeTimestamp = lastTradeTimestamp * 1000;
        }
        let result = {
            'info': order,
            'id': id,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'lastTradeTimestamp': lastTradeTimestamp,
            'symbol': symbol,
            'type': 'limit',
            'side': side,
            'price': price,
            'cost': cost,
            'average': average,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'status': status,
            'fee': fee,
            'trades': undefined, // todo parse trades (operations)
        };
        return result;
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchOrder () requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'coin_pair': market['id'],
            'order_id': parseInt (id),
        };
        const response = await this.privatePostGetOrder (this.extend (request, params));
        const responseData = this.safeValue (response, 'response_data', {});
        const order = this.safeValue (responseData, 'order');
        return this.parseOrder (order, market);
    }

    async withdraw (code, amount, address, tag = undefined, params = {}) {
        this.checkAddress (address);
        await this.loadMarkets ();
        let currency = this.currency (code);
        let request = {
            'coin': currency['id'],
            'quantity': amount.toFixed (10),
            'address': address,
        };
        if (code === 'BRL') {
            let account_ref = ('account_ref' in params);
            if (!account_ref) {
                throw new ExchangeError (this.id + ' requires account_ref parameter to withdraw ' + code);
            }
        } else if (code !== 'LTC') {
            let tx_fee = ('tx_fee' in params);
            if (!tx_fee) {
                throw new ExchangeError (this.id + ' requires tx_fee parameter to withdraw ' + code);
            }
            if (code === 'XRP') {
                if (tag === undefined) {
                    if (!('destination_tag' in params)) {
                        throw new ExchangeError (this.id + ' requires a tag argument or destination_tag parameter to withdraw ' + code);
                    }
                } else {
                    request['destination_tag'] = tag;
                }
            }
        }
        let response = await this.privatePostWithdrawCoin (this.extend (request, params));
        return {
            'info': response,
            'id': response['response_data']['withdrawal']['id'],
        };
    }

    parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
        return [
            ohlcv['timestamp'] * 1000,
            parseFloat (ohlcv['open']),
            parseFloat (ohlcv['high']),
            parseFloat (ohlcv['low']),
            parseFloat (ohlcv['close']),
            parseFloat (ohlcv['volume']),
        ];
    }

    async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'precision': this.timeframes[timeframe],
            'coin': market.id.toLowerCase (),
        };
        if (since !== undefined) {
            request['from'] = parseInt (since / 1000);
            if (limit !== undefined) {
                request['to'] = (this.sum (request['from'], limit * this.parseTimeframe (timeframe)));
            } else {
                request['to'] = this.sum (this.seconds (), 1);
            }
        }
        let response = await this.v4PublicGetCoinCandle (this.extend (request, params));
        return this.parseOHLCVs (response.candles, market, timeframe, since, limit);
    }

    async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchOrders () requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'coin_pair': market['base'],
        };
        const response = await this.privatePostListOrders (this.extend (request, params));
        const responseData = this.safeValue (response, 'response_data', {});
        const orders = this.safeValue (responseData, 'orders', []);
        return this.parseOrders (orders, market, since, limit);
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api'][api] + '/';
        let query = this.omit (params, this.extractParams (path));
        if (api === 'public' || (api === 'v4Public')) {
            url += this.implodeParams (path, params);
            if (Object.keys (query).length)
                url += '?' + this.urlencode (query);
        } else {
            this.checkRequiredCredentials ();
            url += this.version + '/';
            let nonce = this.nonce ();
            body = this.urlencode (this.extend ({
                'tapi_method': path,
                'tapi_nonce': nonce,
            }, params));
            let auth = '/tapi/' + this.version + '/' + '?' + body;
            headers = {
                'Content-Type': 'application/x-www-form-urlencoded',
                'TAPI-ID': this.apiKey,
                'TAPI-MAC': this.hmac (this.encode (auth), this.encode (this.secret), 'sha512'),
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let response = await this.fetch2 (path, api, method, params, headers, body);
        if ('error_message' in response)
            throw new ExchangeError (this.id + ' ' + this.json (response));
        return response;
    }
};
<|endoftext|>


<commit_before>var updateDownloadLink = function () {
  var platform = uaParserJs().os.name
  var releaseServer = 'https://electron-api-demos.githubapp.com/updates/'
  var assetName
  var osLabel

  if (platform.match(/mac/i)) {
    assetName = 'electron-api-demos-mac.zip'
    osLabel = 'Mac'
  } else if (platform.match(/windows/i)) {
    assetName = 'ElectronAPIDemosSetup.exe'
    osLabel = 'Windows'
  } else if (platform.match(/ubuntu/i)) {
    assetName = 'electron-api-demos-linux.zip'
    osLabel = 'Linux'
  } else {
    return
  }

  document.querySelector('#download-latest-release')
    .setAttribute('href', releaseServer + assetName)

  document.querySelector('#download-latest-release .label')
    .textContent = 'Download for ' + osLabel

  document.querySelector('#download-alternatives')
    .style.display = 'inline-block'
}

document.addEventListener('DOMContentLoaded', updateDownloadLink)
<commit_msg>Add linux to pattern<commit_after>var updateDownloadLink = function () {
  var platform = uaParserJs().os.name
  var releaseServer = 'https://electron-api-demos.githubapp.com/updates/'
  var assetName
  var osLabel

  if (platform.match(/mac/i)) {
    assetName = 'electron-api-demos-mac.zip'
    osLabel = 'Mac'
  } else if (platform.match(/windows/i)) {
    assetName = 'ElectronAPIDemosSetup.exe'
    osLabel = 'Windows'
  } else if (platform.match(/ubuntu|linux/i)) {
    assetName = 'electron-api-demos-linux.zip'
    osLabel = 'Linux'
  } else {
    return
  }

  document.querySelector('#download-latest-release')
    .setAttribute('href', releaseServer + assetName)

  document.querySelector('#download-latest-release .label')
    .textContent = 'Download for ' + osLabel

  document.querySelector('#download-alternatives')
    .style.display = 'inline-block'
}

document.addEventListener('DOMContentLoaded', updateDownloadLink)
<|endoftext|>