<commit_before>exports.run = async(client, msg, args) => {
  const ms = require('ms')
  /**
  * @var {target} @type {Object} user-Object to mute
  * @var {dole} @type {Object} role-Object for mutes
  * @var {reason} @type {String} Punishment-Reason
  * @var {duration} @type {String} Punishment-Duration
  */
  const target = msg.mentions.users.first();
  const role = msg.guild.roles.find('name', 'may-muted');
  const reason = msg.content.split(' ').slice(3).join(' ');
  const duration = msg.content.split(' ')[2];
  const mayLog = msg.guild.channels.find('name', 'may-log');

  let Freason;
  if (!reason) {
    Freason = 'None'
  } else {
    Freason = reason;
  }

  let Fdur;
  if (duration === 'permant') {
    Fdur = 'permant'
  } else {
    Fdur = duration;
  }

  let finallTime;
  if (Fdur === 'permant') {
    finallTime = 'permanent'
  } else {
    finallTime = ms(ms(Fdur), {long : true});
  }

  if (!target) {
    return msg.reply('Please mention a user for the punishment')
  }

  if (!mayLog) {
    embedMessage.advanced({
      author    : {
        name    : `Muted ${target.username}`,
        pic     : client.user.avatarURL
      },
      desc      : `\`\`\`\n
Target   : ${target.username} [${target.id}]\n\
Moderator: ${msg.author.username} [${msg.author.id}]\n\
Duration : ${ms(ms(finallTime))}\n\
Reason   : ${Freason}
\`\`\``,
      color     : 0x6580b0
    })

  } else if (mayLog) {
    const embed = require('')
  }
};

exports.help = {
    category   : 'moderation',
    usage      : '[time:time or permant] [reason:optional]',
    description: 'I will be sure to shut their mouth',
    detail     : 'When using mute the bot will mute the selected user, for the time you choose(optional)',
    botPerm    : ['SEND_MESSAGES', 'MANAGE_ROLES'],
    authorPerm : ['SEND_MESSAGES', 'MUTE_MEMBERS'],
    alias      : [
        null
    ]
};
<commit_msg>Message if the channel found<commit_after>exports.run = async(client, msg, args) => {
  const ms = require('ms')
  /**
  * @var {target} @type {Object} user-Object to mute
  * @var {dole} @type {Object} role-Object for mutes
  * @var {reason} @type {String} Punishment-Reason
  * @var {duration} @type {String} Punishment-Duration
  */
  const target = msg.mentions.users.first();
  const role = msg.guild.roles.find('name', 'may-muted');
  const reason = msg.content.split(' ').slice(3).join(' ');
  const duration = msg.content.split(' ')[2];
  const mayLog = msg.guild.channels.find('name', 'may-log');

  let Freason;
  if (!reason) {
    Freason = 'None'
  } else {
    Freason = reason;
  }

  let Fdur;
  if (!duration) {
    Fdur = 'permanent'
  } else if (duration !== 'permanent'){
    Fdur = duration;
  }

  let finallTime;
  if (Fdur === 'permanent') {
    finallTime = 'permanent'
  } else {
    finallTime = ms(ms(Fdur), {long : true})
  }

  if (!target) {
    return msg.reply('Please mention a user for the punishment')
  }

  if (!mayLog) {
    embedMessage.advanced({
      author    : {
        name    : `Muted ${target.username}`,
        pic     : client.user.avatarURL
      },
      desc      : `\`\`\`\n
Target   : ${target.username} [${target.id}]\n\
Moderator: ${msg.author.username} [${msg.author.id}]\n\
Duration : ${finallTime}\n\
Reason   : ${Freason}
\`\`\``,
    })

  } else if (mayLog) {
    const embed = new Discord.RichEmbed()
    .setAuthor(`Muted ${target.username}`, client.user.avatarURL)
    .setDescription(`\`\`\`\n
Target   : ${target.username} [${target.id}]\n\
Moderator: ${msg.author.username} [${msg.author.id}]\n\
Duration : ${finallTime}\n\
Reason   : ${Freason}
\`\`\``)
    .setColor(0x6580b0)
    mayLog.send({embed})
  }
};

exports.help = {
    category   : 'moderation',
    usage      : '[time:time or permant] [reason:optional]',
    description: 'I will be sure to shut their mouth',
    detail     : 'When using mute the bot will mute the selected user, for the time you choose(optional)',
    botPerm    : ['SEND_MESSAGES', 'MANAGE_ROLES'],
    authorPerm : ['SEND_MESSAGES', 'MUTE_MEMBERS'],
    alias      : [
        null
    ]
};
<|endoftext|>


<commit_before>const { determineRepoUpgrades } = require('./determine');
const { branchifyUpgrades } = require('./branchify');

module.exports = {
  determineUpdates,
};

async function determineUpdates(input) {
  let config = { ...input };
  logger.debug('determineUpdates()');
  logger.trace({ config });
  config = await determineRepoUpgrades(config);
  platform.ensureIssueClosing('Action Required: Fix Renovate Configuration');
  config = branchifyUpgrades(config);
  logger.debug('Finished determining upgrades');
  return config;
}
<commit_msg>fix: await platform.ensureIssueClosing<commit_after>const { determineRepoUpgrades } = require('./determine');
const { branchifyUpgrades } = require('./branchify');

module.exports = {
  determineUpdates,
};

async function determineUpdates(input) {
  let config = { ...input };
  logger.debug('determineUpdates()');
  logger.trace({ config });
  config = await determineRepoUpgrades(config);
  await platform.ensureIssueClosing(
    'Action Required: Fix Renovate Configuration'
  );
  config = branchifyUpgrades(config);
  logger.debug('Finished determining upgrades');
  return config;
}
<|endoftext|>


<commit_before>const Discord = require('discord.js');
const ms = require('ms');
exports.run = (client, message, args) => {
  const rank = args.slice(1).join(' ');
  const user = message.mentions.users.first();
  const modlog = client.channels.find('name', 'mod-log');
  if (!modlog) return message.reply('I cannot find a mod-log channel').catch(console.error);
  if (rank.length < 1) return message.reply('You must supply a rank.').catch(console.error);
  if (message.mentions.users.size < 1) return message.reply('You must mention someone to mute them.').catch(console.error);
  const muteRole = client.guilds.get(message.guild.id).roles.find('name', `${rank}`);
  const embed = new Discord.RichEmbed()
  .setTimestamp()
  .setColor(0xff0000)
  .setTitle("User Rank Modified")
  .setThumbnail(`${user.avatarURL}`)
  .setDescription(`\n`)
  .addField("Username:",`${user.username} (${user})`,true)
  .addField("Moderator:",`${message.author.username} (${message.author})`, true)
  .addField("New Rank:",`${rank}`, false)
  .setFooter(`User: ${user.username}`,`${user.avatarURL}`);

  user.sendMessage({embed: {
color: 0xff0000,
title: "User ranked",
description: (`\nYou have been ranked!\n`),
fields: [{
  name : "Username:",
  value : `${user.username} (${user})`,
  inline : true
},{
  name : "Administrator:",
  value :`${message.author.username} (${message.author})`,
  inline : true
},{
  name : "New rank:",
  value : `${rank}`,
  inline : false
},{
  name : "If you believe that this was an error, please contact the Administrator involved.",
  value : `~ Canadian Army`,
  inline : false
}]
  }})

  if (!message.guild.member(client.user).hasPermission('MANAGE_ROLES_OR_PERMISSIONS')) return message.reply('I do not have the correct permissions.').catch(console.error);

    message.guild.member(user).addRole(muteRole).then(() => {
      client.channels.get(modlog.id).send({embed}).catch(console.error);
     message.channel.send({embed}).catch(console.error);
    });
  }

exports.conf = {
  enabled: true,
  guildOnly: false,
  aliases: [],
  permLevel: 3
};

exports.help = {
  name: 'rank',
  description: 'Gives a role to the discord user.',
  usage: 'rank [mention] [role]'
};
<commit_msg>Update rank.js<commit_after>const Discord = require('discord.js');
const ms = require('ms');
exports.run = (client, message, args) => {
  const rank = args.slice(1).join(' ');
  const user = message.mentions.users.first();
  const modlog = client.channels.find('name', 'mod-log');
  if (!modlog) return message.reply('I cannot find a mod-log channel').catch(console.error);
  if (rank.length < 1) return message.reply('You must supply a rank.').catch(console.error);
  if (message.mentions.users.size < 1) return message.reply('You must mention someone to mute them.').catch(console.error);
  const muteRole = client.guilds.get(message.guild.id).roles.find('name', `${rank}`);
  const embed = new Discord.RichEmbed()
  .setTimestamp()
  .setColor(0x00ff00)
  .setTitle("User Rank Modified")
  .setThumbnail(`${user.avatarURL}`)
  .setDescription(`\n`)
  .addField("Username:",`${user.username} (${user})`,true)
  .addField("Moderator:",`${message.author.username} (${message.author})`, true)
  .addField("New Rank:",`${rank}`, false)
  .setFooter(`User: ${user.username}`,`${user.avatarURL}`);

  user.sendMessage({embed: {
color: 0x00ff00,
title: "User ranked",
description: (`\nYou have been ranked!\n`),
fields: [{
  name : "Username:",
  value : `${user.username} (${user})`,
  inline : true
},{
  name : "Administrator:",
  value :`${message.author.username} (${message.author})`,
  inline : true
},{
  name : "New rank:",
  value : `${rank}`,
  inline : false
},{
  name : "If you believe that this was an error, please contact the Administrator involved.",
  value : `~ Canadian Army`,
  inline : false
}]
  }})

  if (!message.guild.member(client.user).hasPermission('MANAGE_ROLES_OR_PERMISSIONS')) return message.reply('I do not have the correct permissions.').catch(console.error);

    message.guild.member(user).addRole(muteRole).then(() => {
      client.channels.get(modlog.id).send({embed}).catch(console.error);
     message.channel.send({embed}).catch(console.error);
    });
  }

exports.conf = {
  enabled: true,
  guildOnly: false,
  aliases: [],
  permLevel: 3
};

exports.help = {
  name: 'rank',
  description: 'Gives a role to the discord user.',
  usage: 'rank [mention] [role]'
};
<|endoftext|>


<commit_before>exports.run = async (client,msg,args) => {
  const toBanUsr = msg.mentions.users.last() === client.user ? msg.mentions.users.first() : msg.mentions.users.last();
  let reason;
  let duration;
  if (!args[1]){
      duration = 'permanent';
      reason = 'None'
      reason = args.slice(2).join(' ') ? args.slice(2).join(' ') : 'None';
  } else {
      reason = args.slice(1).join(' ');
  }

  const embed = new Discord.RichEmbed()
  .addField('')
};

exports.help = {
    category: 'moderation',
    usage: '[mention:user] [reason:string]',
    description: 'Warn someone',
    detail: 'Use warn to warn someone who passes the rules.',
    botPerm    : ['SEND_MESSAGES', 'EMBED_LINKS'],
    authorPerm : [],
    alias      : [
        'wa'
    ]
};
<commit_msg>Added warn<commit_after>const Discord = require('discord.js')
exports.run = async (client,msg,args) => {
  const toWarn = msg.mentions.users.last() === client.user ? msg.mentions.users.first() : msg.mentions.users.last();
  const mayLog = msg.guild.channels.find('name', 'may-log');
  let reason;
  let duration;
  if (!args[1]){
      duration = 'permanent';
      reason = 'None'
      reason = args.slice(2).join(' ') ? args.slice(2).join(' ') : 'None';
  } else {
      reason = args.slice(1).join(' ');
  }

  if (!toWarn) {
    return msg.channel.send('Please mention someone.')
  }
  const embed = new Discord.RichEmbed()
  .setAuthor(`Warned ${toWarn.tag}`)
  .setDescription(`**Punished User:** ${toWarn.tag} \`(${toWarn.id})\`\n**Punished By** ${msg.author.tag} \`(${msg.author.id})\`\n**Reason:** ${reason}`);
  mayLog ? mayLog.send({embed}) : msg.channel.send({embed});
};

exports.help = {
    category: 'moderation',
    usage: '[mention:user] [reason:string]',
    description: 'Warn someone',
    detail: 'Use warn to warn someone who passes the rules.',
    botPerm    : ['SEND_MESSAGES', 'EMBED_LINKS'],
    authorPerm : [],
    alias      : [
        'wa'
    ]
};
<|endoftext|>


<commit_before>'use strict';
const util = require('util');
const CommandUtil = require('../src/command_util').CommandUtil;
const l10nFile = __dirname + '/../l10n/commands/wear.yml';
const l10n = require('../src/l10n')(l10nFile);

exports.command = (rooms, items, players, npcs, Commands) => {
  return (args, player) => {
    const cmds = args.toLowerCase().split(' ');

    let thing = cmds[0];
    if (thing === 'all') {
      wearAll();
      return;
    }

    thing = CommandUtil.findItemInInventory(thing, player, true);
    if (!thing) {
      player.sayL10n(l10n, 'ITEM_NOT_FOUND');
      return;
    }

    return wearItem(thing);

    function wearAll() {
      const items = player.getInventory();
      items.forEach(wearItem);
    }

    function wearItem(item) {
      if (isWearable(item) && hasOpenSpot(item)) {
        broadCastWearing(item);
        return putOn(item);
      }
      return false;
    }

    function isWearable(item) {

      if (!item.getAttribute('wearLocation')) {
        util.log("No wear location:" , item.getShortDesc(), item.wearLocation);
        player.sayL10n(l10n, 'NO_WEAR_LOCATION', item.getShortDesc(player.getLocale()));
        return false;
      }
      return true;
    }

    function hasOpenSpot(item) {
      const worn = player.getEquipped(item.getAttribute('wearLocation'));
      if (worn) {
        util.log("Cannot wear due to already wearing an item.");
        player.sayL10n(l10n, 'CANT_WEAR', items.get(worn).getShortDesc(player.getLocale()));
        return false;
      }
      return true;
    }

    function broadCastWearing(item) {
      players.eachIf(
        p => CommandUtil.inSameRoom(p, player),
        p => p.sayL10n(l10n, 'OTHER_WEAR', player.getName(), item.getShortDesc(p.getLocale()))
      );
    }

    function putOn(item) {
      const location = item.getAttribute('wearLocation');
      const hasEmitScript = item._events && items._events.wear;
      item.emit('wear', location, player, players);

      //FIXME: Emitting wear does not always work. Perhaps due to items lacking scripts.
      player.equip(location, item);
      player.sayL10n(l10n, 'YOU_WEAR', item.getShortDesc(player.getLocale()));
    }

  };
};
<commit_msg>Fixed typo in check for emit script.<commit_after>'use strict';
const util = require('util');
const CommandUtil = require('../src/command_util').CommandUtil;
const l10nFile = __dirname + '/../l10n/commands/wear.yml';
const l10n = require('../src/l10n')(l10nFile);

exports.command = (rooms, items, players, npcs, Commands) => {
  return (args, player) => {
    const cmds = args.toLowerCase().split(' ');

    let thing = cmds[0];
    if (thing === 'all') {
      wearAll();
      return;
    }

    thing = CommandUtil.findItemInInventory(thing, player, true);
    if (!thing) {
      player.sayL10n(l10n, 'ITEM_NOT_FOUND');
      return;
    }

    return wearItem(thing);

    function wearAll() {
      const items = player.getInventory();
      items.forEach(wearItem);
      items.forEach(item => util.log(item.getShortDesc('en')));
    }

    function wearItem(item) {
      if (isWearable(item) && hasOpenSpot(item)) {
        broadCastWearing(item);
        return putOn(item);
      }
      return false;
    }

    function isWearable(item) {
      if (!item.getAttribute('wearLocation')) {
        util.log("No wear location:" , item.getShortDesc('en'), item.wearLocation);
        player.sayL10n(l10n, 'NO_WEAR_LOCATION', item.getShortDesc(player.getLocale()));
        return false;
      }
      return true;
    }

    function hasOpenSpot(item) {
      const worn = player.getEquipped(item.getAttribute('wearLocation'));
      if (worn) {
        util.log("Cannot wear due to already wearing an item.");
        player.sayL10n(l10n, 'CANT_WEAR', items.get(worn).getShortDesc(player.getLocale()));
        return false;
      }
      return true;
    }

    function broadCastWearing(item) {
      players.eachIf(
        p => CommandUtil.inSameRoom(p, player),
        p => p.sayL10n(l10n, 'OTHER_WEAR', player.getName(), item.getShortDesc(p.getLocale()))
      );
    }

    function putOn(item) {
      const location = item.getAttribute('wearLocation');
      const hasEmitScript = item._events && item._events.wear;
      if (hasEmitScript) { item.emit('wear', location, player, players); }

      //FIXME: Emitting wear does not always work. Perhaps due to items lacking scripts.
      player.equip(location, item);
      player.sayL10n(l10n, 'YOU_WEAR', item.getShortDesc(player.getLocale()));
    }

  };
};
<|endoftext|>


<commit_before>var combine = require('stream-combiner');
var split = require('split');
var thru = require('through2');
var zlib = require('zlib');

module.exports = function () {
  var currentGenre;
  var tr = thru(function(line, _, next) {
    if (line.length <= 0) {
      return next();
    }

    var row = JSON.parse(line);
    if (row.type === 'genre') {
      if (currentGenre) {
        this.push(JSON.stringify(currentGenre) + '\n');
      }

      currentGenre = {
        name: row.name,
        books: []
      };
    } else if (row.type === 'book') {
      currentGenre.books.push(row.name);
    }

    next();
  }, function(done) {
    // if it ends with a genre, push that genre
    this.push(JSON.stringify(currentGenre) + '\n');
    done();
  });

  return combine(
    split(),
    tr,
    zlib.createGzip()
  );
};
<commit_msg>completes step 14<commit_after>var crypto = require('crypto');

var passphrase = process.argv[2];
var stream = crypto.createDecipher('aes256', passphrase);

process.stdin
    .pipe(stream)
    .pipe(process.stdout);
<|endoftext|>


<commit_before>(function() {
    'use strict';
    angular.module('chaise.navbar', [
        'chaise.login',
        'chaise.utils'
    ])
    .directive('navbar', [ '$rootScope', 'UriUtils' function($rootScope, UriUtils) {
        var chaiseConfig = Object.assign({}, $rootScope.chaiseConfig);

    // One-time transformation of chaiseConfig.navbarMenu to set the appropriate newTab setting at each node
        var root = chaiseConfig.navbarMenu || {};
        if (root) {
            // Set default newTab property at root node
            root.newTab = true;
            var q = [root];
            while (q.length > 0) {
                var obj = q.shift();
                var parentNewTab = obj.newTab;
                // If current node is a leaf, do nothing
                if (obj.url) {
                    continue;
                }
                // If current node has children, set each child's newTab to its own existing newTab or parent's newTab
                for (var key in obj) {
                    if (key == 'children') {
                        obj[key].forEach(function(child) {
                            q.push(child);
                            if (child.newTab === undefined) {
                                child.newTab = parentNewTab;
                            }
                        });
                    }
                }
            }
        }

        return {
            restrict: 'EA',
            scope: {},
            templateUrl: UriUtils.chaiseDeploymentPath() + 'common/templates/navbar.html',
            link: function(scope) {
                scope.brandURL = chaiseConfig.navbarBrand;
                scope.brandText = chaiseConfig.navbarBrandText || chaiseConfig.headTitle;
                scope.brandImage = chaiseConfig.navbarBrandImage;
                scope.menu = chaiseConfig.navbarMenu || [];
            }
        };
    }])

    .directive('navbarMenu', ['$compile', 'UriUtils', function($compile, UriUtils) {
        return {
            restrict: 'EA',
            scope: {
                menu: '='
            },
            templateUrl: UriUtils.chaiseDeploymentPath() + 'common/templates/navbarMenu.html',
            compile: function(el) {
                var contents = el.contents().remove();
                var compiled;
                return function(scope, el) {
                    if (!compiled) {
                        compiled = $compile(contents);
                    }
                    compiled(scope, function(clone) {
                        el.append(clone);
                    });
                };
            }
        };
    }])
})();
<commit_msg>Syntax error corrected<commit_after>(function() {
    'use strict';
    angular.module('chaise.navbar', [
        'chaise.login',
        'chaise.utils'
    ])
    .directive('navbar', [ '$rootScope', 'UriUtils', function($rootScope, UriUtils) {
        var chaiseConfig = Object.assign({}, $rootScope.chaiseConfig);

    // One-time transformation of chaiseConfig.navbarMenu to set the appropriate newTab setting at each node
        var root = chaiseConfig.navbarMenu || {};
        if (root) {
            // Set default newTab property at root node
            root.newTab = true;
            var q = [root];
            while (q.length > 0) {
                var obj = q.shift();
                var parentNewTab = obj.newTab;
                // If current node is a leaf, do nothing
                if (obj.url) {
                    continue;
                }
                // If current node has children, set each child's newTab to its own existing newTab or parent's newTab
                for (var key in obj) {
                    if (key == 'children') {
                        obj[key].forEach(function(child) {
                            q.push(child);
                            if (child.newTab === undefined) {
                                child.newTab = parentNewTab;
                            }
                        });
                    }
                }
            }
        }

        return {
            restrict: 'EA',
            scope: {},
            templateUrl: UriUtils.chaiseDeploymentPath() + 'common/templates/navbar.html',
            link: function(scope) {
                scope.brandURL = chaiseConfig.navbarBrand;
                scope.brandText = chaiseConfig.navbarBrandText || chaiseConfig.headTitle;
                scope.brandImage = chaiseConfig.navbarBrandImage;
                scope.menu = chaiseConfig.navbarMenu || [];
            }
        };
    }])

    .directive('navbarMenu', ['$compile', 'UriUtils', function($compile, UriUtils) {
        return {
            restrict: 'EA',
            scope: {
                menu: '='
            },
            templateUrl: UriUtils.chaiseDeploymentPath() + 'common/templates/navbarMenu.html',
            compile: function(el) {
                var contents = el.contents().remove();
                var compiled;
                return function(scope, el) {
                    if (!compiled) {
                        compiled = $compile(contents);
                    }
                    compiled(scope, function(clone) {
                        el.append(clone);
                    });
                };
            }
        };
    }])
})();
<|endoftext|>


<commit_before>(function() {

	var UrlStereoLatLongMap = E2.plugins.url_stereo_latlongmap_generator = function(core, node) {
		Plugin.apply(this, arguments)
		this.desc = 'Load a stereo latlong map from a URL. JPEG and PNG supported. Hover over the Browse button to select an existing image from the library.'

		this.input_slots = []

		this.output_slots = [
			{
				name: 'left',
				dt: core.datatypes.TEXTURE,
				desc: 'The left side of the loaded lat long map.'
			},
			{
				name: 'right',
				dt: core.datatypes.TEXTURE,
				desc: 'The right side of the loaded lat long map.'
			}
		]

		this.state = { url: '' }

		this.loadingTexture = E2.core.assetLoader.loadingTexture

		this.leftTexture = this.loadingTexture
		this.rightTexture = this.loadingTexture

		this.dirty = false
		this.thumbnail = null
	}

	UrlStereoLatLongMap.prototype = Object.create(Plugin.prototype)

	UrlStereoLatLongMap.prototype.create_ui = function() {
		var container = make('div')
		var inp = NodeUI.makeSpriteSVGButton(
		NodeUI.makeSpriteSVG('vp-edit-icon', 'cmd_edit_graph'),
		'No texture selected'
		);
		inp.addClass('p_round');

		this.thumbnail = make('div').addClass('p_thumbnail');

		this.thumbnail.css({
			'background-image': 'url(\'images/no_texture.png\')',
			'background-size': 'cover'
		})

		var clickHandler = function() {
			var that = this;
			var oldValue = that.state.url
			var newValue = oldValue

			var setValueFn = function(v) {
				that.state.url = newValue = v
				that.updated = true
				that.state_changed();
				return true;
			};

			FileSelectControl
			.createTextureSelector(oldValue, function(control) {
				control
				.template('texture')
				.selected(oldValue)
				.onChange(setValueFn)
				.buttons({
					'Cancel': setValueFn.bind(this, oldValue),
					'Select': setValueFn
				})
				.on('closed', function() {
					if (newValue === oldValue)
						return;

					mixpanel.track('UrlStereoCubeMap Texture Changed')
					that.undoableSetState('url', newValue, oldValue)
				})
				.modal()
			});

			return false;
		}.bind(this);

		inp.click(clickHandler)
		this.thumbnail.click(clickHandler)

		container.append(this.thumbnail)
		container.append(inp)

		this.node.on('pluginStateChanged', this.updateUi.bind(this))

		return container
	}

	UrlStereoLatLongMap.prototype.update_input = function() {}

	UrlStereoLatLongMap.prototype.update_state = function() {
		if (!this.dirty)
			return

		var that = this

		this.waitingToLoad = true

		this.leftTexture = this.loadingTexture
		this.rightTexture = this.loadingTexture

		E2.core.assetLoader
		.loadAsset('image', this.state.url)
		.then(function(img) {
			that.makeTexturesFromImage(img)
		})
		.catch(function() {
			that.leftTexture = that.defaultTexture
			that.rightTexture = that.defaultTexture
			that.waitingToLoad = false
			that.updated = true
		})

		this.dirty = false
	}

	UrlStereoLatLongMap.prototype.makeTexturesFromImage = function(img) {
		var imageWidth = img.width
		var imageHeight = img.height

		var tiles = 2

		var tileWidth = imageWidth
		var tileHeight = imageHeight / 2

		var textures = []

		for (var i = 0; i < tiles; ++i) {
			var tileCanvas = document.createElement('canvas')
			tileCanvas.width = tileWidth
			tileCanvas.height = tileHeight

			var ctx = tileCanvas.getContext('2d')
			ctx.drawImage(img, 0, i * tileHeight,
			tileWidth, tileHeight, 0, 0, tileWidth, tileHeight)

			textures.push(tileCanvas)
		}

		// left eye
		this.leftTexture = new THREE.Texture(textures[0])

		// right eye
		this.rightTexture = new THREE.Texture(textures[1])

		this.updated = true
	}

	UrlStereoLatLongMap.prototype.update_output = function(slot) {
		if (this.waitingToLoad &&
		this.leftTexture && this.rightTexture &&
		this.leftTexture.image && this.leftTexture.image.width !== 0 &&
		this.rightTexture.image && this.rightTexture.image.width !== 0)
		{
			// force an extra update through the graph
			// with a texture that has actual image data
			this.waitingToLoad = false
			this.updated = true
		}

		return slot.index === 0 ? this.leftTexture : this.rightTexture
	}

	UrlStereoLatLongMap.prototype.state_changed = function() {
		if (!this.state.url)
			return

		this.updateUi()

		this.dirty = true
	}

	UrlStereoLatLongMap.prototype.updateUi = function() {
		if (this.thumbnail)
			this.thumbnail.css({ 'background-image': 'url(\'' + this.state.url + '\')' })
	}

})()<commit_msg>fix stereo latlong<commit_after>(function() {

	var UrlStereoLatLongMap = E2.plugins.url_stereo_latlongmap_generator = function(core, node) {
		Plugin.apply(this, arguments)
		this.desc = 'Load a stereo latlong map from a URL. JPEG and PNG supported. Hover over the Browse button to select an existing image from the library.'

		this.input_slots = []

		this.output_slots = [
			{
				name: 'left',
				dt: core.datatypes.TEXTURE,
				desc: 'The left side of the loaded lat long map.'
			},
			{
				name: 'right',
				dt: core.datatypes.TEXTURE,
				desc: 'The right side of the loaded lat long map.'
			}
		]

		this.state = { url: '' }

		this.loadingTexture = E2.core.assetLoader.loadingTexture

		this.leftTexture = this.loadingTexture
		this.rightTexture = this.loadingTexture

		this.dirty = false
		this.thumbnail = null
	}

	UrlStereoLatLongMap.prototype = Object.create(Plugin.prototype)

	UrlStereoLatLongMap.prototype.create_ui = function() {
		var container = make('div')
		var inp = NodeUI.makeSpriteSVGButton(
		NodeUI.makeSpriteSVG('vp-edit-icon', 'cmd_edit_graph'),
		'No texture selected'
		);
		inp.addClass('p_round');

		this.thumbnail = make('div').addClass('p_thumbnail');

		this.thumbnail.css({
			'background-image': 'url(\'images/no_texture.png\')',
			'background-size': 'cover'
		})

		var clickHandler = function() {
			var that = this;
			var oldValue = that.state.url
			var newValue = oldValue

			var setValueFn = function(v) {
				that.state.url = newValue = v
				that.updated = true
				that.state_changed();
				return true;
			};

			FileSelectControl
			.createTextureSelector(oldValue, function(control) {
				control
				.template('texture')
				.selected(oldValue)
				.onChange(setValueFn)
				.buttons({
					'Cancel': setValueFn.bind(this, oldValue),
					'Select': setValueFn
				})
				.on('closed', function() {
					if (newValue === oldValue)
						return;

					mixpanel.track('UrlStereoCubeMap Texture Changed')
					that.undoableSetState('url', newValue, oldValue)
				})
				.modal()
			});

			return false;
		}.bind(this);

		inp.click(clickHandler)
		this.thumbnail.click(clickHandler)

		container.append(this.thumbnail)
		container.append(inp)

		this.node.on('pluginStateChanged', this.updateUi.bind(this))

		return container
	}

	UrlStereoLatLongMap.prototype.update_input = function() {}

	UrlStereoLatLongMap.prototype.update_state = function() {
		if (!this.dirty)
			return

		var that = this

		this.waitingToLoad = true

		this.leftTexture = this.loadingTexture
		this.rightTexture = this.loadingTexture

		E2.core.assetLoader
		.loadAsset('image', this.state.url)
		.then(function(img) {
			that.makeTexturesFromImage(img)
		})
		.catch(function() {
			that.leftTexture = that.defaultTexture
			that.rightTexture = that.defaultTexture
			that.waitingToLoad = false
			that.updated = true
		})

		this.dirty = false
	}

	UrlStereoLatLongMap.prototype.makeTexturesFromImage = function(img) {
		var imageWidth = img.width
		var imageHeight = img.height

		var tiles = 2

		var tileWidth = imageWidth
		var tileHeight = imageHeight / 2

		var textures = []

		for (var i = 0; i < tiles; ++i) {
			var tileCanvas = document.createElement('canvas')
			tileCanvas.width = tileWidth
			tileCanvas.height = tileHeight

			var ctx = tileCanvas.getContext('2d')
			ctx.drawImage(img, 0, i * tileHeight,
			tileWidth, tileHeight, 0, 0, tileWidth, tileHeight)

			textures.push(tileCanvas)
		}

		// left eye
		this.leftTexture = new THREE.Texture(textures[0])
		this.leftTexture.needsUpdate = true

		// right eye
		this.rightTexture = new THREE.Texture(textures[1])
		this.rightTexture.needsUpdate = true

		this.updated = true
	}

	UrlStereoLatLongMap.prototype.update_output = function(slot) {
		if (this.waitingToLoad &&
		this.leftTexture && this.rightTexture &&
		this.leftTexture.image && this.leftTexture.image.width !== 0 &&
		this.rightTexture.image && this.rightTexture.image.width !== 0)
		{
			// force an extra update through the graph
			// with a texture that has actual image data
			this.waitingToLoad = false
			this.updated = true
		}

		return slot.index === 0 ? this.leftTexture : this.rightTexture
	}

	UrlStereoLatLongMap.prototype.state_changed = function() {
		if (!this.state.url)
			return

		this.updateUi()

		this.dirty = true
	}

	UrlStereoLatLongMap.prototype.updateUi = function() {
		if (this.thumbnail)
			this.thumbnail.css({ 'background-image': 'url(\'' + this.state.url + '\')' })
	}

})()<|endoftext|>


<commit_before>(function ($) {
  // register namespace
  $.extend(true, window, {
    "Slick": {
      "CellRangeSelector": CellRangeSelector
    }
  });

  function CellRangeSelector(options) {
    var _grid;
    var _canvas;
    var _dragging;
    var _decorator;
    var _self = this;
    var _handler = new Slick.EventHandler();
    var _defaults = {
      selectionCss: {
        "border": "2px dashed blue"
      }
    };

    function init(grid) {
      options = $.extend(true, {}, _defaults, options);
      _decorator = new Slick.CellRangeDecorator(grid, options);
      _grid = grid;
      _canvas = _grid.getCanvasNode();
      _handler
        .subscribe(_grid.onDragInit, handleDragInit)
        .subscribe(_grid.onDragStart, handleDragStart)
        .subscribe(_grid.onDrag, handleDrag)
        .subscribe(_grid.onDragEnd, handleDragEnd);
    }

    function destroy() {
      _handler.unsubscribeAll();
    }

    function handleDragInit(e, dd) {
      // prevent the grid from cancelling drag'n'drop by default
      e.stopImmediatePropagation();
    }

    function handleDragStart(e, dd) {
      var cell = _grid.getCellFromEvent(e);
      if (_self.onBeforeCellRangeSelected.notify(cell) !== false) {
        if (_grid.canCellBeSelected(cell.row, cell.cell)) {
          _dragging = true;
          e.stopImmediatePropagation();
        }
      }
      if (!_dragging) {
        return;
      }

      _grid.focus();

      var start = _grid.getCellFromPoint(
          dd.startX - $(_canvas).offset().left,
          dd.startY - $(_canvas).offset().top);

      dd.range = {start: start, end: {}};

      return _decorator.show(new Slick.Range(start.row, start.cell));
    }

    function handleDrag(e, dd) {
      if (!_dragging) {
        return;
      }
      e.stopImmediatePropagation();

      var end = _grid.getCellFromPoint(
          e.pageX - $(_canvas).offset().left,
          e.pageY - $(_canvas).offset().top);

      if (!_grid.canCellBeSelected(end.row, end.cell)) {
        return;
      }

      dd.range.end = end;
      _decorator.show(new Slick.Range(dd.range.start.row, dd.range.start.cell, end.row, end.cell));
    }

    function handleDragEnd(e, dd) {
      if (!_dragging) {
        return;
      }

      _dragging = false;
      e.stopImmediatePropagation();

      _decorator.hide();
      _self.onCellRangeSelected.notify({
        range: new Slick.Range(
            dd.range.start.row,
            dd.range.start.cell,
            dd.range.end.row,
            dd.range.end.cell
        )
      });
    }

    $.extend(this, {
      "init": init,
      "destroy": destroy,

      "onBeforeCellRangeSelected": new Slick.Event(),
      "onCellRangeSelected": new Slick.Event()
    });
  }
})(jQuery);<commit_msg>Delete slick.cellrangeselector.js<commit_after><|endoftext|>


<commit_before>/*
 *  PlugfestTransport.js
 *
 *  David Janes
 *  IOTDB.org
 *  2016-01-23
 *
 *  Copyright [2013-2016] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

var iotdb = require('iotdb');
var iotdb_transport = require('iotdb-transport');
var iotdb_links = require('iotdb-links');
var _ = iotdb._;

var coap = require('coap');

var path = require('path');
var events = require('events');
var util = require('util');
var url = require('url');

var logger = iotdb.logger({
    name: 'iotdb-transport-plugfest',
    module: 'PlugfestTransport',
});

/* --- constructor --- */

/**
 *  Create a transport for Plugfest.
 */
var PlugfestTransport = function (initd) {
    var self = this;

    self.initd = _.defaults(
        initd, {
            channel: iotdb_transport.channel,
            unchannel: iotdb_transport.unchannel,
        },
        iotdb.keystore().get("/transports/PlugfestTransport/initd"), {
            prefix: "",
            server_host: null,
            server_port: 22001,
        }
    );

    self._emitter = new events.EventEmitter();
    self.native = null;
    self.server_url = null;

    self._emitter.on("server-ready", function() {
        self._setup_server();
    });

    _.net.external.ipv4(function (error, ipv4) {
        if (self.initd.server_host) {
            ipv4 = self.initd.server_host;
        } else if (error) {
            ipv4 = _.net.ipv4();
        }

        var server = coap.createServer();
        // server.listen(self.initd.server_port, "0.0.0.0", function (error) {
        server.listen(self.initd.server_port, "0.0.0.0", function (error) {
            if (error) {
                console.log("ERROR", error);
                return;
            }

            self.server_url = "coap://" + ipv4 + ":" + self.initd.server_port;

            console.log("===============================");
            console.log("=== Plugfest CoAP Server Up");
            console.log("=== ");
            console.log("=== Connect at:");
            console.log("=== " + self.server_url);
            console.log("===============================");

            self.native = server;
            self._emitter.emit("server-ready");
        });
    });
};

PlugfestTransport.prototype = new iotdb_transport.Transport();
PlugfestTransport.prototype._class = "PlugfestTransport";

/* --- CoAP server -- */
PlugfestTransport.prototype._setup_server = function () {
    var self = this;

    self.native.on('request', function (req, res) {
        try {
            logger.info({
                method: "_setup_server/on('request')",
                request_url: req.url,
                request_method: req.method,
            }, "CoAP request");

            var _done = function(error, content) {
                if (error) {
                    request.code = 500;
                }

                if (content) {
                    if (_.is.Dictionary(content)) {
                        content = JSON.stringify(content);
                    }

                    res.write(content);
                }

                res.end();
            }

            if (req.url === "/.well-known/core") {
                self._get_well_known(_done);
            } else if (req.url === "/bulletins") {
                self._get_bulletins(_done);
            } else {
                done(null, {});
            }

        } catch (x) {
            logger.error({
                method: "_setup_server/on('request')",
                exception: _.error.message(x),
                stack: x.stack,
            }, "unexpected exception");
        }
    });

};

PlugfestTransport.prototype._get_well_known = function (done) {
    var self = this;

    var resultd = {};
    resultd["/.well-known/core"] = {
        ct: 65202,
    };
    resultd["/bulletins"] = {};

    iotdb_links.produce(resultd, done);
};

PlugfestTransport.prototype._get_bulletins = function (done) {
    done(null, {});
};

/* --- methods --- */

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.list = function (paramd, callback) {
    var self = this;

    self._validate_list(paramd, callback);

    callback(null, null);
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.added = function (paramd, callback) {
    var self = this;

    self._validate_added(paramd, callback);

    var channel = self.initd.channel(self.initd, paramd.id);
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.get = function (paramd, callback) {
    var self = this;

    self._validate_get(paramd, callback);

    var gd = _.shallowCopy(paramd);
    gd.value = null;

    callback(new errors.NotImplemented(), gd);
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.put = function (paramd, callback) {
    var self = this;

    self._validate_update(paramd, callback);

    var pd = _.shallowCopy(paramd);

    callback(new errors.NotImplemented(), pd);
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.updated = function (paramd, callback) {
    var self = this;

    self._validate_updated(paramd, callback);
};

/**
 *  See {iotdb_transport.Transport#bands} for documentation.
 */
PlugfestTransport.prototype.bands = function (paramd, callback) {
    var self = this;

    self._validate_bands(paramd, callback);

    var bd = _.shallowCopy(paramd);

    callback(new errors.NeverImplemented(), bd);
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.remove = function (paramd, callback) {
    var self = this;

    self._validate_remove(paramd, callback);

    var channel = self.initd.channel(self.intid, paramd.id, paramd.band);
};

/* --- internals --- */

/**
 *  API
 */
exports.PlugfestTransport = PlugfestTransport;
<commit_msg>remove() cleanup<commit_after>/*
 *  PlugfestTransport.js
 *
 *  David Janes
 *  IOTDB.org
 *  2016-01-23
 *
 *  Copyright [2013-2016] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

var iotdb = require('iotdb');
var iotdb_transport = require('iotdb-transport');
var iotdb_links = require('iotdb-links');
var _ = iotdb._;

var coap = require('coap');

var path = require('path');
var events = require('events');
var util = require('util');
var url = require('url');

var logger = iotdb.logger({
    name: 'iotdb-transport-plugfest',
    module: 'PlugfestTransport',
});

/* --- constructor --- */

/**
 *  Create a transport for Plugfest.
 */
var PlugfestTransport = function (initd) {
    var self = this;

    self.initd = _.defaults(
        initd, {
            channel: iotdb_transport.channel,
            unchannel: iotdb_transport.unchannel,
        },
        iotdb.keystore().get("/transports/PlugfestTransport/initd"), {
            prefix: "",
            server_host: null,
            server_port: 22001,
        }
    );

    self._emitter = new events.EventEmitter();
    self.native = null;
    self.server_url = null;

    self._emitter.on("server-ready", function() {
        self._setup_server();
    });

    _.net.external.ipv4(function (error, ipv4) {
        if (self.initd.server_host) {
            ipv4 = self.initd.server_host;
        } else if (error) {
            ipv4 = _.net.ipv4();
        }

        var server = coap.createServer();
        // server.listen(self.initd.server_port, "0.0.0.0", function (error) {
        server.listen(self.initd.server_port, "0.0.0.0", function (error) {
            if (error) {
                console.log("ERROR", error);
                return;
            }

            self.server_url = "coap://" + ipv4 + ":" + self.initd.server_port;

            console.log("===============================");
            console.log("=== Plugfest CoAP Server Up");
            console.log("=== ");
            console.log("=== Connect at:");
            console.log("=== " + self.server_url);
            console.log("===============================");

            self.native = server;
            self._emitter.emit("server-ready");
        });
    });
};

PlugfestTransport.prototype = new iotdb_transport.Transport();
PlugfestTransport.prototype._class = "PlugfestTransport";

/* --- CoAP server -- */
PlugfestTransport.prototype._setup_server = function () {
    var self = this;

    self.native.on('request', function (req, res) {
        try {
            logger.info({
                method: "_setup_server/on('request')",
                request_url: req.url,
                request_method: req.method,
            }, "CoAP request");

            var _done = function(error, content) {
                if (error) {
                    request.code = 500;
                }

                if (content) {
                    if (_.is.Dictionary(content)) {
                        content = JSON.stringify(content);
                    }

                    res.write(content);
                }

                res.end();
            }

            if (req.url === "/.well-known/core") {
                self._get_well_known(_done);
            } else if (req.url === "/bulletins") {
                self._get_bulletins(_done);
            } else {
                done(null, {});
            }

        } catch (x) {
            logger.error({
                method: "_setup_server/on('request')",
                exception: _.error.message(x),
                stack: x.stack,
            }, "unexpected exception");
        }
    });

};

PlugfestTransport.prototype._get_well_known = function (done) {
    var self = this;

    var resultd = {};
    resultd["/.well-known/core"] = {
        ct: 65202,
    };
    resultd["/bulletins"] = {};

    iotdb_links.produce(resultd, done);
};

PlugfestTransport.prototype._get_bulletins = function (done) {
    done(null, {});
};

/* --- methods --- */

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.list = function (paramd, callback) {
    var self = this;

    self._validate_list(paramd, callback);

    callback(null, null);
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.added = function (paramd, callback) {
    var self = this;

    self._validate_added(paramd, callback);

    var channel = self.initd.channel(self.initd, paramd.id);
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.get = function (paramd, callback) {
    var self = this;

    self._validate_get(paramd, callback);

    var gd = _.shallowCopy(paramd);
    gd.value = null;

    callback(new errors.NotImplemented(), gd);
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.put = function (paramd, callback) {
    var self = this;

    self._validate_update(paramd, callback);

    var pd = _.shallowCopy(paramd);

    callback(new errors.NotImplemented(), pd);
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.updated = function (paramd, callback) {
    var self = this;

    self._validate_updated(paramd, callback);
};

/**
 *  See {iotdb_transport.Transport#bands} for documentation.
 */
PlugfestTransport.prototype.bands = function (paramd, callback) {
    var self = this;

    self._validate_bands(paramd, callback);

    var bd = _.shallowCopy(paramd);

    callback(new errors.NeverImplemented(), bd);
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 */
PlugfestTransport.prototype.remove = function (paramd, callback) {
    var self = this;

    self._validate_remove(paramd, callback);

    var rd = _.shallowCopy(paramd);
    delete rd.band;
    delete rd.value;

    callback(new errors.NotImplemented(), rd);
};

/* --- internals --- */

/**
 *  API
 */
exports.PlugfestTransport = PlugfestTransport;
<|endoftext|>


<commit_before>(function(L){

  var tileProtocol = (window.location.protocol !== "https:") ? "http:" : "https:";
  var attributionStyles = "line-height:9px; text-overflow:ellipsis; white-space:nowrap;overflow:hidden; display:inline-block;";
  var logoStyles = "position:absolute; top:-38px; right:2px;";
  var attributionLogo = "";
  var formatTextAttributions = function formatTextAttributions(text){
    return "" + text + "";
  };

  L.esri.BasemapLayer = L.TileLayer.extend({
    statics: {
      TILES: {
        Streets: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}/",
          attributionUrl: "https://static.arcgis.com/attribution/World_Street_Map",
          options: {
            minZoom: 1,
            maxZoom: 19,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri") + attributionLogo
          }
        },
        Topographic: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}/",
          attributionUrl: "https://static.arcgis.com/attribution/World_Topo_Map",
          options: {
            minZoom: 1,
            maxZoom: 19,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri") + attributionLogo
          }
        },
        Oceans: {
          urlTemplate: "https://server.arcgisonline.com/ArcGIS/rest/services/Ocean_Basemap/MapServer/tile/{z}/{y}/{x}/",
          attributionUrl: "https://static.arcgis.com/attribution/Ocean_Basemap",
          options: {
            minZoom: 1,
            maxZoom: 16,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri") + attributionLogo
          }
        },
        NationalGeographic: {
          urlTemplate: "https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}/",
          options: {
            minZoom: 1,
            maxZoom: 16,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri") + attributionLogo
          }
        },
        Gray: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}/",
          options: {
            minZoom: 1,
            maxZoom: 16,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri, NAVTEQ, DeLorme") + attributionLogo
          }
        },
        GrayLabels: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Reference/MapServer/tile/{z}/{y}/{x}/",
          options: {
            minZoom: 1,
            maxZoom: 16,
            subdomains: ["server", "services"]
          }
        },
        Imagery: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}/",
          options: {
            minZoom: 1,
            maxZoom: 19,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri, DigitalGlobe, GeoEye, i-cubed, USDA, USGS, AEX, Getmapping, Aerogrid, IGN, IGP, swisstopo, and the GIS User Community") + attributionLogo
          }
        },
        ImageryLabels: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}/",
          options: {
            minZoom: 1,
            maxZoom: 19,
            subdomains: ["server", "services"]
          }
        },
        ImageryTransportation: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer/tile/{z}/{y}/{x}/",
          options: {
            minZoom: 1,
            maxZoom: 19,
            subdomains: ["server", "services"]
          }
        },
        ShadedRelief: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}/",
          options: {
            minZoom: 1,
            maxZoom: 13,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("ESRI, NAVTEQ, DeLorme") + attributionLogo
          }
        },
        ShadedReliefLabels: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places_Alternate/MapServer/tile/{z}/{y}/{x}/",
          options: {
            minZoom: 1,
            maxZoom: 12,
            subdomains: ["server", "services"]
          }
        }
      }
    },
    initialize: function(key, options){
      var config;
      // set the config variable with the appropriate config object
      if (typeof key === "object" && key.urlTemplate && key.options){
        config = key;
      } else if(typeof key === "string" && L.esri.BasemapLayer.TILES[key]){
        config = L.esri.BasemapLayer.TILES[key];
      } else {
        throw new Error("L.esri.BasemapLayer: Invalid parameter. Use one of 'Streets', 'Topographic', 'Oceans', 'NationalGeographic', 'Gray', 'GrayLabels', 'Imagery', 'ImageryLabels', 'ImageryTransportation', 'ShadedRelief' or 'ShadedReliefLabels'");
      }

      // merge passed options into the config options
      var mergedOptions = L.Util.extend(config.options, options);

      // clean up our input url
      var url = L.esri.Util.cleanUrl(config.urlTemplate);

      // call the initialize method on L.TileLayer to set everything up
      L.TileLayer.prototype.initialize.call(this, url, L.Util.setOptions(this, mergedOptions));

      // if this basemap requires dynamic attribution set it up
      if(config.attributionUrl){
        var attributionUrl = config.attributionUrl;
        this._dynamicAttribution = true;
        this._getAttributionData(attributionUrl);
      }
    },
    _dynamicAttribution: false,
    bounds: null,
    zoom: null,
    onAdd: function(map){
      L.TileLayer.prototype.onAdd.call(this, map);
      if(this._dynamicAttribution){
        this.on("load", this._handleTileUpdates, this);
        this._map.on("viewreset zoomend dragend", this._handleTileUpdates, this);
      }
      this._map.on("resize", this._resizeAttribution, this);
    },
    onRemove: function(map){
      if(this._dynamicAttribution){
        this.off("load", this._handleTileUpdates, this);
        this._map.off("viewreset zoomend dragend", this._handleTileUpdates, this);
      }
      this._map.off("resize", this._resizeAttribution, this);
      L.TileLayer.prototype.onRemove.call(this, map);
    },
    _handleTileUpdates: function(e){
      var newBounds;
      var newZoom;

      if(e.type === "load"){
        newBounds = this._map.getBounds();
        newZoom = this._map.getZoom();
      }

      if(e.type === "viewreset" || e.type === "dragend" || e.type ==="zoomend"){
        newBounds = e.target.getBounds();
        newZoom = e.target.getZoom();
      }

      if(this.attributionBoundingBoxes && newBounds && newZoom){
        if(!newBounds.equals(this.bounds) || newZoom !== this.zoom){
          this.bounds = newBounds;
          this.zoom = newZoom;
          this._updateMapAttribution();
        }
      }
    },
    _resizeAttribution: function(){
      var mapWidth = this._map.getSize().x;
      this._getAttributionLogo().style.display = (mapWidth < 600) ? "none":"block";
      this._getAttributionSpan().style.maxWidth =  (mapWidth* 0.75) + "px";
    },
    _getAttributionData: function(url){
      this.attributionBoundingBoxes = [];
      L.esri.RequestHandlers.JSONP(url, {}, this._processAttributionData, this);
    },
    _processAttributionData: function(attributionData){
      for (var c = 0; c < attributionData.contributors.length; c++) {
        var contributor = attributionData.contributors[c];
        for (var i = 0; i < contributor.coverageAreas.length; i++) {
          var coverageArea = contributor.coverageAreas[i];
          var southWest = new L.LatLng(coverageArea.bbox[0], coverageArea.bbox[1]);
          var northEast = new L.LatLng(coverageArea.bbox[2], coverageArea.bbox[3]);
          this.attributionBoundingBoxes.push({
            attribution: contributor.attribution,
            score: coverageArea.score,
            bounds: new L.LatLngBounds(southWest, northEast),
            minZoom: coverageArea.zoomMin,
            maxZoom: coverageArea.zoomMax
          });
        }
      }
      this.attributionBoundingBoxes.sort(function(a,b){
        if (a.score  b.score){ return 1; }
        return 0;
      });
      if(this.bounds){
        this._updateMapAttribution();
      }
    },
    _getAttributionSpan:function(){
      return this._map._container.querySelectorAll('.esri-attributions')[0];
    },
    _getAttributionLogo:function(){
      return this._map._container.querySelectorAll('.esri-attribution-logo')[0];
    },
    _updateMapAttribution: function(){
      var newAttributions = '';
      for (var i = 0; i < this.attributionBoundingBoxes.length; i++) {
        var attr = this.attributionBoundingBoxes[i];
        if(this.bounds.intersects(attr.bounds) && this.zoom >= attr.minZoom && this.zoom <= attr.maxZoom) {
          var attribution = this.attributionBoundingBoxes[i].attribution;
          if(newAttributions.indexOf(attribution) === -1){
            if(newAttributions.length > 0){
              newAttributions += ', ';
            }
            newAttributions += attribution;
          }
        }
      }
      this._getAttributionSpan().innerHTML = newAttributions;
      this._resizeAttribution();
    }
  });

  L.esri.basemapLayer = function(key, options){
    return new L.esri.BasemapLayer(key, options);
  };

})(L);<commit_msg>dark gray map<commit_after>(function(L){

  var tileProtocol = (window.location.protocol !== "https:") ? "http:" : "https:";
  var attributionStyles = "line-height:9px; text-overflow:ellipsis; white-space:nowrap;overflow:hidden; display:inline-block;";
  var logoStyles = "position:absolute; top:-38px; right:2px;";
  var attributionLogo = "";
  var formatTextAttributions = function formatTextAttributions(text){
    return "" + text + "";
  };

  L.esri.BasemapLayer = L.TileLayer.extend({
    statics: {
      TILES: {
        Streets: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}",
          attributionUrl: "https://static.arcgis.com/attribution/World_Street_Map",
          options: {
            minZoom: 1,
            maxZoom: 19,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri") + attributionLogo
          }
        },
        Topographic: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}",
          attributionUrl: "https://static.arcgis.com/attribution/World_Topo_Map",
          options: {
            minZoom: 1,
            maxZoom: 19,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri") + attributionLogo
          }
        },
        Oceans: {
          urlTemplate: tileProtocol + "//server.arcgisonline.com/ArcGIS/rest/services/Ocean_Basemap/MapServer/tile/{z}/{y}/{x}",
          attributionUrl: "https://static.arcgis.com/attribution/Ocean_Basemap",
          options: {
            minZoom: 1,
            maxZoom: 16,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri") + attributionLogo
          }
        },
        NationalGeographic: {
          urlTemplate: "https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}",
          options: {
            minZoom: 1,
            maxZoom: 16,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri") + attributionLogo
          }
        },
        DarkGray: {
          urlTemplate: tileProtocol + "//tiles{s}.arcgis.com/tiles/P3ePLMYs2RVChkJx/arcgis/rest/services/World_Dark_Gray_Base_Beta/MapServer/tile/{z}/{y}/{x}",
          options: {
            minZoom: 1,
            maxZoom: 10,
            subdomains: [1, 2],
            attribution: formatTextAttributions("Esri, DeLorme, HERE") + attributionLogo
          }
        },
        DarkGrayLabels: {
          urlTemplate: tileProtocol + "//tiles{s}.arcgis.com/tiles/P3ePLMYs2RVChkJx/arcgis/rest/services/World_Dark_Gray_Reference_Beta/MapServer/tile/{z}/{y}/{x}",
          options: {
            minZoom: 1,
            maxZoom: 10,
            subdomains: [1, 2],
          }
        },
        Gray: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}",
          options: {
            minZoom: 1,
            maxZoom: 16,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri, NAVTEQ, DeLorme") + attributionLogo
          }
        },
        GrayLabels: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Reference/MapServer/tile/{z}/{y}/{x}",
          options: {
            minZoom: 1,
            maxZoom: 16,
            subdomains: ["server", "services"]
          }
        },
        Imagery: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
          options: {
            minZoom: 1,
            maxZoom: 19,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("Esri, DigitalGlobe, GeoEye, i-cubed, USDA, USGS, AEX, Getmapping, Aerogrid, IGN, IGP, swisstopo, and the GIS User Community") + attributionLogo
          }
        },
        ImageryLabels: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}",
          options: {
            minZoom: 1,
            maxZoom: 19,
            subdomains: ["server", "services"]
          }
        },
        ImageryTransportation: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer/tile/{z}/{y}/{x}",
          options: {
            minZoom: 1,
            maxZoom: 19,
            subdomains: ["server", "services"]
          }
        },
        ShadedRelief: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}",
          options: {
            minZoom: 1,
            maxZoom: 13,
            subdomains: ["server", "services"],
            attribution: formatTextAttributions("ESRI, NAVTEQ, DeLorme") + attributionLogo
          }
        },
        ShadedReliefLabels: {
          urlTemplate: tileProtocol + "//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places_Alternate/MapServer/tile/{z}/{y}/{x}",
          options: {
            minZoom: 1,
            maxZoom: 12,
            subdomains: ["server", "services"]
          }
        }
      }
    },
    initialize: function(key, options){
      var config;
      // set the config variable with the appropriate config object
      if (typeof key === "object" && key.urlTemplate && key.options){
        config = key;
      } else if(typeof key === "string" && L.esri.BasemapLayer.TILES[key]){
        config = L.esri.BasemapLayer.TILES[key];
      } else {
        throw new Error("L.esri.BasemapLayer: Invalid parameter. Use one of 'Streets', 'Topographic', 'Oceans', 'NationalGeographic', 'Gray', 'GrayLabels', 'DarkGray', 'DarkGrayLabels', 'Imagery', 'ImageryLabels', 'ImageryTransportation', 'ShadedRelief' or 'ShadedReliefLabels'");
      }

      // merge passed options into the config options
      var mergedOptions = L.Util.extend(config.options, options);

      // call the initialize method on L.TileLayer to set everything up
      L.TileLayer.prototype.initialize.call(this, config.urlTemplate, L.Util.setOptions(this, mergedOptions));

      // if this basemap requires dynamic attribution set it up
      if(config.attributionUrl){
        var attributionUrl = config.attributionUrl;
        this._dynamicAttribution = true;
        this._getAttributionData(attributionUrl);
      }
    },
    _dynamicAttribution: false,
    bounds: null,
    zoom: null,
    onAdd: function(map){
      L.TileLayer.prototype.onAdd.call(this, map);
      if(this._dynamicAttribution){
        this.on("load", this._handleTileUpdates, this);
        this._map.on("viewreset zoomend dragend", this._handleTileUpdates, this);
      }
      this._map.on("resize", this._resizeAttribution, this);
    },
    onRemove: function(map){
      if(this._dynamicAttribution){
        this.off("load", this._handleTileUpdates, this);
        this._map.off("viewreset zoomend dragend", this._handleTileUpdates, this);
      }
      this._map.off("resize", this._resizeAttribution, this);
      L.TileLayer.prototype.onRemove.call(this, map);
    },
    _handleTileUpdates: function(e){
      var newBounds;
      var newZoom;

      if(e.type === "load"){
        newBounds = this._map.getBounds();
        newZoom = this._map.getZoom();
      }

      if(e.type === "viewreset" || e.type === "dragend" || e.type ==="zoomend"){
        newBounds = e.target.getBounds();
        newZoom = e.target.getZoom();
      }

      if(this.attributionBoundingBoxes && newBounds && newZoom){
        if(!newBounds.equals(this.bounds) || newZoom !== this.zoom){
          this.bounds = newBounds;
          this.zoom = newZoom;
          this._updateMapAttribution();
        }
      }
    },
    _resizeAttribution: function(){
      var mapWidth = this._map.getSize().x;
      this._getAttributionLogo().style.display = (mapWidth < 600) ? "none":"block";
      this._getAttributionSpan().style.maxWidth =  (mapWidth* 0.75) + "px";
    },
    _getAttributionData: function(url){
      this.attributionBoundingBoxes = [];
      L.esri.RequestHandlers.JSONP(url, {}, this._processAttributionData, this);
    },
    _processAttributionData: function(attributionData){
      for (var c = 0; c < attributionData.contributors.length; c++) {
        var contributor = attributionData.contributors[c];
        for (var i = 0; i < contributor.coverageAreas.length; i++) {
          var coverageArea = contributor.coverageAreas[i];
          var southWest = new L.LatLng(coverageArea.bbox[0], coverageArea.bbox[1]);
          var northEast = new L.LatLng(coverageArea.bbox[2], coverageArea.bbox[3]);
          this.attributionBoundingBoxes.push({
            attribution: contributor.attribution,
            score: coverageArea.score,
            bounds: new L.LatLngBounds(southWest, northEast),
            minZoom: coverageArea.zoomMin,
            maxZoom: coverageArea.zoomMax
          });
        }
      }
      this.attributionBoundingBoxes.sort(function(a,b){
        if (a.score  b.score){ return 1; }
        return 0;
      });
      if(this.bounds){
        this._updateMapAttribution();
      }
    },
    _getAttributionSpan:function(){
      return this._map._container.querySelectorAll('.esri-attributions')[0];
    },
    _getAttributionLogo:function(){
      return this._map._container.querySelectorAll('.esri-attribution-logo')[0];
    },
    _updateMapAttribution: function(){
      var newAttributions = '';
      for (var i = 0; i < this.attributionBoundingBoxes.length; i++) {
        var attr = this.attributionBoundingBoxes[i];
        if(this.bounds.intersects(attr.bounds) && this.zoom >= attr.minZoom && this.zoom <= attr.maxZoom) {
          var attribution = this.attributionBoundingBoxes[i].attribution;
          if(newAttributions.indexOf(attribution) === -1){
            if(newAttributions.length > 0){
              newAttributions += ', ';
            }
            newAttributions += attribution;
          }
        }
      }
      this._getAttributionSpan().innerHTML = newAttributions;
      this._resizeAttribution();
    }
  });

  L.esri.basemapLayer = function(key, options){
    return new L.esri.BasemapLayer(key, options);
  };

})(L);<|endoftext|>


<commit_before>/*
This module contains a generic data browsing interface.
*/

CT.Browser = CT.Class({
	CLASSNAME: "CT.Browser",
	_: {
		nodes: {},
		edit: function(data, noreview) {
			var _ = this._, view = this.view;
			CT.db.put(data, function(dfull) {
				if (data.key)
					return noreview || view(dfull);
				_.items.push(dfull);
				_.tlist.postAdd(dfull, true);
			});
		},
		load: function(d) {
			var _ = this._, oz = this.opts, fview = this.firstview;
			if (d.name)
				return this.view(d);
			CT.dom.setContent(_.nodes.content, CT.dom.div([
				CT.dom.div(oz.opener || ("what's this " + oz.modelName + " called?"), "bigger centered"),
				CT.dom.smartField({
					classname: "w1",
					blurs: oz.blurs,
					cb: function(name) {
						d.name = name;
						fview(d);
					}
				})
			], "margined padded bordered round"));
		},
		filter: function() {
			var _ = this._, refresher = function(val) {
				CT.dom.each(_.tlist, function(n, i) {
					CT.dom[(!val || n.firstChild.innerHTML.toLowerCase().includes(val.toLowerCase())) ? "show" : "hide"](n);
				});
				clearbutt.style.display = val ? "inline" : "none";
			}, sf = CT.dom.smartField({
				keyup: refresher
			}), clearbutt = CT.dom.span("X", "hidden pointer");
			clearbutt.onclick = function() {
				sf.value = "";
				refresher();
			}
			return CT.dom.span([sf, clearbutt]);
		},
		build: function(items) {
			this.items(items);
			var _ = this._, oz = this.opts, defs = {
					modelName: oz.modelName
				}, defz = this.defaults, ntxt = "new " + oz.modelName;
			if (oz.owner)
				defs.owner = user.core.get("key");
			_.items = items;
			_.tlist = CT.panel.triggerList([ntxt].concat(items), function(d) {
				_.load((d == ntxt) ? CT.merge(defs, defz()) : d);
			});
			CT.dom.setContent(_.nodes.list, _.tlist);
			var maker = CT.dom.id("tlnew" + oz.modelName),
				h = document.location.hash.slice(1),
				hd = h && CT.data.get(h);
			if (hd && hd.modelName == oz.modelName)
				setTimeout(CT.dom.id("tl" + h).firstChild.onclick, 200); // wait a tick...
			else
				maker.trigger();
			if (oz.filter) {
				CT.dom.setContent(maker.firstChild,
					CT.dom.div("+", "biggest bold shiftup"));
				maker.style.float = "right";
				_.tlist.parentNode.insertBefore(CT.dom.div([
					_.filter(),
					maker
				], "browser_filter"), _.tlist);
			}
		},
		setup: function() {
			var _ = this._, nz = _.nodes, oz = this.opts;
			nz.list = CT.dom.div(null, "ctlist");
			nz.content = CT.dom.div(null, "ctcontent");
			CT.dom.setContent(oz.parent, [
				nz.list,
				nz.content
			]);
			CT.db.get(oz.modelName, _.build, null, null, null, oz.owner && {
				owner: user.core.get("key") // requires user module
			});
		}
	},
	namer: function(d, classes) {
		var n = CT.dom.div(d.name,
			"pointer " + (classes || "bigger centered"));
		n.onclick = function() {
			var sf = CT.dom.smartField({
				value: d.name,
				cb: function(name) {
					if (name == d.name) return;
					CT.db.put({
						key: d.key,
						name: name
					}, function(newd) {
						d.name = newd.name;
						d.label = newd.label;
						CT.dom.setContent(n, d.name);
						CT.dom.setContent(CT.dom.id("tl" + d.key).firstChild,
							d.label);
					});
				}
			});
			CT.dom.setContent(n, sf);
			sf.focus();
		};
		return n;
	},
	view: function(d) {
		// override!
		CT.dom.setContent(_.nodes.content, [
			this.namer(d),
			JSON.stringify(d)
		]);
	},
	firstview: function(d) {
		this.view(d);
	},
	defaults: function() {
		// override
	},
	items: function(items) {
		// override
	},
	init: function(opts) {
		this.opts = CT.merge(opts, {
			parent: "ctmain",
			modelName: null, // REQUIRED
			nopts: {},
			owner: true,
			filter: true,
			blurs: ["name please", "title", "what's it called?"]
		});
		setTimeout(this._.setup);
	}
});<commit_msg>CT.browser._.edit(): support opts.saveMessage (optional alert())<commit_after>/*
This module contains a generic data browsing interface.
*/

CT.Browser = CT.Class({
	CLASSNAME: "CT.Browser",
	_: {
		nodes: {},
		edit: function(data, noreview) {
			var _ = this._, oz = this.opts, view = this.view;
			CT.db.put(data, function(dfull) {
				if (data.key) {
					oz.saveMessage && alert(oz.saveMessage);
					return noreview || view(dfull);
				}
				_.items.push(dfull);
				_.tlist.postAdd(dfull, true);
			});
		},
		load: function(d) {
			var _ = this._, oz = this.opts, fview = this.firstview;
			if (d.name)
				return this.view(d);
			CT.dom.setContent(_.nodes.content, CT.dom.div([
				CT.dom.div(oz.opener || ("what's this " + oz.modelName + " called?"), "bigger centered"),
				CT.dom.smartField({
					classname: "w1",
					blurs: oz.blurs,
					cb: function(name) {
						d.name = name;
						fview(d);
					}
				})
			], "margined padded bordered round"));
		},
		filter: function() {
			var _ = this._, refresher = function(val) {
				CT.dom.each(_.tlist, function(n, i) {
					CT.dom[(!val || n.firstChild.innerHTML.toLowerCase().includes(val.toLowerCase())) ? "show" : "hide"](n);
				});
				clearbutt.style.display = val ? "inline" : "none";
			}, sf = CT.dom.smartField({
				keyup: refresher
			}), clearbutt = CT.dom.span("X", "hidden pointer");
			clearbutt.onclick = function() {
				sf.value = "";
				refresher();
			}
			return CT.dom.span([sf, clearbutt]);
		},
		build: function(items) {
			this.items(items);
			var _ = this._, oz = this.opts, defs = {
					modelName: oz.modelName
				}, defz = this.defaults, ntxt = "new " + oz.modelName;
			if (oz.owner)
				defs.owner = user.core.get("key");
			_.items = items;
			_.tlist = CT.panel.triggerList([ntxt].concat(items), function(d) {
				_.load((d == ntxt) ? CT.merge(defs, defz()) : d);
			});
			CT.dom.setContent(_.nodes.list, _.tlist);
			var maker = CT.dom.id("tlnew" + oz.modelName),
				h = document.location.hash.slice(1),
				hd = h && CT.data.get(h);
			if (hd && hd.modelName == oz.modelName)
				setTimeout(CT.dom.id("tl" + h).firstChild.onclick, 200); // wait a tick...
			else
				maker.trigger();
			if (oz.filter) {
				CT.dom.setContent(maker.firstChild,
					CT.dom.div("+", "biggest bold shiftup"));
				maker.style.float = "right";
				_.tlist.parentNode.insertBefore(CT.dom.div([
					_.filter(),
					maker
				], "browser_filter"), _.tlist);
			}
		},
		setup: function() {
			var _ = this._, nz = _.nodes, oz = this.opts;
			nz.list = CT.dom.div(null, "ctlist");
			nz.content = CT.dom.div(null, "ctcontent");
			CT.dom.setContent(oz.parent, [
				nz.list,
				nz.content
			]);
			CT.db.get(oz.modelName, _.build, null, null, null, oz.owner && {
				owner: user.core.get("key") // requires user module
			});
		}
	},
	namer: function(d, classes) {
		var n = CT.dom.div(d.name,
			"pointer " + (classes || "bigger centered"));
		n.onclick = function() {
			var sf = CT.dom.smartField({
				value: d.name,
				cb: function(name) {
					if (name == d.name) return;
					CT.db.put({
						key: d.key,
						name: name
					}, function(newd) {
						d.name = newd.name;
						d.label = newd.label;
						CT.dom.setContent(n, d.name);
						CT.dom.setContent(CT.dom.id("tl" + d.key).firstChild,
							d.label);
					});
				}
			});
			CT.dom.setContent(n, sf);
			sf.focus();
		};
		return n;
	},
	view: function(d) {
		// override!
		CT.dom.setContent(_.nodes.content, [
			this.namer(d),
			JSON.stringify(d)
		]);
	},
	firstview: function(d) {
		this.view(d);
	},
	defaults: function() {
		// override
	},
	items: function(items) {
		// override
	},
	init: function(opts) {
		this.opts = CT.merge(opts, {
			parent: "ctmain",
			modelName: null, // REQUIRED
			nopts: {},
			owner: true,
			filter: true,
			blurs: ["name please", "title", "what's it called?"]
		});
		setTimeout(this._.setup);
	}
});<|endoftext|>


<commit_before>import { app } from 'electron';
import fs from 'fs';
import os from 'os';
import path from 'path';
import uuid from 'uuid';
import { spawnSync } from 'child_process';
import WebSocket, { Server as WebSocketServer } from 'ws';

let server;
let oldTime = {};
let uniqID = uuid.v4();

let runas = () => {};
if (process.platform === 'win32') {
  runas = require('runas');
}

let mdns;
try {
  mdns = require('mdns');
} catch (e) {
  Logger.error('Failed to load bonjour with error: %j', e);
  console.error('Bonjour is required to use Chromecast Support or to enable ZeroConf for the PlaybackAPI'); // eslint-disable-line
  if (process.platform === 'win32') {
    console.error('On windows you need to install Bonjour Print Services'); // eslint-disable-line
  } else if (process.platform === 'darwin') {
    console.error('One macOS Bonjour should "just work" so if you see this you have much bigger problems'); // eslint-disable-line
  } else {
    console.error('On linux you need to install "avahi"'); // eslint-disable-line
  }
  if (process.platform === 'win32') {
    Emitter.sendToWindowsOfName('main', 'bonjour-install');
  }
}

const changeEvents = ['track', 'state', 'rating', 'lyrics', 'shuffle', 'repeat', 'playlists', 'queue', 'search-results', 'library', 'volume'];
const API_VERSION = JSON.parse(fs.readFileSync(path.resolve(`${__dirname}/../../../../package.json`))).apiVersion;

let ad;
let authCode = Math.floor(Math.random() * 9999);
authCode = '0000'.substr(0, 4 - authCode.length) + authCode;

changeEvents.forEach((channel) => {
  PlaybackAPI.on(`change:${channel}`, (newValue) => {
    if (server && server.broadcast) {
      server.broadcast(channel === 'state' ? 'playState' : channel, newValue);
    }
  });
});

const settingsChangeEvents = ['themeColor', 'theme', 'themeType'];

settingsChangeEvents.forEach((channel) => {
  Settings.onChange(channel, (newValue) => {
    if (server && server.broadcast) {
      server.broadcast(`settings:${channel}`, newValue);
    }
  });
});

PlaybackAPI.on('change:time', (timeObj) => {
  if (server && server.broadcast) {
    if (JSON.stringify(timeObj) !== JSON.stringify(oldTime)) {
      oldTime = timeObj;
      server.broadcast('time', timeObj);
    }
  }
});

const requireCode = (ws) => {
  authCode = Math.floor(Math.random() * 9999).toString();
  authCode = '0000'.substr(0, 4 - authCode.length) + authCode;
  // DEV: Always be 000 when testing
  authCode = Settings.__TEST__ ? '0000' : authCode;
  Emitter.sendToWindowsOfName('main', 'show:code_controller', {
    authCode,
  });
  ws.json({
    channel: 'connect',
    payload: 'CODE_REQUIRED',
  });
};

const enableAPI = () => {
  let portOpen = true;
  if (process.platform === 'win32') {
    const testResult = spawnSync(
      'netsh',
      ['advfirewall', 'firewall', 'show', 'rule', 'name=GPMDP\ PlaybackAPI'] // eslint-disable-line
    );
    portOpen = testResult.status === 0;
  }
  if (!portOpen) {
    Emitter.once('openport:confirm', () => {
      runas(
        'netsh',
        [
          'advfirewall', 'firewall', 'add', 'rule', 'name=GPMDP\ PlaybackAPI', // eslint-disable-line
          'dir=in', 'action=allow', 'protocol=TCP', 'localport=5672',
        ],
        {
          admin: true,
        });
    });
    Emitter.sendToWindowsOfName('main', 'openport:request');
  }
  server = new WebSocketServer({
    host: process['env'].GPMDP_API_HOST || '0.0.0.0', // eslint-disable-line
    port: global.API_PORT || process['env'].GPMDP_API_PORT || 5672, // eslint-disable-line
  }, () => {
    if (ad) {
      ad.stop();
      ad = null;
    }

    try {
      ad = mdns.createAdvertisement(mdns.tcp('GPMDP'), global.API_PORT || process['env'].GPMDP_API_PORT || 5672, { // eslint-disable-line
        name: os.hostname(),
        txtRecord: {
          API_VERSION,
        },
      });

      ad.start();
    } catch (e) {
      Logger.error('Could not initialize bonjour service with error: %j', e);
    }
    if (ad) ad.on('error', () => {});

    server.broadcast = (channel, data) => {
      server.clients.forEach((client) => {
        client.channel(channel, data);
      });
    };

    server.on('connection', (websocket) => {
      const ws = websocket;

      ws.json = (obj) => {
        if (ws.readyState !== WebSocket.OPEN) return;
        ws.send(JSON.stringify(obj));
      };
      ws.channel = (channel, obj) => {
        ws.json({
          channel,
          payload: obj,
        });
      };

      ws.on('message', (data) => {
        try {
          const command = JSON.parse(data);
          if (command.namespace && command.method) {
            const args = command.arguments || [];
            // Attempt to handle client connectection and authorization
            if (command.namespace === 'connect' && command.method === 'connect') {
              if (Settings.get('authorized_devices', []).indexOf(args[1]) > -1) {
                Emitter.sendToGooglePlayMusic('register_controller', {
                  name: args[0],
                });
                ws.authorized = true;
              } else if (args[1] === authCode) {
                const code = uuid.v4();
                Settings.set('authorized_devices', Settings.get('authorized_devices', []).concat([code]));
                Emitter.sendToWindowsOfName('main', 'hide:code_controller');
                ws.json({
                  channel: 'connect',
                  payload: code,
                });
              } else {
                requireCode(ws);
              }
              return;
            }
            // Attempt to execute the globa magical controller
            if (!Array.isArray(args)) {
              throw Error('Bad arguments');
            }
            if (!ws.authorized) {
              requireCode(ws);
              return;
            }
            Emitter.sendToGooglePlayMusic('execute:gmusic', {
              namespace: command.namespace,
              method: command.method,
              requestID: command.requestID || uniqID,
              args,
            });
            if (typeof command.requestID !== 'undefined') {
              Emitter.once(`execute:gmusic:result_${command.requestID}`, (event, result) => {
                ws.json(result);
              });
            }
            uniqID = uuid.v4();
          } else {
            throw Error('Bad command');
          }
        } catch (err) {
          console.log(err);
          Logger.error('WebSocketAPI Error: Invalid message recieved', { err, data });
        }
      });

      // Send initial PlaybackAPI Values
      ws.channel('API_VERSION', API_VERSION);
      ws.channel('playState', PlaybackAPI.isPlaying());
      ws.channel('shuffle', PlaybackAPI.currentShuffle());
      ws.channel('repeat', PlaybackAPI.currentRepeat());
      ws.channel('queue', PlaybackAPI.getQueue());
      ws.channel('search-results', PlaybackAPI.getResults());
      ws.channel('volume', PlaybackAPI.getVolume());
      if (PlaybackAPI.currentSong(true)) {
        ws.channel('track', PlaybackAPI.currentSong(true));
        ws.channel('time', PlaybackAPI.currentTime());
        ws.channel('lyrics', PlaybackAPI.currentSongLyrics(true));
      }
      if (!Settings.__TEST__) {
        settingsChangeEvents.forEach((channel) => {
          ws.channel(`settings:${channel}`, Settings.get(channel));
        });
      }
      // We send library and playlists last as they take a while to stringify
      ws.channel('playlists', PlaybackAPI.getPlaylists());
      ws.channel('library', PlaybackAPI.getLibrary());
    });
  });

  server.on('error', () => {
    Emitter.sendToWindowsOfName('main', 'error', {
      title: 'Could not start Playback API',
      message: 'The playback API attempted (and failed) to start on port 5672.  Another application is probably using this port',  // eslint-disable-line
    });
    server = null;
  });
};

Emitter.on('playbackapi:toggle', (event, state) => {
  if (!state.state && server) {
    server.close();
    server = null;
  }
  if (state.state) {
    if (!server) {
      enableAPI();
    }
  } else if (ad) {
    ad.stop();
    ad = null;
  }
  Settings.set('playbackAPI', state.state);
});

app.on('will-quit', () => {
  if (server) {
    server.close();
    server = null;
  }
});

if (Settings.get('playbackAPI', false)) {
  enableAPI();
}
<commit_msg>Add inital GPMDP connect support<commit_after>import { app } from 'electron';
import fs from 'fs';
import os from 'os';
import path from 'path';
import uuid from 'uuid';
import { spawnSync } from 'child_process';
import WebSocket, { Server as WebSocketServer } from 'ws';

let server;
let oldTime = {};
let uniqID = uuid.v4();

let runas = () => {};
if (process.platform === 'win32') {
  runas = require('runas');
}

let mdns;
try {
  mdns = require('mdns');
} catch (e) {
  Logger.error('Failed to load bonjour with error: %j', e);
  console.error('Bonjour is required to use Chromecast Support or to enable ZeroConf for the PlaybackAPI'); // eslint-disable-line
  if (process.platform === 'win32') {
    console.error('On windows you need to install Bonjour Print Services'); // eslint-disable-line
  } else if (process.platform === 'darwin') {
    console.error('One macOS Bonjour should "just work" so if you see this you have much bigger problems'); // eslint-disable-line
  } else {
    console.error('On linux you need to install "avahi"'); // eslint-disable-line
  }
  if (process.platform === 'win32') {
    Emitter.sendToWindowsOfName('main', 'bonjour-install');
  }
}

const changeEvents = ['track', 'state', 'rating', 'lyrics', 'shuffle', 'repeat', 'playlists', 'queue', 'search-results', 'library', 'volume'];
const API_VERSION = JSON.parse(fs.readFileSync(path.resolve(`${__dirname}/../../../../package.json`))).apiVersion;

let ad;
let authCode = Math.floor(Math.random() * 9999);
authCode = '0000'.substr(0, 4 - authCode.length) + authCode;
let connectClient;
let connectClientShouldReconnect = true;

changeEvents.forEach((channel) => {
  PlaybackAPI.on(`change:${channel}`, (newValue) => {
    if (server && server.broadcast) {
      server.broadcast(channel === 'state' ? 'playState' : channel, newValue);
    }
    if (connectClient) {
      connectClient.channel(channel === 'state' ? 'playState' : channel, newValue);
    }
  });
});

const settingsChangeEvents = ['themeColor', 'theme', 'themeType'];

settingsChangeEvents.forEach((channel) => {
  Settings.onChange(channel, (newValue) => {
    if (server && server.broadcast) {
      server.broadcast(`settings:${channel}`, newValue);
    }
    if (connectClient) {
      connectClient.channel(`settings:${channel}`, newValue);
    }
  });
});

PlaybackAPI.on('change:time', (timeObj) => {
  if (JSON.stringify(timeObj) !== JSON.stringify(oldTime)) {
    oldTime = timeObj;
    if (server && server.broadcast) {
      server.broadcast('time', timeObj);
    }
    if (connectClient) {
      connectClient.channel('time', timeObj);
    }
  }
});

const requireCode = (ws) => {
  authCode = Math.floor(Math.random() * 9999).toString();
  authCode = '0000'.substr(0, 4 - authCode.length) + authCode;
  // DEV: Always be 000 when testing
  authCode = Settings.__TEST__ ? '0000' : authCode;
  Emitter.sendToWindowsOfName('main', 'show:code_controller', {
    authCode,
  });
  ws.json({
    channel: 'connect',
    payload: 'CODE_REQUIRED',
  });
};

const sendInitialBurst = (ws) => {
  ws.channel('API_VERSION', API_VERSION);
  ws.channel('playState', PlaybackAPI.isPlaying());
  ws.channel('shuffle', PlaybackAPI.currentShuffle());
  ws.channel('repeat', PlaybackAPI.currentRepeat());
  ws.channel('queue', PlaybackAPI.getQueue());
  ws.channel('search-results', PlaybackAPI.getResults());
  ws.channel('volume', PlaybackAPI.getVolume());
  if (PlaybackAPI.currentSong(true)) {
    ws.channel('track', PlaybackAPI.currentSong(true));
    ws.channel('time', PlaybackAPI.currentTime());
    ws.channel('lyrics', PlaybackAPI.currentSongLyrics(true));
  }
  if (!Settings.__TEST__) {
    settingsChangeEvents.forEach((channel) => {
      ws.channel(`settings:${channel}`, Settings.get(channel));
    });
  }
  // We send library and playlists last as they take a while to stringify
  ws.channel('playlists', PlaybackAPI.getPlaylists());
  ws.channel('library', PlaybackAPI.getLibrary());
};

const addWSPrototypes = (ws) => {
  ws.json = (obj) => { // eslint-disable-line
    if (ws.readyState !== WebSocket.OPEN) return;
    ws.send(JSON.stringify(obj));
  };
  ws.channel = (channel, obj) => { // eslint-disable-line
    ws.json({
      channel,
      payload: obj,
    });
  };
};

const handleWSMessage = (ws) =>
  (data) => {
    try {
      const command = JSON.parse(data);
      if (command.type === 'disconnect') {
        connectClientShouldReconnect = false;
      }
      if (command.namespace && command.method) {
        const args = command.arguments || [];
        // Attempt to handle client connectection and authorization
        if (command.namespace === 'connect' && command.method === 'connect') {
          if (Settings.get('authorized_devices', []).indexOf(args[1]) > -1) {
            Emitter.sendToGooglePlayMusic('register_controller', {
              name: args[0],
            });
            ws.authorized = true; // eslint-disable-line
          } else if (args[1] === authCode) {
            const code = uuid.v4();
            Settings.set('authorized_devices', Settings.get('authorized_devices', []).concat([code]));
            Emitter.sendToWindowsOfName('main', 'hide:code_controller');
            ws.json({
              channel: 'connect',
              payload: code,
            });
          } else {
            requireCode(ws);
          }
          return;
        }
        if (command.namespace === 'inital_burst') {
          sendInitialBurst(ws);
          return;
        }
        // Attempt to execute the globa magical controller
        if (!Array.isArray(args)) {
          throw Error('Bad arguments');
        }
        if (!ws.authorized) {
          requireCode(ws);
          return;
        }
        Emitter.sendToGooglePlayMusic('execute:gmusic', {
          namespace: command.namespace,
          method: command.method,
          requestID: command.requestID || uniqID,
          args,
        });
        if (typeof command.requestID !== 'undefined') {
          Emitter.once(`execute:gmusic:result_${command.requestID}`, (event, result) => {
            ws.json(result);
          });
        }
        uniqID = uuid.v4();
      } else {
        throw Error('Bad command');
      }
    } catch (err) {
      console.log(err);
      Logger.error('WebSocketAPI Error: Invalid message recieved', { err, data });
    }
  };

if (Settings.get('__gpmdp_connect__')) {
  const reconnectConnectClient = () => {
    connectClient = new WebSocket('wss://connect.gpmdp.xyz');
    addWSPrototypes(connectClient);
    connectClient.on('open', () => {
      connectClient.json({
        type: 'connect',
        email: 'samuel.r.attard@gmail.com',
        clientType: 'player',
      });
      connectClient.on('message', handleWSMessage(connectClient));
    });
    connectClient.on('error', () => {});
    connectClient.on('close', () => {
      if (connectClientShouldReconnect) {
        Logger.warn('Attempting to reconnect to connect.gpmdp.xyz');
        setTimeout(() => reconnectConnectClient(), 500);
      }
    });
  };
  reconnectConnectClient();
}

const enableAPI = () => {
  let portOpen = true;
  if (process.platform === 'win32') {
    const testResult = spawnSync(
      'netsh',
      ['advfirewall', 'firewall', 'show', 'rule', 'name=GPMDP\ PlaybackAPI'] // eslint-disable-line
    );
    portOpen = testResult.status === 0;
  }
  if (!portOpen) {
    Emitter.once('openport:confirm', () => {
      runas(
        'netsh',
        [
          'advfirewall', 'firewall', 'add', 'rule', 'name=GPMDP\ PlaybackAPI', // eslint-disable-line
          'dir=in', 'action=allow', 'protocol=TCP', 'localport=5672',
        ],
        {
          admin: true,
        });
    });
    Emitter.sendToWindowsOfName('main', 'openport:request');
  }
  server = new WebSocketServer({
    host: process['env'].GPMDP_API_HOST || '0.0.0.0', // eslint-disable-line
    port: global.API_PORT || process['env'].GPMDP_API_PORT || 5672, // eslint-disable-line
  }, () => {
    if (ad) {
      ad.stop();
      ad = null;
    }

    try {
      ad = mdns.createAdvertisement(mdns.tcp('GPMDP'), global.API_PORT || process['env'].GPMDP_API_PORT || 5672, { // eslint-disable-line
        name: os.hostname(),
        txtRecord: {
          API_VERSION,
        },
      });

      ad.start();
    } catch (e) {
      Logger.error('Could not initialize bonjour service with error: %j', e);
    }
    if (ad) ad.on('error', () => {});

    server.broadcast = (channel, data) => {
      server.clients.forEach((client) => {
        client.channel(channel, data);
      });
    };

    server.on('connection', (websocket) => {
      const ws = websocket;

      addWSPrototypes(ws);

      ws.on('message', handleWSMessage(ws));

      // Send initial PlaybackAPI Values
      sendInitialBurst(ws);
    });
  });

  server.on('error', () => {
    Emitter.sendToWindowsOfName('main', 'error', {
      title: 'Could not start Playback API',
      message: 'The playback API attempted (and failed) to start on port 5672.  Another application is probably using this port',  // eslint-disable-line
    });
    server = null;
  });
};

Emitter.on('playbackapi:toggle', (event, state) => {
  if (!state.state && server) {
    server.close();
    server = null;
  }
  if (state.state) {
    if (!server) {
      enableAPI();
    }
  } else if (ad) {
    ad.stop();
    ad = null;
  }
  Settings.set('playbackAPI', state.state);
});

app.on('will-quit', () => {
  if (server) {
    server.close();
    server = null;
  }
});

if (Settings.get('playbackAPI', false)) {
  enableAPI();
}
<|endoftext|>