<commit_before>var e = module.exports = {};

e.init = () => {

    e.category = bu.CommandType.ADMIN;
};

e.requireCtx = require;

e.isCommand = true;
e.hidden = false;
e.usage = 'roleme <list | add | remove>';
e.info = 'A roleme is a system to automatically give/remove roles to a user when they say a specific catchphrase. You can make these catchphrases anything you want, case sensitive/insensitive, and only activate in specific channels. The roleme command has three subcommands:\n\n**list**: lists all the rolemes active on the guild.\n**add**: adds a roleme to the guild. Just follow the instructions.\n**remove**: returns a list of rolemes so you can choose one to remove.';
e.long = `
A roleme is a system to automatically give/remove roles to a
user when they say a specific catchphrase. You can make these catchphrases
anything you want, case sensitive/insensitive, and only activate in
specific channels. The roleme command has three subcommands:

list: lists all the rolemes active on the guild.

add: adds a roleme to the guild. Just follow the instructions.

remove: returns a list of rolemes so you can choose one to remove.<\li><\\ul>`;

e.execute = async function(msg, words) {
    if (words[1]) {
        bu.dirtyCache[msg.guild.id] = true;

        let storedGuild = await bu.getGuild(msg.guild.id);
        let roleme = storedGuild.roleme;
        let res, rolemeString, rolemeList;
        if (roleme == undefined) roleme = [];
        switch (words[1].toLowerCase()) {
            case 'add':
                let addList = [];
                let resList;
                res = (await bu.awaitMessage(msg, 'List all the roles that this will add, each on a new line. If you do not wish any roles, type `0`.')).content;
                if (res != 0) {
                    resList = res.split('\n');
                    for (let i = 0; i < resList.length; i++) {
                        let role = await bu.getRole(msg, resList[i]);
                        // logger.debug(role);
                        if (role)
                            addList.push(role.id);
                    }
                }
                let removeList = [];
                res = (await bu.awaitMessage(msg, 'List all the roles that this will remove, each on a new line. If you do not wish any roles, type `0`.')).content;
                if (res != 0) {
                    resList = res.split('\n');
                    for (let i = 0; i < resList.length; i++) {
                        let role = await bu.getRole(msg, resList[i]);
                        if (role)
                            removeList.push(role.id);
                    }
                }
                if (addList.length == 0 && removeList.length == 0) {
                    await bu.send(msg, 'You must have some roles!');
                    break;
                }
                let channelList = [];
                res = (await bu.awaitMessage(msg, 'Mention all the channels that this will apply to (in #<channelname> format). Alternatively, don\'t mention any channels to make it apply everywhere.'));
                channelList = res.channelMentions;
                let activationMessage = (await bu.awaitMessage(msg, 'Type the sentence that users should type in order for this action to happen.')).content;
                let caseSensitive = (await bu.awaitMessage(msg, 'Type `1` if the previous sentence should be case-sensitive. Type anything else to make it match regardless of capitalization.'));
                caseSensitive = caseSensitive.content == '1' ? true : false;
                logger.debug(addList, removeList);
                roleme.push({
                    add: addList,
                    remove: removeList,
                    channels: channelList,
                    message: activationMessage,
                    casesensitive: caseSensitive,
                });
                await r.table('guild').get(msg.channel.guild.id).update({
                    roleme: roleme
                }).run();
                bu.send(msg, 'Roleme added!');
                break;
            case 'remove':
                if (roleme.length == 0) {
                    await bu.send(msg, 'You have no rolemes created!');
                    break;
                }
                rolemeString = 'Here are the rolemes on your guild:\n```prolog\n';
                let condensed = false;
                if (roleme.length >= 30) {
                    rolemeList = roleme.map(m => {
                        return `Message: ${m.message}`;
                    });
                    condensed = true;
                } else {
                    rolemeList = roleme.map(m => {
                        return `  Message: ${m.message}
  Channel(s): ${m.channels.join(' ')}`;
                    });
                }
                for (let i = 0; i < rolemeList.length; i++) {
                    rolemeString += `${i + 1}:${condensed ? ' ' + (i < 9 ? ' ' : '') : '\n'}${rolemeList[i]}\n`;
                }
                if (rolemeString.length > 1900) rolemeString = rolemeString.substring(0, 1850) + '...';
                rolemeString += '```\nPlease type the number of the roleme you wish to remove, or `c` to cancel.';
                //  logger.debug(rolemeString.length, rolemeString);
                let resMsg = (await bu.awaitMessage(msg, rolemeString, m => (!isNaN(parseInt(m.content)) && parseInt(m.content) > 0 && parseInt(m.content) <= rolemeList.length) || m.content.toLowerCase() == 'c'));
                if (resMsg.content.toLowerCase() == 'c') {
                    await bu.send(msg, 'Remove canceled!');
                    break;
                }
                roleme.splice(parseInt(resMsg.content) - 1, 1);
                storedGuild.roleme = roleme;
                await r.table('guild').get(msg.channel.guild.id).replace(storedGuild).run();
                let delmsg = bu.awaitMessages[msg.channel.id][msg.author.id].botmsg;
                await bot.deleteMessage(delmsg.channel.id, delmsg.id);
                await bu.send(msg, 'Done! :ok_hand:');
                break;
            case 'list':
                if (roleme.length == 0) {
                    await bu.send(msg, 'You have no rolemes created!');
                    break;
                }
                rolemeString = 'Here are the rolemes on your guild:\n```prolog\n';
                let condensed = false;
                if (roleme.length >= 30) {
                    rolemeList = roleme.map(m => {
                        return `Message: ${m.message}`;
                    });
                    condensed = true;
                } else {
                    rolemeList = roleme.map(m => {
                        return `  Message: ${m.message}
  Channel(s): ${m.channels.join(' ')}`;
                    });
                }
                for (let i = 0; i < rolemeList.length; i++) {
                    rolemeString += `${i + 1}:${condensed ? ' ' + (i < 9 ? ' ' : '') : '\n'}${rolemeList[i]}\n`;
                }
                if (rolemeString.length > 2000) rolemeString = rolemeString.substring(0, 1994) + '...';
                rolemeString += '```';
                bu.send(msg, rolemeString);
                break;
            default:
                bu.send(msg, e.info);
                break;
        }
    } else {
        bu.send(msg, e.info);
    }
};<commit_msg>scopign issues<commit_after>var e = module.exports = {};

e.init = () => {

    e.category = bu.CommandType.ADMIN;
};

e.requireCtx = require;

e.isCommand = true;
e.hidden = false;
e.usage = 'roleme <list | add | remove>';
e.info = 'A roleme is a system to automatically give/remove roles to a user when they say a specific catchphrase. You can make these catchphrases anything you want, case sensitive/insensitive, and only activate in specific channels. The roleme command has three subcommands:\n\n**list**: lists all the rolemes active on the guild.\n**add**: adds a roleme to the guild. Just follow the instructions.\n**remove**: returns a list of rolemes so you can choose one to remove.';
e.long = `
A roleme is a system to automatically give/remove roles to a
user when they say a specific catchphrase. You can make these catchphrases
anything you want, case sensitive/insensitive, and only activate in
specific channels. The roleme command has three subcommands:

list: lists all the rolemes active on the guild.

add: adds a roleme to the guild. Just follow the instructions.

remove: returns a list of rolemes so you can choose one to remove.<\li><\\ul>`;

e.execute = async function(msg, words) {
    if (words[1]) {
        bu.dirtyCache[msg.guild.id] = true;

        let storedGuild = await bu.getGuild(msg.guild.id);
        let roleme = storedGuild.roleme;
        let res, rolemeString, rolemeList, condensed = false;
        if (roleme == undefined) roleme = [];
        switch (words[1].toLowerCase()) {
            case 'add':
                let addList = [];
                let resList;
                res = (await bu.awaitMessage(msg, 'List all the roles that this will add, each on a new line. If you do not wish any roles, type `0`.')).content;
                if (res != 0) {
                    resList = res.split('\n');
                    for (let i = 0; i < resList.length; i++) {
                        let role = await bu.getRole(msg, resList[i]);
                        // logger.debug(role);
                        if (role)
                            addList.push(role.id);
                    }
                }
                let removeList = [];
                res = (await bu.awaitMessage(msg, 'List all the roles that this will remove, each on a new line. If you do not wish any roles, type `0`.')).content;
                if (res != 0) {
                    resList = res.split('\n');
                    for (let i = 0; i < resList.length; i++) {
                        let role = await bu.getRole(msg, resList[i]);
                        if (role)
                            removeList.push(role.id);
                    }
                }
                if (addList.length == 0 && removeList.length == 0) {
                    await bu.send(msg, 'You must have some roles!');
                    break;
                }
                let channelList = [];
                res = (await bu.awaitMessage(msg, 'Mention all the channels that this will apply to (in #<channelname> format). Alternatively, don\'t mention any channels to make it apply everywhere.'));
                channelList = res.channelMentions;
                let activationMessage = (await bu.awaitMessage(msg, 'Type the sentence that users should type in order for this action to happen.')).content;
                let caseSensitive = (await bu.awaitMessage(msg, 'Type `1` if the previous sentence should be case-sensitive. Type anything else to make it match regardless of capitalization.'));
                caseSensitive = caseSensitive.content == '1' ? true : false;
                logger.debug(addList, removeList);
                roleme.push({
                    add: addList,
                    remove: removeList,
                    channels: channelList,
                    message: activationMessage,
                    casesensitive: caseSensitive,
                });
                await r.table('guild').get(msg.channel.guild.id).update({
                    roleme: roleme
                }).run();
                bu.send(msg, 'Roleme added!');
                break;
            case 'remove':
                if (roleme.length == 0) {
                    await bu.send(msg, 'You have no rolemes created!');
                    break;
                }
                rolemeString = 'Here are the rolemes on your guild:\n```prolog\n';
                if (roleme.length >= 30) {
                    rolemeList = roleme.map(m => {
                        return `Message: ${m.message}`;
                    });
                    condensed = true;
                } else {
                    rolemeList = roleme.map(m => {
                        return `  Message: ${m.message}
  Channel(s): ${m.channels.join(' ')}`;
                    });
                }
                for (let i = 0; i < rolemeList.length; i++) {
                    rolemeString += `${i + 1}:${condensed ? ' ' + (i < 9 ? ' ' : '') : '\n'}${rolemeList[i]}\n`;
                }
                if (rolemeString.length > 1900) rolemeString = rolemeString.substring(0, 1850) + '...';
                rolemeString += '```\nPlease type the number of the roleme you wish to remove, or `c` to cancel.';
                //  logger.debug(rolemeString.length, rolemeString);
                let resMsg = (await bu.awaitMessage(msg, rolemeString, m => (!isNaN(parseInt(m.content)) && parseInt(m.content) > 0 && parseInt(m.content) <= rolemeList.length) || m.content.toLowerCase() == 'c'));
                if (resMsg.content.toLowerCase() == 'c') {
                    await bu.send(msg, 'Remove canceled!');
                    break;
                }
                roleme.splice(parseInt(resMsg.content) - 1, 1);
                storedGuild.roleme = roleme;
                await r.table('guild').get(msg.channel.guild.id).replace(storedGuild).run();
                let delmsg = bu.awaitMessages[msg.channel.id][msg.author.id].botmsg;
                await bot.deleteMessage(delmsg.channel.id, delmsg.id);
                await bu.send(msg, 'Done! :ok_hand:');
                break;
            case 'list':
                if (roleme.length == 0) {
                    await bu.send(msg, 'You have no rolemes created!');
                    break;
                }
                rolemeString = 'Here are the rolemes on your guild:\n```prolog\n';
                if (roleme.length >= 30) {
                    rolemeList = roleme.map(m => {
                        return `Message: ${m.message}`;
                    });
                    condensed = true;
                } else {
                    rolemeList = roleme.map(m => {
                        return `  Message: ${m.message}
  Channel(s): ${m.channels.join(' ')}`;
                    });
                }
                for (let i = 0; i < rolemeList.length; i++) {
                    rolemeString += `${i + 1}:${condensed ? ' ' + (i < 9 ? ' ' : '') : '\n'}${rolemeList[i]}\n`;
                }
                if (rolemeString.length > 2000) rolemeString = rolemeString.substring(0, 1994) + '...';
                rolemeString += '```';
                bu.send(msg, rolemeString);
                break;
            default:
                bu.send(msg, e.info);
                break;
        }
    } else {
        bu.send(msg, e.info);
    }
};<|endoftext|>


<commit_before>(function($) {
  var LOCALIZED_FIELDS, ADMIN_URL, $translation_field;

  $.holdReady(true);

  if (window.location.pathname.substr(-7)==='change/') {
    // When inside Django /change/ url, step back two path increments
    ADMIN_URL = window.location.pathname + '../../localizedfields/';
  } else {
    // When inside Django /add/ url (or others without a pk), step back one path increment
    ADMIN_URL = window.location.pathname + '../localizedfields/';
  }

  $.getJSON(ADMIN_URL, function (data) {})
      .done(function (data) {
          LOCALIZED_FIELDS = data;
          $.holdReady(false);
      })
      .fail(function () {
          $.holdReady(false);
          console.error('API endpoint admin/localizedfields not found.');
      });

  $(function() {
    // Shortcut, if there isn't any change form
    if (!LOCALIZED_FIELDS || !$('body').hasClass('change-form')) {return;}

    $translation_field = $('div.field-translated_languages input');

    if (window.location.search.match(/lang=(\w{2})/)) {
      visible_translations([LOCALIZED_FIELDS.default_language, RegExp.$1]);
    }
    $('fieldset.language').wrapAll('
');

    // move default language to first position
    $('fieldset.language.' + LOCALIZED_FIELDS.default_language).prependTo($('#all_languages'));

    prepare_language_selector();
    if (prepare_visibility_fields()) {
      prepare_fallback_checkbox();
    }
  });

  function prepare_language_selector() {
    // add checkboxes to turn display of individual languages on and off
    var lang_selectors = '
' +
                         '
' + LOCALIZED_FIELDS.translation_label + ': ',
        translations = visible_translations();

    $.each(LOCALIZED_FIELDS.languages, function() {
      var lang = this[0], name = this[1];

      // primary language can't be toggled
      if (lang == LOCALIZED_FIELDS.default_language) {return;}
      var show_fields_for_language = $.inArray(lang, translations) > -1;

      lang_selectors += '<input id="id_translation_show_' + lang + '" type="checkbox"  value="' + lang + '" ' +
        (show_fields_for_language ? 'checked="checked"' : '') + ' /> ' + '' +
        name + ' (' + lang + ')  ';

    });
    lang_selectors += '

';
    $('.breadcrumbs').after(lang_selectors);

    $('#language-selector').on('click', 'input', function() {
      if ($(this).is(':checked')) {
        visible_translations(this.value);
      } else {
        visible_translations(undefined, this.value);
      }
      show_hide_elements()
    });

    show_hide_elements()
  }

  function prepare_visibility_fields() {
    // add button to make all language versions visible
    $($('div[class*=field-visible][class*=field-box]')[0])  // before the first checkbox
      .before('
<input id="id_visible_all" type="checkbox"> '
        + 'Visible (all)
');
    $('#id_visible_all').change(function() {
      if ($(this).is(':checked')) {
        $('input[name^=visible]').attr('checked', false);
      } else {
        $('input[name^=visible]').attr('checked', true);
      }
    });

    $('input[name^=visible]').change(function() {
      // check or uncheck "all visible" checkbox when applicable
      if ($(this).is(':checked')) {
        if (!$('input[name^=visible]:not(:checked)').length) {
          $('#id_visible_all').attr('checked', true);
        }
      } else {
        $('#id_visible_all').attr('checked', false);
      }
    }).change();

    return $('div.field-translated_languages').hide().length > 0;
  }

  function prepare_fallback_checkbox() {
    var fallback_toggle_label_color = $('fieldset.language h2').css('color'),
        fallback_title = LOCALIZED_FIELDS.fallback_label.replace(/\{language\}/, LOCALIZED_FIELDS.languages[0][1]),
        active = active_translations();

    $.each(LOCALIZED_FIELDS.languages, function() {
      var lang = this[0], name = this[1],
          fallback_active = false;
          fallback_toggle_id = 'fallback-toggle-' + lang;

      if (lang == LOCALIZED_FIELDS.default_language) {return;}

      if ($.inArray(lang, active) == -1) {
        fallback_active = true;
      } else {
        $('#language-selector label[for=id_translation_show_' + lang + ']').addClass('translated');
      }

      $fallback_toggle = $(
        '
' +
        '<input type="checkbox" id="' + fallback_toggle_id + '" ' + (fallback_active ? 'checked="checked"' : '') + ' value="' + lang +
        '"/> ' + fallback_title + '' +
        '
'
      );

      $('fieldset.language.' + lang + ' h2').append($fallback_toggle);

    });

    function align_objects(){
      var field_types = [
          'link',
          'key_fact',
          'document',
          'title',
          'tile',
          'text',
          'name',
          'button',
          'image',
          'cropping',
          'headline',
          'teaser',
          'black_overlay_text'
      ];

      for(i=0; i<field_types.length; i++) {
        $('div[class*=' + field_types[i] + ']').addClass('field-' + field_types[i]);
      }

      $.each($('fieldset'), function () {
         for(i=0; i<field_types.length; i++) {
           $(this).find($('.field-' + field_types[i])).wrapAll("
");
          }
      });
    }
    align_objects();

    $('#all_languages').on('click', '.fallback-toggle input', function() {
      var $this = $(this),
          lang = $this.val(),
          $lang_label = $('#language-selector label[for=id_translation_show_' + lang + ']');

      if ($this.is(':checked')) {
        // remove from existing translations
        active_translations(undefined, lang);
        $lang_label.removeClass('translated');
      } else {
        // activate language
        active_translations(lang);
        $lang_label.addClass('translated');
      }

      show_hide_elements();
    });

    // update FeinCMS content blocks
    if (typeof(contentblock_init_handlers) != 'undefined') {
      contentblock_init_handlers.push(function() {
        show_hide_elements();

        var def_lang_fields = $('#main > div fieldset.module:not(.lang-processed) > .form-row').filter(function () {
          return $(this).attr('class').indexOf('_'+LOCALIZED_FIELDS.default_language) > 0;
        });
        // languages should be next to each in feincms contents
        // clear the left float on the primary language
        def_lang_fields.css('clear', 'left');

        // prevent multiple execution
        def_lang_fields.each(function () {
          $(this).closest('fieldset').addClass('lang-processed');
        });
      });
    }
  }

  function show_hide_elements() {
    var visible = visible_translations(),
        active = active_translations();

    $('#all_languages, #main').css('width', 460*(visible.length));

    // loop over fields and show/hide as appropriate
    $.each(LOCALIZED_FIELDS.languages, function() {
      var lang = this[0], name = this[1];
      if (lang == LOCALIZED_FIELDS.default_language) {return;}

     // hide elements where class name contains "_lang" (e.g. "_de")
      var $elements = $('fieldset.language.' + lang),
          $feincms_elements = $('div.item-content div.form-row[class*=_' + lang + ']');

      if ($.inArray(lang, visible) > -1) {
        // show this language's fieldset
        $elements.show();
        $feincms_elements.show();
        if ((active === false) || ($.inArray(lang, active) > -1)) {
          // no visibility checking or language exists - show all fields
          $elements.find('.form-row').show();
          $feincms_elements.css('visibility', 'visible');
          if ($.show_tinymce !== undefined) {$.show_tinymce();}
        } else {
          // language doesn't exist yet
          $elements.find('.form-row').hide();
          $feincms_elements.css('visibility', 'hidden');
        }
      } else {
        $elements.hide();
        $feincms_elements.hide();
      }
    });
  }

  function visible_translations(add, remove) {
    var translations = (Cookies.get('admin_translations') || LOCALIZED_FIELDS.default_language).split(/,/);
    if (add || remove) {
      if (add && ($.inArray(add, translations) == -1)) {
          translations.push(add);
      }
      if (remove) {
        translations = $.grep(translations, function(v) {return v != remove});
      }
      Cookies.set('admin_translations', translations.join(','), {path: '/'});
    }
    return translations;
  }

  function active_translations(add, remove) {
    if (!$translation_field.length) {
      return false;
    }
    var translations = $translation_field.val().replace(/,,/g, ',').replace(/^,/, '').replace(/,$/, '').split(/,/);

    if (add || remove) {
      if (add && ($.inArray(add, translations) == -1)) {
        translations.push(add);
        $('#language-selector label[for=id_translation_show_' + add + ']').addClass('translated');
      }
      if (remove) {
        translations = $.grep(translations, function(v) {return v != remove});
        $('#language-selector label[for=id_translation_show_' + remove + ']').removeClass('translated');
      }
      $translation_field.val(translations.join(','));
    }
    return translations;
  }
})(django.jQuery);
<commit_msg>feat: Reindent File<commit_after>(function ($) {
    var LOCALIZED_FIELDS, ADMIN_URL, $translation_field;

    $.holdReady(true);

    if (window.location.pathname.substr(-7) === 'change/') {
        // When inside Django /change/ url, step back two path increments
        ADMIN_URL = window.location.pathname + '../../localizedfields/';
    } else {
        // When inside Django /add/ url (or others without a pk), step back one path increment
        ADMIN_URL = window.location.pathname + '../localizedfields/';
    }

    $.getJSON(ADMIN_URL, function (data) {
    })
        .done(function (data) {
            LOCALIZED_FIELDS = data;
            $.holdReady(false);
        })
        .fail(function () {
            $.holdReady(false);
            console.error('API endpoint admin/localizedfields not found.');
        });

    $(function () {
        // Shortcut, if there isn't any change form
        if (!LOCALIZED_FIELDS || !$('body').hasClass('change-form')) {
            return;
        }

        $translation_field = $('div.field-translated_languages input');

        if (window.location.search.match(/lang=(\w{2})/)) {
            visible_translations([LOCALIZED_FIELDS.default_language, RegExp.$1]);
        }
        $('fieldset.language').wrapAll('
');

        // move default language to first position
        $('fieldset.language.' + LOCALIZED_FIELDS.default_language).prependTo($('#all_languages'));

        prepare_language_selector();
        if (prepare_visibility_fields()) {
            prepare_fallback_checkbox();
        }
    });

    function prepare_language_selector() {
        // add checkboxes to turn display of individual languages on and off
        var lang_selectors = '
' +
            '
' + LOCALIZED_FIELDS.translation_label + ': ',
            translations = visible_translations();

        $.each(LOCALIZED_FIELDS.languages, function () {
            var lang = this[0], name = this[1];

            // primary language can't be toggled
            if (lang == LOCALIZED_FIELDS.default_language) {
                return;
            }
            var show_fields_for_language = $.inArray(lang, translations) > -1;

            lang_selectors += '<input id="id_translation_show_' + lang + '" type="checkbox"  value="' + lang + '" ' +
                (show_fields_for_language ? 'checked="checked"' : '') + ' /> ' + '' +
                name + ' (' + lang + ')  ';

        });
        lang_selectors += '

';
        $('.breadcrumbs').after(lang_selectors);

        $('#language-selector').on('click', 'input', function () {
            if ($(this).is(':checked')) {
                visible_translations(this.value);
            } else {
                visible_translations(undefined, this.value);
            }
            show_hide_elements()
        });

        show_hide_elements()
    }

    function prepare_visibility_fields() {
        // add button to make all language versions visible
        $($('div[class*=field-visible][class*=field-box]')[0])  // before the first checkbox
            .before('
<input id="id_visible_all" type="checkbox"> '
                + 'Visible (all)
');
        $('#id_visible_all').change(function () {
            if ($(this).is(':checked')) {
                $('input[name^=visible]').attr('checked', false);
            } else {
                $('input[name^=visible]').attr('checked', true);
            }
        });

        $('input[name^=visible]').change(function () {
            // check or uncheck "all visible" checkbox when applicable
            if ($(this).is(':checked')) {
                if (!$('input[name^=visible]:not(:checked)').length) {
                    $('#id_visible_all').attr('checked', true);
                }
            } else {
                $('#id_visible_all').attr('checked', false);
            }
        }).change();

        return $('div.field-translated_languages').hide().length > 0;
    }

    function prepare_fallback_checkbox() {
        var fallback_toggle_label_color = $('fieldset.language h2').css('color'),
            fallback_title = LOCALIZED_FIELDS.fallback_label.replace(/\{language\}/, LOCALIZED_FIELDS.languages[0][1]),
            active = active_translations();

        $.each(LOCALIZED_FIELDS.languages, function () {
            var lang = this[0], name = this[1],
                fallback_active = false;
            fallback_toggle_id = 'fallback-toggle-' + lang;

            if (lang == LOCALIZED_FIELDS.default_language) {
                return;
            }

            if ($.inArray(lang, active) == -1) {
                fallback_active = true;
            } else {
                $('#language-selector label[for=id_translation_show_' + lang + ']').addClass('translated');
            }

            $fallback_toggle = $(
                '
' +
                '<input type="checkbox" id="' + fallback_toggle_id + '" ' + (fallback_active ? 'checked="checked"' : '') + ' value="' + lang +
                '"/> ' + fallback_title + '' +
                '
'
            );

            $('fieldset.language.' + lang + ' h2').append($fallback_toggle);

        });

        function align_objects() {
            var field_types = [
                'link',
                'key_fact',
                'document',
                'title',
                'tile',
                'text',
                'name',
                'button',
                'image',
                'cropping',
                'headline',
                'teaser',
                'black_overlay_text'
            ];

            for (i = 0; i < field_types.length; i++) {
                $('div[class*=' + field_types[i] + ']').addClass('field-' + field_types[i]);
            }

            $.each($('fieldset'), function () {
                for (i = 0; i < field_types.length; i++) {
                    $(this).find($('.field-' + field_types[i])).wrapAll("
");
                }
            });
        }

        align_objects();

        $('#all_languages').on('click', '.fallback-toggle input', function () {
            var $this = $(this),
                lang = $this.val(),
                $lang_label = $('#language-selector label[for=id_translation_show_' + lang + ']');

            if ($this.is(':checked')) {
                // remove from existing translations
                active_translations(undefined, lang);
                $lang_label.removeClass('translated');
            } else {
                // activate language
                active_translations(lang);
                $lang_label.addClass('translated');
            }

            show_hide_elements();
        });

        // update FeinCMS content blocks
        if (typeof(contentblock_init_handlers) != 'undefined') {
            contentblock_init_handlers.push(function () {
                show_hide_elements();

                var def_lang_fields = $('#main > div fieldset.module:not(.lang-processed) > .form-row').filter(function () {
                    return $(this).attr('class').indexOf('_' + LOCALIZED_FIELDS.default_language) > 0;
                });
                // languages should be next to each in feincms contents
                // clear the left float on the primary language
                def_lang_fields.css('clear', 'left');

                // prevent multiple execution
                def_lang_fields.each(function () {
                    $(this).closest('fieldset').addClass('lang-processed');
                });
            });
        }
    }

    function show_hide_elements() {
        var visible = visible_translations(),
            active = active_translations();

        $('#all_languages, #main').css('width', 460 * (visible.length));

        // loop over fields and show/hide as appropriate
        $.each(LOCALIZED_FIELDS.languages, function () {
            var lang = this[0], name = this[1];
            if (lang == LOCALIZED_FIELDS.default_language) {
                return;
            }

            // hide elements where class name contains "_lang" (e.g. "_de")
            var $elements = $('fieldset.language.' + lang),
                $feincms_elements = $('div.item-content div.form-row[class*=_' + lang + ']');

            if ($.inArray(lang, visible) > -1) {
                // show this language's fieldset
                $elements.show();
                $feincms_elements.show();
                if ((active === false) || ($.inArray(lang, active) > -1)) {
                    // no visibility checking or language exists - show all fields
                    $elements.find('.form-row').show();
                    $feincms_elements.css('visibility', 'visible');
                    if ($.show_tinymce !== undefined) {
                        $.show_tinymce();
                    }
                } else {
                    // language doesn't exist yet
                    $elements.find('.form-row').hide();
                    $feincms_elements.css('visibility', 'hidden');
                }
            } else {
                $elements.hide();
                $feincms_elements.hide();
            }
        });
    }

    function visible_translations(add, remove) {
        var translations = (Cookies.get('admin_translations') || LOCALIZED_FIELDS.default_language).split(/,/);
        if (add || remove) {
            if (add && ($.inArray(add, translations) == -1)) {
                translations.push(add);
            }
            if (remove) {
                translations = $.grep(translations, function (v) {
                    return v != remove
                });
            }
            Cookies.set('admin_translations', translations.join(','), {path: '/'});
        }
        return translations;
    }

    function active_translations(add, remove) {
        if (!$translation_field.length) {
            return false;
        }
        var translations = $translation_field.val().replace(/,,/g, ',').replace(/^,/, '').replace(/,$/, '').split(/,/);

        if (add || remove) {
            if (add && ($.inArray(add, translations) == -1)) {
                translations.push(add);
                $('#language-selector label[for=id_translation_show_' + add + ']').addClass('translated');
            }
            if (remove) {
                translations = $.grep(translations, function (v) {
                    return v != remove
                });
                $('#language-selector label[for=id_translation_show_' + remove + ']').removeClass('translated');
            }
            $translation_field.val(translations.join(','));
        }
        return translations;
    }
})(django.jQuery);
<|endoftext|>


<commit_before>var url = require('url');
var merge = require('merge');

function FluentInterface(server, o) {
	o = o || { debug: false };
	var debug = require('./debug')('interfake-fluent', o.debug);

	function forMethod(method, parent) {
		return function (originalPath) {
			var route;
			var routeDescriptor = {
				request: {
					url: originalPath,
					method: method
				}
			};

			if (!parent) {
				debug('Fluent setup called for', routeDescriptor.request.url);
				route = server.createRoute(routeDescriptor);
			} else {
				debug('Fluent setup called for', routeDescriptor.request.url, 'with parent', parent.request.url);
				route = parent.addAfterResponse(routeDescriptor);
			}

			var fluentInterface = {
				query: function (query) {
					route.setQueryStrings(query);
					return this;
				},
				status: function (status) {
					route.setStatusCode(status);
					return this;
				},
				body: function (body) {
					debug('Changing body of', route.simpleHash(), 'to', body);
					route.setResponseBody(body);
					return this;
				},
				delay: function(delay) {
					route.setResponseDelay(delay);
					return this;
				},
				responseHeaders: function (headers) {
					route.setResponseHeaders(headers);
					return this;
				},
				creates: {
					get: forMethod('get', route),
					put: forMethod('put', route),
					post: forMethod('post', route),
					delete: forMethod('delete', route)
				},
				modifies: {
					get: function (path) {
						route = server.routeMatching({
							method: 'get',
							url: path
						});
						return fluentInterface;
					}
				}
			};
			return fluentInterface;
		};
	}

	this.forMethod = forMethod;
}

module.exports = FluentInterface;<commit_msg>Added a note.<commit_after>var url = require('url');
var merge = require('merge');

function FluentInterface(server, o) {
	o = o || { debug: false };
	var debug = require('./debug')('interfake-fluent', o.debug);

	function forMethod(method, parent) {
		return function (originalPath) {
			var route;
			var routeDescriptor = {
				request: {
					url: originalPath,
					method: method
				}
			};

			if (!parent) {
				debug('Fluent setup called for', routeDescriptor.request.url);
				route = server.createRoute(routeDescriptor);
			} else {
				debug('Fluent setup called for', routeDescriptor.request.url, 'with parent', parent.request.url);
				route = parent.addAfterResponse(routeDescriptor);
			}

			var fluentInterface = {
				query: function (query) {
					route.setQueryStrings(query);
					return this;
				},
				status: function (status) {
					route.setStatusCode(status);
					return this;
				},
				body: function (body) {
					debug('Changing body of', route.simpleHash(), 'to', body);
					route.setResponseBody(body);
					return this;
				},
				delay: function(delay) {
					route.setResponseDelay(delay);
					return this;
				},
				responseHeaders: function (headers) {
					route.setResponseHeaders(headers);
					return this;
				},
				creates: {
					get: forMethod('get', route),
					put: forMethod('put', route),
					post: forMethod('post', route),
					delete: forMethod('delete', route)
				},
				modifies: {
					get: function (path) {
						// TODO This needs its own set of methods for merge rather than replace. At least, body does.
						route = server.routeMatching({
							method: 'get',
							url: path
						});
						return fluentInterface;
					}
				}
			};
			return fluentInterface;
		};
	}

	this.forMethod = forMethod;
}

module.exports = FluentInterface;<|endoftext|>


<commit_before>'use strict';

var node_path   = require('path');
var node_url    = require('url');
var fs          = require('fs-sync');
var pkg_helper  = require('../util/package');

exports.shorthands = {
    c: 'cwd',
};

exports.options = {
    cwd: {
        type: node_path,
        default: process.cwd(),
        info: 'specify the current working directory.'
    },

    force: {
        type: Boolean,
        info: 'if `true`, cortex will force to publishing existing module.'
    },

    tar: {
        type: node_path,
        info: 'the tar file to publish, if specified, option `cwd` will be overriden',
        setter: function(tar) {
            var remain = this.get('remain') || [];
            var cwd = this.get('cwd');
            var done = this.async();

            if(!tar){
                if(remain.length){
                    tar = remain[0];
                }
            }

            if(!tar){
                // `if options.tar` is not specified, `options.cwd` must be the root of a repo
                var dir = pkg_helper.repo_root(cwd);

                if(dir === null){
                    return done('directory "' + cwd + '" is not inside a project.');
                }

                return done(null);
            }

            if(!fs.isPathAbsolute(tar)){
                tar = node_path.resolve(cwd, tar);
            }

            if(!fs.isFile(tar)){
                return done('error `tar` parameter: `tar` does not exist or is not a file.');
            }

            done(null, tar);
        }
    },

    prerelease: {
        type: String,
        info: 'if `true`, cortex will publish the current package as a snapshot version.',

    }
};

exports.info = 'Publish a module to npm server';

exports.usage = [
    '{{name}} publish [options]',
    '{{name}} publish <tarfile> [options]'
];<commit_msg>#218: improve --cwd argument; adjust hint text<commit_after>'use strict';

var node_path   = require('path');
var node_url    = require('url');
var fs          = require('fs-sync');
var pkg_helper  = require('../util/package');

exports.shorthands = {
    c: 'cwd',
};

exports.options = {
    cwd: {
        type: node_path,
        default: process.cwd(),
        info: 'specify the current working directory.'
    },

    force: {
        type: Boolean,
        info: 'if `true`, cortex will force to publishing existing module.'
    },

    tar: {
        type: node_path,
        info: 'the tar file to publish, if specified, option `cwd` will be overriden',
        setter: function(tar) {
            var remain = this.get('remain') || [];
            var cwd = this.get('cwd');
            var done = this.async();

            if(!tar){
                if(remain.length){
                    tar = remain[0];
                }
            }

            if(!tar){
                // `if options.tar` is not specified, `options.cwd` must be the root of a repo
                var dir = pkg_helper.repo_root(cwd);

                if(dir === null){
                    return done('directory "' + cwd + '" is not inside a project.');
                }

                this.set('cwd', dir);

                return done(null);
            }

            if(!fs.isPathAbsolute(tar)){
                tar = node_path.resolve(cwd, tar);
            }

            if(!fs.isFile(tar)){
                return done('error `tar` parameter: tarball does not exist or is not a file.');
            }

            done(null, tar);
        }
    },

    prerelease: {
        type: String,
        info: 'if `true`, cortex will publish the current package as a snapshot version.'
    }
};

exports.info = 'Publish a module to npm server';

exports.usage = [
    '{{name}} publish [options]',
    '{{name}} publish <tarball> [options]'
];<|endoftext|>


<commit_before>'use strict';

/**
 * getRoute calculates or returns the stored route, based on the memory prepared
 * memory.routing
 *
 * @return {list} - result of `room.findRoute` base room added
 */
Creep.prototype.getRoute = function() {
  if (this.memory.routing.route) {
    return this.memory.routing.route;
  }

  let route = [];
  if (this.memory.base !== this.memory.routing.targetRoom) {
    route = this.room.findRoute(this.memory.base, this.memory.routing.targetRoom);
    if (route < 0) {
      route = this.room.findRoute(this.memory.base, this.memory.routing.targetRoom, true);
    }
  }

  if (!route.splice && (route < 0)) {
    throw new Error(`Creep.prototype.getRoute: route can not be spliced: ${JSON.stringify(route)}`);
  }
  route.splice(0, 0, {
    room: this.memory.base,
  });
  this.memory.routing.route = route;
  return route;
};

/**
 * getRoutePos returns the current position on the route
 *
 * @param {list} route - List of rooms to check against
 * @return {number} - returns the index of the current position in the given route
 */
Creep.prototype.getRoutePos = function(route) {
  this.memory.routing.routePos = this.memory.routing.routePos || 0;
  if (!route[this.memory.routing.routePos] || this.room.name !== route[this.memory.routing.routePos].room) {
    this.memory.routing.routePos = _.findIndex(route, (i) => i.room === this.room.name);
  }
  return this.memory.routing.routePos;
};

/**
 * getPathPos returns the current position on the path
 *
 * @param {list} path - Path to find the current position in
 * @return {number} - returns the index of the current position in the given route
 */
Creep.prototype.getPathPos = function(path) {
  let pathPos = this.memory.routing.pathPos || 0;
  const pos = path[pathPos];
  if (!pos || !this.pos.isEqualTo(pos.x, pos.y)) {
    pathPos = _.findIndex(path, (i) => i.x === this.pos.x && i.y === this.pos.y);
    this.memory.routing.pathPos = pathPos;
  }
  return pathPos;
};

/**
 * getDirections calculates the
 *  - forwardDirection: direction to next pos in path
 *  - backwardDirection: direction to previous pos in path
 *  - direction: which direction to go
 *  - pathOffset: offset for the path
 * based on the current path, pathPos and memory.routing.reverse
 *
 * @param {list} path - The path of the Creep
 * @param {number} pathPos - The current patPosition
 * @return {object} - forwardDirection, backwardDirection, direction, pathOffset
 **/
Creep.prototype.getDirections = function(path) {
  const pathPos = this.memory.routing.pathPos;
  if (pathPos < 0) {
    return {};
  }
  const pos = path[pathPos];
  const currentPos = new RoomPosition(pos.x, pos.y, this.room.name);
  let forwardDirection;
  let backwardDirection;
  let direction;

  if (pathPos + 1 < path.length) {
    const nextPos = path[pathPos + 1];
    forwardDirection = currentPos.getDirectionTo(nextPos.x, nextPos.y);
  }

  if (pathPos - 1 >= 0) {
    const nextPos = path[pathPos - 1];
    backwardDirection = currentPos.getDirectionTo(nextPos.x, nextPos.y);
  }

  let offset = 1;
  if (this.memory.routing.reverse) {
    offset = -1;
    direction = backwardDirection;
  } else {
    direction = forwardDirection;
  }

  return {
    forwardDirection: forwardDirection,
    backwardDirection: backwardDirection,
    direction: direction,
    pathOffset: offset,
    reverse: this.memory.routing.reverse,
  };
};

// TODO Maybe execute on creep creation
/**
 * prepareRoutingMemory Initializes the routing memory
 *
 * @return {list} - The path
 **/
Creep.prototype.prepareRoutingMemory = function() {
  const route = this.getRoute();
  const routePos = this.getRoutePos(route);
  const path = this.room.getPath(route, routePos, 'pathStart', this.memory.routing.targetId);
  this.getPathPos(path);
  return path;
};

/**
 * followPath follows that path for the creep and executes `action` when target
 * is reached
 *
 * @param {function} action - Action function to execute when target is reached
 * @return {boolean} - If the execution is successful
 */
Creep.prototype.followPath = function(action) {
  if (!this.memory.routing.targetId && this.room.name === this.memory.routing.targetRoom) {
    this.memory.routing.reached = true;
    return action(this);
  }

  const path = this.prepareRoutingMemory();
  let directions = this.getDirections(path);

  if (this.unit().preMove && this.unit().preMove(this, directions)) {
    return true;
  }

  // Recalculate the directions, if `preMove` changed `memory.routing.reversed`
  directions = this.getDirections(path);
  this.killPrevious(path);

  if (this.memory.routing.routePos === this.memory.routing.route.length - 1) {
    if (this.memory.routing.pathPos === path.length - 1 && !this.memory.routing.reverse) {
      this.memory.routing.reached = true;
      // TODO handle creeps with body part?
      this.memory.timeToTravel = CREEP_LIFE_TIME - this.ticksToLive;
      return action(this);
    }
  }

  this.buildRoad();

  return this.moveByPathMy(path, this.memory.routing.pathPos, directions);
};

/**
 * moveBackToPath moves to the first or last position based on
 * `memory.routing.reverse` to get to the best path position.
 *
 * @param {list} path - The path we want to get back to
 * @return {number} - Result of `creep.moveToMy`
 **/
Creep.prototype.moveBackToPath = function(path) {
  let pos;
  if (this.memory.routing.reverse) {
    pos = new RoomPosition(path[0].x, path[0].y, path[0].roomName);
  } else {
    const step = path.length > 1 ? path.length - 2 : path.length - 1;
    pos = new RoomPosition(path[step].x, path[step].y, path[step].roomName);
  }

  const moveToMyResult = this.moveToMy(pos, 0);
  if (!moveToMyResult) {
    this.log(`moveBackToPath moveToMy(${JSON.stringify(pos)}, 0); => ${moveToMyResult}`);
  }
  return moveToMyResult;
};

/**
 * validateDirections check if the directions object has at least one direction
 *
 * @param {object} directions - The object to check
 * @return {boolean} - If the object is valid
 **/
function validateDirections(directions) {
  return directions && (directions.forwardDirection || directions.backwardDirection);
}

/**
 * moveByPathMy follows the given path or gets back to the path
 *
 * @param {list} path - The path to follow
 * @param {number} pathPos - The current position on the path
 * @param {object} directions - Precalculated directions on the path
 * @return {boolean} true if a way was found to move the creep
 **/
Creep.prototype.moveByPathMy = function(path, pathPos, directions) {
  if (this.fatigue > 0) {
    return true;
  }

  if (pathPos < 0) {
    return this.moveBackToPath(path);
  }

  if (!validateDirections(directions)) {
    this.log(`moveByPathMy: Directions invalid pathPos: ${pathPos} path: ${path} directions: ${directions}`);
    return false;
  }

  const moveResponse = this.move(directions.direction);
  if (moveResponse !== OK && moveResponse !== ERR_NO_BODYPART) {
    // TODO carries sometimes run into this issues when switching between rooms
    if (!this.pos.isBorder()) {
      this.log(`moveByPathMy this.move(${directions.direction}) => ${moveResponse} DEBUG: reverse: ${this.memory.routing.reverse} pathPos: ${pathPos} directions: ${directions} path: ${path}`);
    }
  }
  this.memory.routing.pathPos = pathPos + directions.pathOffset;
  return true;
};

/**
 * checkForRoutingReached checks if current room and targetRoom matches
 * and set memory.routing.reached to true
 **/
Creep.prototype.checkForRoutingReached = function() {
  if (this.room.name === this.memory.routing.targetRoom) {
    this.memory.routing.reached = true;
  }
};
<commit_msg>BuildRoad: Only when following a calculated path<commit_after>'use strict';

/**
 * getRoute calculates or returns the stored route, based on the memory prepared
 * memory.routing
 *
 * @return {list} - result of `room.findRoute` base room added
 */
Creep.prototype.getRoute = function() {
  if (this.memory.routing.route) {
    return this.memory.routing.route;
  }

  let route = [];
  if (this.memory.base !== this.memory.routing.targetRoom) {
    route = this.room.findRoute(this.memory.base, this.memory.routing.targetRoom);
    if (route < 0) {
      route = this.room.findRoute(this.memory.base, this.memory.routing.targetRoom, true);
    }
  }

  if (!route.splice && (route < 0)) {
    throw new Error(`Creep.prototype.getRoute: route can not be spliced: ${JSON.stringify(route)}`);
  }
  route.splice(0, 0, {
    room: this.memory.base,
  });
  this.memory.routing.route = route;
  return route;
};

/**
 * getRoutePos returns the current position on the route
 *
 * @param {list} route - List of rooms to check against
 * @return {number} - returns the index of the current position in the given route
 */
Creep.prototype.getRoutePos = function(route) {
  this.memory.routing.routePos = this.memory.routing.routePos || 0;
  if (!route[this.memory.routing.routePos] || this.room.name !== route[this.memory.routing.routePos].room) {
    this.memory.routing.routePos = _.findIndex(route, (i) => i.room === this.room.name);
  }
  return this.memory.routing.routePos;
};

/**
 * getPathPos returns the current position on the path
 *
 * @param {list} path - Path to find the current position in
 * @return {number} - returns the index of the current position in the given route
 */
Creep.prototype.getPathPos = function(path) {
  let pathPos = this.memory.routing.pathPos || 0;
  const pos = path[pathPos];
  if (!pos || !this.pos.isEqualTo(pos.x, pos.y)) {
    pathPos = _.findIndex(path, (i) => i.x === this.pos.x && i.y === this.pos.y);
    this.memory.routing.pathPos = pathPos;
  }
  return pathPos;
};

/**
 * getDirections calculates the
 *  - forwardDirection: direction to next pos in path
 *  - backwardDirection: direction to previous pos in path
 *  - direction: which direction to go
 *  - pathOffset: offset for the path
 * based on the current path, pathPos and memory.routing.reverse
 *
 * @param {list} path - The path of the Creep
 * @param {number} pathPos - The current patPosition
 * @return {object} - forwardDirection, backwardDirection, direction, pathOffset
 **/
Creep.prototype.getDirections = function(path) {
  const pathPos = this.memory.routing.pathPos;
  if (pathPos < 0) {
    return {};
  }
  const pos = path[pathPos];
  const currentPos = new RoomPosition(pos.x, pos.y, this.room.name);
  let forwardDirection;
  let backwardDirection;
  let direction;

  if (pathPos + 1 < path.length) {
    const nextPos = path[pathPos + 1];
    forwardDirection = currentPos.getDirectionTo(nextPos.x, nextPos.y);
  }

  if (pathPos - 1 >= 0) {
    const nextPos = path[pathPos - 1];
    backwardDirection = currentPos.getDirectionTo(nextPos.x, nextPos.y);
  }

  let offset = 1;
  if (this.memory.routing.reverse) {
    offset = -1;
    direction = backwardDirection;
  } else {
    direction = forwardDirection;
  }

  return {
    forwardDirection: forwardDirection,
    backwardDirection: backwardDirection,
    direction: direction,
    pathOffset: offset,
    reverse: this.memory.routing.reverse,
  };
};

// TODO Maybe execute on creep creation
/**
 * prepareRoutingMemory Initializes the routing memory
 *
 * @return {list} - The path
 **/
Creep.prototype.prepareRoutingMemory = function() {
  const route = this.getRoute();
  const routePos = this.getRoutePos(route);
  const path = this.room.getPath(route, routePos, 'pathStart', this.memory.routing.targetId);
  this.getPathPos(path);
  return path;
};

/**
 * followPath follows that path for the creep and executes `action` when target
 * is reached
 *
 * @param {function} action - Action function to execute when target is reached
 * @return {boolean} - If the execution is successful
 */
Creep.prototype.followPath = function(action) {
  if (!this.memory.routing.targetId && this.room.name === this.memory.routing.targetRoom) {
    this.memory.routing.reached = true;
    return action(this);
  }

  const path = this.prepareRoutingMemory();
  let directions = this.getDirections(path);

  if (this.unit().preMove && this.unit().preMove(this, directions)) {
    return true;
  }

  // Recalculate the directions, if `preMove` changed `memory.routing.reversed`
  directions = this.getDirections(path);
  this.killPrevious(path);

  if (this.memory.routing.routePos === this.memory.routing.route.length - 1) {
    if (this.memory.routing.pathPos === path.length - 1 && !this.memory.routing.reverse) {
      this.memory.routing.reached = true;
      // TODO handle creeps with body part?
      this.memory.timeToTravel = CREEP_LIFE_TIME - this.ticksToLive;
      return action(this);
    }
  }

  return this.moveByPathMy(path, this.memory.routing.pathPos, directions);
};

/**
 * moveBackToPath moves to the first or last position based on
 * `memory.routing.reverse` to get to the best path position.
 *
 * @param {list} path - The path we want to get back to
 * @return {number} - Result of `creep.moveToMy`
 **/
Creep.prototype.moveBackToPath = function(path) {
  let pos;
  if (this.memory.routing.reverse) {
    pos = new RoomPosition(path[0].x, path[0].y, path[0].roomName);
  } else {
    const step = path.length > 1 ? path.length - 2 : path.length - 1;
    pos = new RoomPosition(path[step].x, path[step].y, path[step].roomName);
  }

  const moveToMyResult = this.moveToMy(pos, 0);
  if (!moveToMyResult) {
    this.log(`moveBackToPath moveToMy(${JSON.stringify(pos)}, 0); => ${moveToMyResult}`);
  }
  return moveToMyResult;
};

/**
 * validateDirections check if the directions object has at least one direction
 *
 * @param {object} directions - The object to check
 * @return {boolean} - If the object is valid
 **/
function validateDirections(directions) {
  return directions && (directions.forwardDirection || directions.backwardDirection);
}

/**
 * moveByPathMy follows the given path or gets back to the path
 *
 * @param {list} path - The path to follow
 * @param {number} pathPos - The current position on the path
 * @param {object} directions - Precalculated directions on the path
 * @return {boolean} true if a way was found to move the creep
 **/
Creep.prototype.moveByPathMy = function(path, pathPos, directions) {
  if (this.fatigue > 0) {
    return true;
  }

  if (pathPos < 0) {
    return this.moveBackToPath(path);
  }

  this.buildRoad();

  if (!validateDirections(directions)) {
    this.log(`moveByPathMy: Directions invalid pathPos: ${pathPos} path: ${path} directions: ${directions}`);
    return false;
  }

  const moveResponse = this.move(directions.direction);
  if (moveResponse !== OK && moveResponse !== ERR_NO_BODYPART) {
    // TODO carries sometimes run into this issues when switching between rooms
    if (!this.pos.isBorder()) {
      this.log(`moveByPathMy this.move(${directions.direction}) => ${moveResponse} DEBUG: reverse: ${this.memory.routing.reverse} pathPos: ${pathPos} directions: ${directions} path: ${path}`);
    }
  }
  this.memory.routing.pathPos = pathPos + directions.pathOffset;
  return true;
};

/**
 * checkForRoutingReached checks if current room and targetRoom matches
 * and set memory.routing.reached to true
 **/
Creep.prototype.checkForRoutingReached = function() {
  if (this.room.name === this.memory.routing.targetRoom) {
    this.memory.routing.reached = true;
  }
};
<|endoftext|>


<commit_before>/*jslint node: true */
"use strict";

/*
*
*
* Paths
* if extra paths are needed for the project, add them here.
*
*/
var paths = {
    scripts: {
        input: 'app/dev/assets/js/**/*.js',
        output: 'app/public/js'
    },
    styles: {
        input: 'app/dev/assets/styles/**/*.{scss,sass}',
        output: 'app/public/css'
    },
    html: {
        input: 'app/dev/**/*.html',
        output: 'app/public/'
    },
    images: {
        input: 'app/dev/assets/images/**/*',
        output: 'app/public/images'
    },
    extras: {
        input: ['app/dev/extras/*'],
        output: 'app/public/'
    }
};

/*
*
*
* Plugins
*
*
*/

//General Plugins
var gulp = require('gulp');
var gutil = require('gulp-util');
var rename = require('gulp-rename');
var concat = require('gulp-concat');
var clean = require('gulp-clean');
var flatten = require('gulp-flatten');

//Html Plugins
var htmlmin = require('gulp-htmlmin');

//Sass plugins
var sass = require('gulp-sass');
var minifycss = require('gulp-minify-css');
var autoprefixer = require('gulp-autoprefixer');
var bourbon = require('node-bourbon').includePaths;
var neat = require('node-neat').includePaths;

//Image Plugins
var imagemin = require('gulp-imagemin');
var pngquant = require('imagemin-pngquant');

//Javascript Plugins
var uglify = require('gulp-uglify');

//Browsersync
var browserSync = require("browser-sync").create();

//Linters
var scssLint = require("gulp-scss-lint");
var eslint = require('gulp-eslint');

/*
*
* CLEAN
* Removes the dist directory -
* cleans out all files that may no longer exist in dev
*/
gulp.task('clean', function () {
    return gulp.src('public/', {read: false})
        .pipe(clean());
});

/*
*
* MOVE FILES
*
*/
//Master move task
gulp.task('move', ['move-extras']);

//Extra files - robot.txt, etc
gulp.task('move-extras', function () {
    return gulp.src(paths.extras.input)
        .pipe(gulp.dest(paths.extras.output));
});

/*
*
* HTML
* Minifies html
*/
gulp.task('html', function () {
    return gulp.src(paths.html.input)
        .pipe(htmlmin({collapseWhitespace: true, removeComments: true}))
        .pipe(gulp.dest(paths.html.output));
});

/*
*
* SASS
*
*/
gulp.task('sass', function () {
    return gulp.src(paths.styles.input)
        .pipe(sass({
            includePaths: [].concat(bourbon, neat)
        }))
        .pipe(autoprefixer())
        .pipe(rename({ suffix: '.min' }))
        .pipe(minifycss())
        .pipe(gulp.dest(paths.styles.output))
        .pipe(browserSync.reload({
            stream: true
        }));
});

/*
*
* IMAGES
*
*/
gulp.task('imagemin', function () {
    return gulp.src(paths.images.input)
        .pipe(imagemin({
            progressive: true,
            svgoPlugins: [{removeViewBox: false}],
            use: [pngquant()]
        }))
        .pipe(gulp.dest(paths.images.output));
});

/*
*
* JAVASCRIPT
*
*/

// LINTER
gulp.task('eslint', function () {
	return gulp.src(paths.scripts.input)
			.pipe(eslint())
			.pipe(eslint.format())
			.pipe(eslint.failAfterError());
});

gulp.task('js', ['eslint'], function () {
    return gulp.src(paths.scripts.input)
        .pipe(concat('main.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest(paths.scripts.output));
});

/*
*
* BROWSERSYNC AND RELOAD
*
*/
gulp.task('browser-sync', function () {
    browserSync.init({});
});

gulp.task('browser-sync-reload', function () {
    browserSync.reload();
});

/*
*
* WATCH
*
*/
gulp.task('watch', function () {

    //Watch HTML files
    gulp.watch(paths.html.input, ['html', 'browser-sync-reload']);

    //Watch Sass files
    gulp.watch(paths.styles.input, ['sass']);

    //Watch JS files
    gulp.watch(paths.scripts.input, ['js']);

});

//Default Task. -
//Add all the tasks you would like to run on startup of the container here.
gulp.task('default', ['move', 'browser-sync', 'sass', 'imagemin', 'js', 'watch']);
<commit_msg>switched gulp-minify with gulp-clean in gulpfile<commit_after>/*jslint node: true */
"use strict";

/*
*
*
* Paths
* if extra paths are needed for the project, add them here.
*
*/
var paths = {
    scripts: {
        input: 'app/dev/assets/js/**/*.js',
        output: 'app/public/js'
    },
    styles: {
        input: 'app/dev/assets/styles/**/*.{scss,sass}',
        output: 'app/public/css'
    },
    html: {
        input: 'app/dev/**/*.html',
        output: 'app/public/'
    },
    images: {
        input: 'app/dev/assets/images/**/*',
        output: 'app/public/images'
    },
    extras: {
        input: ['app/dev/extras/*'],
        output: 'app/public/'
    }
};

/*
*
*
* Plugins
*
*
*/

//General Plugins
var gulp = require('gulp');
var gutil = require('gulp-util');
var rename = require('gulp-rename');
var concat = require('gulp-concat');
var clean = require('gulp-clean');
var flatten = require('gulp-flatten');

//Html Plugins
var htmlmin = require('gulp-htmlmin');

//Sass plugins
var sass = require('gulp-sass');
var minifycss = require('gulp-clean-css');
var autoprefixer = require('gulp-autoprefixer');
var bourbon = require('node-bourbon').includePaths;
var neat = require('node-neat').includePaths;

//Image Plugins
var imagemin = require('gulp-imagemin');
var pngquant = require('imagemin-pngquant');

//Javascript Plugins
var uglify = require('gulp-uglify');

//Browsersync
var browserSync = require("browser-sync").create();

//Linters
var scssLint = require("gulp-scss-lint");
var eslint = require('gulp-eslint');

/*
*
* CLEAN
* Removes the dist directory -
* cleans out all files that may no longer exist in dev
*/
gulp.task('clean', function () {
    return gulp.src('public/', {read: false})
        .pipe(clean());
});

/*
*
* MOVE FILES
*
*/
//Master move task
gulp.task('move', ['move-extras']);

//Extra files - robot.txt, etc
gulp.task('move-extras', function () {
    return gulp.src(paths.extras.input)
        .pipe(gulp.dest(paths.extras.output));
});

/*
*
* HTML
* Minifies html
*/
gulp.task('html', function () {
    return gulp.src(paths.html.input)
        .pipe(htmlmin({collapseWhitespace: true, removeComments: true}))
        .pipe(gulp.dest(paths.html.output));
});

/*
*
* SASS
*
*/
gulp.task('sass', function () {
    return gulp.src(paths.styles.input)
        .pipe(sass({
            includePaths: [].concat(bourbon, neat)
        }))
        .pipe(autoprefixer())
        .pipe(rename({ suffix: '.min' }))
        .pipe(minifycss())
        .pipe(gulp.dest(paths.styles.output))
        .pipe(browserSync.reload({
            stream: true
        }));
});

/*
*
* IMAGES
*
*/
gulp.task('imagemin', function () {
    return gulp.src(paths.images.input)
        .pipe(imagemin({
            progressive: true,
            svgoPlugins: [{removeViewBox: false}],
            use: [pngquant()]
        }))
        .pipe(gulp.dest(paths.images.output));
});

/*
*
* JAVASCRIPT
*
*/

// LINTER
gulp.task('eslint', function () {
	return gulp.src(paths.scripts.input)
			.pipe(eslint())
			.pipe(eslint.format())
			.pipe(eslint.failAfterError());
});

gulp.task('js', ['eslint'], function () {
    return gulp.src(paths.scripts.input)
        .pipe(concat('main.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest(paths.scripts.output));
});

/*
*
* BROWSERSYNC AND RELOAD
*
*/
gulp.task('browser-sync', function () {
    browserSync.init({});
});

gulp.task('browser-sync-reload', function () {
    browserSync.reload();
});

/*
*
* WATCH
*
*/
gulp.task('watch', function () {

    //Watch HTML files
    gulp.watch(paths.html.input, ['html', 'browser-sync-reload']);

    //Watch Sass files
    gulp.watch(paths.styles.input, ['sass']);

    //Watch JS files
    gulp.watch(paths.scripts.input, ['js']);

});

//Default Task. -
//Add all the tasks you would like to run on startup of the container here.
gulp.task('default', ['move', 'browser-sync', 'sass', 'imagemin', 'js', 'watch']);
<|endoftext|>


<commit_before>/* gpgme.js - Javascript integration for gpgme
 * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
 *
 * This file is part of GPGME.
 *
 * GPGME is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * GPGME is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
 * SPDX-License-Identifier: LGPL-2.1+
 *
 * Author(s):
 *     Maximilian Krambach <mkrambach@intevation.de>
 */

import { createMessage } from './Message';
import { createKey } from './Key';
import { isFingerprint } from './Helpers';
import { gpgme_error } from './Errors';

/**
 * This class offers access to the gnupg keyring
 */
export class GPGME_Keyring {

    /**
     * Queries Keys (all Keys or a subset) from gnupg.
     *
     * @param {String | Array<String>} pattern (optional) A pattern to
     * search for in userIds or KeyIds.
     * @param {Boolean} prepare_sync (optional) if set to true, most data
     * (with the exception of armored Key blocks) will be cached for the
     * Keys. This enables direct, synchronous use of these properties for
     * all keys. It does not check for changes on the backend. The cached
     * information can be updated with the {@link Key.refresh} method.
     * @param {Boolean} search (optional) retrieve Keys from external
     * servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup)
     * @returns {Promise<Array<GPGME_Key>>}
     * @static
     * @async
     */
    getKeys (pattern, prepare_sync=false, search=false){
        return new Promise(function (resolve, reject) {
            let msg = createMessage('keylist');
            if (pattern !== undefined && pattern !== null){
                msg.setParameter('keys', pattern);
            }
            msg.setParameter('sigs', true);
            if (search === true){
                msg.setParameter('locate', true);
            }
            msg.post().then(function (result){
                let resultset = [];
                if (result.keys.length === 0){
                    resolve([]);
                } else {
                    let secondrequest;
                    if (prepare_sync === true) {
                        secondrequest = function () {
                            let msg2 = createMessage('keylist');
                            msg2.setParameter('keys', pattern);
                            msg2.setParameter('secret', true);
                            return msg2.post();
                        };
                    } else {
                        secondrequest = function () {
                            return Promise.resolve(true);
                        };
                    }
                    secondrequest().then(function (answer) {
                        for (let i=0; i < result.keys.length; i++){
                            if (prepare_sync === true){
                                if (answer && answer.keys) {
                                    for (let j=0;
                                        j < answer.keys.length; j++ ){
                                        const a = answer.keys[j];
                                        const b = result.keys[i];
                                        if (
                                            a.fingerprint === b.fingerprint
                                        ) {
                                            if (a.secret === true){
                                                b.hasSecret = true;
                                            } else {
                                                b.hasSecret = false;
                                            }
                                            break;
                                        }
                                    }
                                }
                            }
                            let k = createKey(result.keys[i].fingerprint,
                                !prepare_sync, result.keys[i]);
                            resultset.push(k);
                        }
                        resolve(resultset);
                    }, function (error){
                        reject(error);
                    });
                }
            });
        });
    }

    /**
     * @typedef {Object} exportResult The result of a getKeysArmored
     * operation.
     * @property {String} armored The public Key(s) as armored block. Note
     * that the result is one armored block, and not a block per key.
     * @property {Array<String>} secret_fprs (optional) list of
     * fingerprints for those Keys that also have a secret Key available in
     * gnupg. The secret key will not be exported, but the fingerprint can
     * be used in operations needing a secret key.
     */

    /**
     * Fetches the armored public Key blocks for all Keys matching the
     * pattern (if no pattern is given, fetches all keys known to gnupg).
     * @param {String|Array<String>} pattern (optional) The Pattern to
     * search for
     * @param {Boolean} with_secret_fpr (optional) also return a list of
     * fingerprints for the keys that have a secret key available
     * @returns {Promise<exportResult|GPGME_Error>} Object containing the
     * armored Key(s) and additional information.
     * @static
     * @async
     */
    getKeysArmored (pattern, with_secret_fpr) {
        return new Promise(function (resolve, reject) {
            let msg = createMessage('export');
            msg.setParameter('armor', true);
            if (with_secret_fpr === true) {
                msg.setParameter('with-sec-fprs', true);
            }
            if (pattern !== undefined && pattern !== null){
                msg.setParameter('keys', pattern);
            }
            msg.post().then(function (answer){
                const result = { armored: answer.data };
                if (with_secret_fpr === true
                    && answer.hasOwnProperty('sec-fprs')
                ) {
                    result.secret_fprs = answer['sec-fprs'];
                }
                resolve(result);
            }, function (error){
                reject(error);
            });
        });
    }

    /**
     * Returns the Key used by default in gnupg.
     * (a.k.a. 'primary Key or 'main key').
     * It looks up the gpg configuration if set, or the first key that
     * contains a secret key.
     *
     * @returns {Promise<GPGME_Key|GPGME_Error>}
     * @async
     * @static
     */
    getDefaultKey (prepare_sync = false) {
        let me = this;
        return new Promise(function (resolve, reject){
            let msg = createMessage('config_opt');
            msg.setParameter('component', 'gpg');
            msg.setParameter('option', 'default-key');
            msg.post().then(function (resp){
                if (resp.option !== undefined
                    && resp.option.hasOwnProperty('value')
                    && resp.option.value.length === 1
                    && resp.option.value[0].hasOwnProperty('string')
                    && typeof (resp.option.value[0].string) === 'string'){
                    me.getKeys(resp.option.value[0].string, true).then(
                        function (keys){
                            if (keys.length === 1){
                                resolve(keys[0]);
                            } else {
                                reject(gpgme_error('KEY_NO_DEFAULT'));
                            }
                        }, function (error){
                            reject(error);
                        });
                } else {
                    let msg = createMessage('keylist');
                    msg.setParameter('secret', true);
                    msg.post().then(function (result){
                        if (result.keys.length === 0){
                            reject(gpgme_error('KEY_NO_DEFAULT'));
                        } else {
                            for (let i=0; i< result.keys.length; i++ ) {
                                if (result.keys[i].invalid === false) {
                                    let k = createKey(
                                        result.keys[i].fingerprint,
                                        !prepare_sync,
                                        result.keys[i]);
                                    resolve(k);
                                    break;
                                } else if (i === result.keys.length - 1){
                                    reject(gpgme_error('KEY_NO_DEFAULT'));
                                }
                            }
                        }
                    }, function (error){
                        reject(error);
                    });
                }
            }, function (error){
                reject(error);
            });
        });
    }

    /**
     * @typedef {Object} importResult The result of a Key update
     * @property {Object} summary Numerical summary of the result. See the
     * feedbackValues variable for available Keys values and the gnupg
     * documentation.
     * https://www.gnupg.org/documentation/manuals/gpgme/Importing-Keys.html
     * for details on their meaning.
     * @property {Array<importedKeyResult>} Keys Array of Object containing
     * GPGME_Keys with additional import information
     *
     */

    /**
     * @typedef {Object} importedKeyResult
     * @property {GPGME_Key} key The resulting key
     * @property {String} status:
     *  'nochange' if the Key was not changed,
     *  'newkey' if the Key was imported in gpg, and did not exist
     *    previously,
     *  'change' if the key existed, but details were updated. For details,
     *    Key.changes is available.
     * @property {Boolean} changes.userId Changes in userIds
     * @property {Boolean} changes.signature Changes in signatures
     * @property {Boolean} changes.subkey Changes in subkeys
     */

    /**
     * Import an armored Key block into gnupg. Note that this currently
     * will not succeed on private Key blocks.
     * @param {String} armored Armored Key block of the Key(s) to be
     * imported into gnupg
     * @param {Boolean} prepare_sync prepare the keys for synched use
     * (see {@link getKeys}).
     * @returns {Promise<importResult>} A summary and Keys considered.
     * @async
     * @static
     */
    importKey (armored, prepare_sync) {
        let feedbackValues = ['considered', 'no_user_id', 'imported',
            'imported_rsa', 'unchanged', 'new_user_ids', 'new_sub_keys',
            'new_signatures', 'new_revocations', 'secret_read',
            'secret_imported', 'secret_unchanged', 'skipped_new_keys',
            'not_imported', 'skipped_v3_keys'];
        if (!armored || typeof (armored) !== 'string'){
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        let me = this;
        return new Promise(function (resolve, reject){
            let msg = createMessage('import');
            msg.setParameter('data', armored);
            msg.post().then(function (response){
                let infos = {};
                let fprs = [];
                let summary = {};
                for (let i=0; i < feedbackValues.length; i++ ){
                    summary[feedbackValues[i]] =
                        response.result[feedbackValues[i]];
                }
                if (!response.result.hasOwnProperty('imports') ||
                    response.result.imports.length === 0
                ){
                    resolve({ Keys:[],summary: summary });
                    return;
                }
                for (let res=0; res<response.result.imports.length; res++){
                    let result = response.result.imports[res];
                    let status = '';
                    if (result.status === 0){
                        status = 'nochange';
                    } else if ((result.status & 1) === 1){
                        status = 'newkey';
                    } else {
                        status = 'change';
                    }
                    let changes = {};
                    changes.userId = (result.status & 2) === 2;
                    changes.signature = (result.status & 4) === 4;
                    changes.subkey = (result.status & 8) === 8;
                    // 16 new secret key: not implemented

                    fprs.push(result.fingerprint);
                    infos[result.fingerprint] = {
                        changes: changes,
                        status: status
                    };
                }
                let resultset = [];
                if (prepare_sync === true){
                    me.getKeys(fprs, true).then(function (result){
                        for (let i=0; i < result.length; i++) {
                            resultset.push({
                                key: result[i],
                                changes:
                                    infos[result[i].fingerprint].changes,
                                status: infos[result[i].fingerprint].status
                            });
                        }
                        resolve({ Keys:resultset,summary: summary });
                    }, function (error){
                        reject(error);
                    });
                } else {
                    for (let i=0; i < fprs.length; i++) {
                        resultset.push({
                            key: createKey(fprs[i]),
                            changes: infos[fprs[i]].changes,
                            status: infos[fprs[i]].status
                        });
                    }
                    resolve({ Keys:resultset,summary:summary });
                }

            }, function (error){
                reject(error);
            });

        });

    }

    /**
     * Convenience function for deleting a Key. See {@link Key.delete} for
     * further information about the return values.
     * @param {String} fingerprint
     * @returns {Promise<Boolean|GPGME_Error>}
     * @async
     * @static
     */
    deleteKey (fingerprint){
        if (isFingerprint(fingerprint) === true) {
            let key = createKey(fingerprint);
            return key.delete();
        } else {
            return Promise.reject(gpgme_error('KEY_INVALID'));
        }
    }

    /**
     * Generates a new Key pair directly in gpg, and returns a GPGME_Key
     * representing that Key. Please note that due to security concerns,
     * secret Keys can not be deleted or exported from inside gpgme.js.
     *
     * @param {String} userId The user Id, e.g. 'Foo Bar <foo@bar.baz>'
     * @param {String} algo (optional) algorithm (and optionally key size)
     * to be used. See {@link supportedKeyAlgos} below for supported
     * values.
     * @param {Date} expires (optional) Expiration date. If not set,
     * expiration will be set to 'never'
     *
     * @return {Promise<Key|GPGME_Error>}
     * @async
     */
    generateKey (userId, algo = 'default', expires){
        if (
            typeof (userId) !== 'string' ||
            // eslint-disable-next-line no-use-before-define
            supportedKeyAlgos.indexOf(algo) < 0 ||
            (expires && !(expires instanceof Date))
        ){
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        let me = this;
        return new Promise(function (resolve, reject){
            let msg = createMessage('createkey');
            msg.setParameter('userid', userId);
            msg.setParameter('algo', algo );
            if (expires){
                msg.setParameter('expires',
                    Math.floor(expires.valueOf()/1000));
            } else {
                msg.setParameter('expires', 0);
            }
            msg.post().then(function (response){
                me.getKeys(response.fingerprint, true).then(
                    // TODO prepare_sync?
                    function (result){
                        resolve(result);
                    }, function (error){
                        reject(error);
                    });
            }, function (error) {
                reject(error);
            });
        });
    }
}

/**
 * List of algorithms supported for key generation. Please refer to the gnupg
 * documentation for details
 */
const supportedKeyAlgos = [
    'default',
    'rsa', 'rsa2048', 'rsa3072', 'rsa4096',
    'dsa', 'dsa2048', 'dsa3072', 'dsa4096',
    'elg', 'elg2048', 'elg3072', 'elg4096',
    'ed25519',
    'cv25519',
    'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1',
    'NIST P-256', 'NIST P-384', 'NIST P-521'
];<commit_msg>js: set expiry date on generateKey<commit_after>/* gpgme.js - Javascript integration for gpgme
 * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
 *
 * This file is part of GPGME.
 *
 * GPGME is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * GPGME is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
 * SPDX-License-Identifier: LGPL-2.1+
 *
 * Author(s):
 *     Maximilian Krambach <mkrambach@intevation.de>
 */

import { createMessage } from './Message';
import { createKey } from './Key';
import { isFingerprint } from './Helpers';
import { gpgme_error } from './Errors';

/**
 * This class offers access to the gnupg keyring
 */
export class GPGME_Keyring {

    /**
     * Queries Keys (all Keys or a subset) from gnupg.
     *
     * @param {String | Array<String>} pattern (optional) A pattern to
     * search for in userIds or KeyIds.
     * @param {Boolean} prepare_sync (optional) if set to true, most data
     * (with the exception of armored Key blocks) will be cached for the
     * Keys. This enables direct, synchronous use of these properties for
     * all keys. It does not check for changes on the backend. The cached
     * information can be updated with the {@link Key.refresh} method.
     * @param {Boolean} search (optional) retrieve Keys from external
     * servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup)
     * @returns {Promise<Array<GPGME_Key>>}
     * @static
     * @async
     */
    getKeys (pattern, prepare_sync=false, search=false){
        return new Promise(function (resolve, reject) {
            let msg = createMessage('keylist');
            if (pattern !== undefined && pattern !== null){
                msg.setParameter('keys', pattern);
            }
            msg.setParameter('sigs', true);
            if (search === true){
                msg.setParameter('locate', true);
            }
            msg.post().then(function (result){
                let resultset = [];
                if (result.keys.length === 0){
                    resolve([]);
                } else {
                    let secondrequest;
                    if (prepare_sync === true) {
                        secondrequest = function () {
                            let msg2 = createMessage('keylist');
                            msg2.setParameter('keys', pattern);
                            msg2.setParameter('secret', true);
                            return msg2.post();
                        };
                    } else {
                        secondrequest = function () {
                            return Promise.resolve(true);
                        };
                    }
                    secondrequest().then(function (answer) {
                        for (let i=0; i < result.keys.length; i++){
                            if (prepare_sync === true){
                                if (answer && answer.keys) {
                                    for (let j=0;
                                        j < answer.keys.length; j++ ){
                                        const a = answer.keys[j];
                                        const b = result.keys[i];
                                        if (
                                            a.fingerprint === b.fingerprint
                                        ) {
                                            if (a.secret === true){
                                                b.hasSecret = true;
                                            } else {
                                                b.hasSecret = false;
                                            }
                                            break;
                                        }
                                    }
                                }
                            }
                            let k = createKey(result.keys[i].fingerprint,
                                !prepare_sync, result.keys[i]);
                            resultset.push(k);
                        }
                        resolve(resultset);
                    }, function (error){
                        reject(error);
                    });
                }
            });
        });
    }

    /**
     * @typedef {Object} exportResult The result of a getKeysArmored
     * operation.
     * @property {String} armored The public Key(s) as armored block. Note
     * that the result is one armored block, and not a block per key.
     * @property {Array<String>} secret_fprs (optional) list of
     * fingerprints for those Keys that also have a secret Key available in
     * gnupg. The secret key will not be exported, but the fingerprint can
     * be used in operations needing a secret key.
     */

    /**
     * Fetches the armored public Key blocks for all Keys matching the
     * pattern (if no pattern is given, fetches all keys known to gnupg).
     * @param {String|Array<String>} pattern (optional) The Pattern to
     * search for
     * @param {Boolean} with_secret_fpr (optional) also return a list of
     * fingerprints for the keys that have a secret key available
     * @returns {Promise<exportResult|GPGME_Error>} Object containing the
     * armored Key(s) and additional information.
     * @static
     * @async
     */
    getKeysArmored (pattern, with_secret_fpr) {
        return new Promise(function (resolve, reject) {
            let msg = createMessage('export');
            msg.setParameter('armor', true);
            if (with_secret_fpr === true) {
                msg.setParameter('with-sec-fprs', true);
            }
            if (pattern !== undefined && pattern !== null){
                msg.setParameter('keys', pattern);
            }
            msg.post().then(function (answer){
                const result = { armored: answer.data };
                if (with_secret_fpr === true
                    && answer.hasOwnProperty('sec-fprs')
                ) {
                    result.secret_fprs = answer['sec-fprs'];
                }
                resolve(result);
            }, function (error){
                reject(error);
            });
        });
    }

    /**
     * Returns the Key used by default in gnupg.
     * (a.k.a. 'primary Key or 'main key').
     * It looks up the gpg configuration if set, or the first key that
     * contains a secret key.
     *
     * @returns {Promise<GPGME_Key|GPGME_Error>}
     * @async
     * @static
     */
    getDefaultKey (prepare_sync = false) {
        let me = this;
        return new Promise(function (resolve, reject){
            let msg = createMessage('config_opt');
            msg.setParameter('component', 'gpg');
            msg.setParameter('option', 'default-key');
            msg.post().then(function (resp){
                if (resp.option !== undefined
                    && resp.option.hasOwnProperty('value')
                    && resp.option.value.length === 1
                    && resp.option.value[0].hasOwnProperty('string')
                    && typeof (resp.option.value[0].string) === 'string'){
                    me.getKeys(resp.option.value[0].string, true).then(
                        function (keys){
                            if (keys.length === 1){
                                resolve(keys[0]);
                            } else {
                                reject(gpgme_error('KEY_NO_DEFAULT'));
                            }
                        }, function (error){
                            reject(error);
                        });
                } else {
                    let msg = createMessage('keylist');
                    msg.setParameter('secret', true);
                    msg.post().then(function (result){
                        if (result.keys.length === 0){
                            reject(gpgme_error('KEY_NO_DEFAULT'));
                        } else {
                            for (let i=0; i< result.keys.length; i++ ) {
                                if (result.keys[i].invalid === false) {
                                    let k = createKey(
                                        result.keys[i].fingerprint,
                                        !prepare_sync,
                                        result.keys[i]);
                                    resolve(k);
                                    break;
                                } else if (i === result.keys.length - 1){
                                    reject(gpgme_error('KEY_NO_DEFAULT'));
                                }
                            }
                        }
                    }, function (error){
                        reject(error);
                    });
                }
            }, function (error){
                reject(error);
            });
        });
    }

    /**
     * @typedef {Object} importResult The result of a Key update
     * @property {Object} summary Numerical summary of the result. See the
     * feedbackValues variable for available Keys values and the gnupg
     * documentation.
     * https://www.gnupg.org/documentation/manuals/gpgme/Importing-Keys.html
     * for details on their meaning.
     * @property {Array<importedKeyResult>} Keys Array of Object containing
     * GPGME_Keys with additional import information
     *
     */

    /**
     * @typedef {Object} importedKeyResult
     * @property {GPGME_Key} key The resulting key
     * @property {String} status:
     *  'nochange' if the Key was not changed,
     *  'newkey' if the Key was imported in gpg, and did not exist
     *    previously,
     *  'change' if the key existed, but details were updated. For details,
     *    Key.changes is available.
     * @property {Boolean} changes.userId Changes in userIds
     * @property {Boolean} changes.signature Changes in signatures
     * @property {Boolean} changes.subkey Changes in subkeys
     */

    /**
     * Import an armored Key block into gnupg. Note that this currently
     * will not succeed on private Key blocks.
     * @param {String} armored Armored Key block of the Key(s) to be
     * imported into gnupg
     * @param {Boolean} prepare_sync prepare the keys for synched use
     * (see {@link getKeys}).
     * @returns {Promise<importResult>} A summary and Keys considered.
     * @async
     * @static
     */
    importKey (armored, prepare_sync) {
        let feedbackValues = ['considered', 'no_user_id', 'imported',
            'imported_rsa', 'unchanged', 'new_user_ids', 'new_sub_keys',
            'new_signatures', 'new_revocations', 'secret_read',
            'secret_imported', 'secret_unchanged', 'skipped_new_keys',
            'not_imported', 'skipped_v3_keys'];
        if (!armored || typeof (armored) !== 'string'){
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        let me = this;
        return new Promise(function (resolve, reject){
            let msg = createMessage('import');
            msg.setParameter('data', armored);
            msg.post().then(function (response){
                let infos = {};
                let fprs = [];
                let summary = {};
                for (let i=0; i < feedbackValues.length; i++ ){
                    summary[feedbackValues[i]] =
                        response.result[feedbackValues[i]];
                }
                if (!response.result.hasOwnProperty('imports') ||
                    response.result.imports.length === 0
                ){
                    resolve({ Keys:[],summary: summary });
                    return;
                }
                for (let res=0; res<response.result.imports.length; res++){
                    let result = response.result.imports[res];
                    let status = '';
                    if (result.status === 0){
                        status = 'nochange';
                    } else if ((result.status & 1) === 1){
                        status = 'newkey';
                    } else {
                        status = 'change';
                    }
                    let changes = {};
                    changes.userId = (result.status & 2) === 2;
                    changes.signature = (result.status & 4) === 4;
                    changes.subkey = (result.status & 8) === 8;
                    // 16 new secret key: not implemented

                    fprs.push(result.fingerprint);
                    infos[result.fingerprint] = {
                        changes: changes,
                        status: status
                    };
                }
                let resultset = [];
                if (prepare_sync === true){
                    me.getKeys(fprs, true).then(function (result){
                        for (let i=0; i < result.length; i++) {
                            resultset.push({
                                key: result[i],
                                changes:
                                    infos[result[i].fingerprint].changes,
                                status: infos[result[i].fingerprint].status
                            });
                        }
                        resolve({ Keys:resultset,summary: summary });
                    }, function (error){
                        reject(error);
                    });
                } else {
                    for (let i=0; i < fprs.length; i++) {
                        resultset.push({
                            key: createKey(fprs[i]),
                            changes: infos[fprs[i]].changes,
                            status: infos[fprs[i]].status
                        });
                    }
                    resolve({ Keys:resultset,summary:summary });
                }

            }, function (error){
                reject(error);
            });

        });

    }

    /**
     * Convenience function for deleting a Key. See {@link Key.delete} for
     * further information about the return values.
     * @param {String} fingerprint
     * @returns {Promise<Boolean|GPGME_Error>}
     * @async
     * @static
     */
    deleteKey (fingerprint){
        if (isFingerprint(fingerprint) === true) {
            let key = createKey(fingerprint);
            return key.delete();
        } else {
            return Promise.reject(gpgme_error('KEY_INVALID'));
        }
    }

    /**
     * Generates a new Key pair directly in gpg, and returns a GPGME_Key
     * representing that Key. Please note that due to security concerns,
     * secret Keys can not be deleted or exported from inside gpgme.js.
     *
     * @param {String} userId The user Id, e.g. 'Foo Bar <foo@bar.baz>'
     * @param {String} algo (optional) algorithm (and optionally key size)
     * to be used. See {@link supportedKeyAlgos} below for supported
     * values.
     * @param {Date} expires (optional) Expiration date. If not set,
     * expiration will be set to 'never'
     *
     * @return {Promise<Key|GPGME_Error>}
     * @async
     */
    generateKey (userId, algo = 'default', expires){
        if (
            typeof (userId) !== 'string' ||
            // eslint-disable-next-line no-use-before-define
            supportedKeyAlgos.indexOf(algo) < 0 ||
            (expires && !(expires instanceof Date))
        ){
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        let me = this;
        return new Promise(function (resolve, reject){
            let msg = createMessage('createkey');
            msg.setParameter('userid', userId);
            msg.setParameter('algo', algo );
            if (expires){
                const now = new Date();
                msg.setParameter('expires',
                    Math.floor((expires - now) /1000));
            } else {
                msg.setParameter('expires', 0);
            }
            msg.post().then(function (response){
                me.getKeys(response.fingerprint, true).then(
                    // TODO prepare_sync?
                    function (result){
                        resolve(result);
                    }, function (error){
                        reject(error);
                    });
            }, function (error) {
                reject(error);
            });
        });
    }
}

/**
 * List of algorithms supported for key generation. Please refer to the gnupg
 * documentation for details
 */
const supportedKeyAlgos = [
    'default',
    'rsa', 'rsa2048', 'rsa3072', 'rsa4096',
    'dsa', 'dsa2048', 'dsa3072', 'dsa4096',
    'elg', 'elg2048', 'elg3072', 'elg4096',
    'ed25519',
    'cv25519',
    'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1',
    'NIST P-256', 'NIST P-384', 'NIST P-521'
];<|endoftext|>