<commit_before>var destination = document.getElementById("summary_destination").textContent;
console.log("Destination: " + destination);

var distancesObserver = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		for(var i = 0; i < mutation.addedNodes.length; i++)
		{
			var addedNode = mutation.addedNodes[i];
			if (addedNode.getAttribute("class") && addedNode.getAttribute("class").indexOf("distances") > -1)
			{
				var distancesNode = addedNode;
				console.log("Added distances node:");
				console.log(distancesNode);
				console.log("Tooltip data:");
				console.log(distancesNode.children[0].children[0].tooltipData);
			}
		}
	})
});

function ms2str(milliseconds)
{
	var ret = '';
	if(milliseconds) {
		milliseconds = parseInt( milliseconds / 1000 / 60);
		ret = milliseconds + ' min';
	} else {
		ret = '0 min';
	}

	return ret;
}

function injectResults(data)
{
	console.log(data);

	var hotelElement = document.getElementById(data.requestId);
	if(hotelElement) {
		var dists = hotelElement.getElementsByClassName('distances_centered');
		if(dists.length > 0) {
			var elem = dists[0];
			elem.innerHTML += '
' + data.numChanges + '
';
			elem.innerHTML += '
' + ms2str(data.travelDuration) + '
';
			elem.innerHTML += '
' + ms2str(data.walkDuration) + '
';
		}
	}
}

function callAPIFunction(address, hotelId)
{
	var now = new Date().getTime();
	var url = 'http://api.hotelroute.org/queryTripSummary?to=' + encodeURIComponent(destination) + '&from=' + encodeURIComponent(address) + '&startDate=' + now + '&endDate=' + now + '&requestId=' + hotelId;
//	console.log(url);

	var xhr = new XMLHttpRequest();
	xhr.open('GET', url, true);
	xhr.onload = function (e) {
		if (xhr.readyState === 4) {
			if (xhr.status === 200) {
				if( '' != xhr.responseText) {
					var response = JSON.parse(xhr.responseText);
					injectResults(response)
				}
//				scrapeHRSHotelAddress(xhr.responseText);
			} else {
//				console.error(xhr.statusText);
			}
		}
	};
	xhr.onerror = function (e) {
//		console.error(xhr.statusText);
	};
	xhr.send(null);
}

function scrapeHRSHotelAddress(html, hotelId)
{
	var div = document.createElement('div');
	div.innerHTML = html;

	var elements = div.getElementsByTagName('address');
	for(var i=0; i<elements.length; i++) {
		var address = elements[i];
		callAPIFunction(address.innerHTML, hotelId);
	}
}

function getHRSHotelAddress(hotelItem, hotelId)
{
	var url = 'http://www.hrs.de' + hotelItem;

	var xhr = new XMLHttpRequest();
	xhr.open('GET', url, true);
	xhr.onload = function (e) {
		if (xhr.readyState === 4) {
			if (xhr.status === 200) {
				scrapeHRSHotelAddress(xhr.responseText, hotelId);
			}
		}
	};
	xhr.send(null);
}

var hotelsObserver = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		for(var i = 0; i < mutation.addedNodes.length; i++)
		{
			var addedNode = mutation.addedNodes[i];
			if (addedNode.getAttribute("data-hpos"))
			{
				var hotelNode = addedNode;
				var hotelId = hotelNode.getAttribute("id");
				console.log("Added hotel with id [" + hotelId + "].");

				var hotelItem = hotelNode.getAttribute("data-hotelitemurl");
				getHRSHotelAddress(hotelItem,hotelId);

				distancesObserver.observe(hotelNode, { childList: true });
			}
		}
	})
});

var target = document.getElementById("containerAllHotels");

var config = { childList: true };

hotelsObserver.observe(target, config);
<commit_msg>show more icons<commit_after>var destination = document.getElementById("summary_destination").textContent;
console.log("Destination: " + destination);

var distancesObserver = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		for(var i = 0; i < mutation.addedNodes.length; i++)
		{
			var addedNode = mutation.addedNodes[i];
			if (addedNode.getAttribute("class") && addedNode.getAttribute("class").indexOf("distances") > -1)
			{
				var distancesNode = addedNode;
				console.log("Added distances node:");
				console.log(distancesNode);
				console.log("Tooltip data:");
				console.log(distancesNode.children[0].children[0].tooltipData);
			}
		}
	})
});

function ms2str(milliseconds)
{
	var ret = '';
	if(milliseconds) {
		milliseconds = parseInt( milliseconds / 1000 / 60);
		ret = milliseconds + ' min';
	} else {
		ret = '0 min';
	}

	return ret;
}

function injectResults(data)
{
	console.log(data);

	var hotelElement = document.getElementById(data.requestId);
	if(hotelElement) {
		var dists = hotelElement.getElementsByClassName('distances_centered');
		if(dists.length > 0) {
			var elem = dists[0];
			elem.innerHTML += '
' + ms2str(data.travelDuration) + '
';
			elem.innerHTML += '
' + ms2str(data.walkDuration) + '
';
			elem.innerHTML += '
' + data.numChanges + ' umst.
';
		}
	}
}

function callAPIFunction(address, hotelId)
{
	var now = new Date().getTime();
	var url = 'http://api.hotelroute.org/queryTripSummary?to=' + encodeURIComponent(destination) + '&from=' + encodeURIComponent(address) + '&startDate=' + now + '&endDate=' + now + '&requestId=' + hotelId;
//	console.log(url);

	var xhr = new XMLHttpRequest();
	xhr.open('GET', url, true);
	xhr.onload = function (e) {
		if (xhr.readyState === 4) {
			if (xhr.status === 200) {
				if( '' != xhr.responseText) {
					var response = JSON.parse(xhr.responseText);
					injectResults(response)
				}
//				scrapeHRSHotelAddress(xhr.responseText);
			} else {
//				console.error(xhr.statusText);
			}
		}
	};
	xhr.onerror = function (e) {
//		console.error(xhr.statusText);
	};
	xhr.send(null);
}

function scrapeHRSHotelAddress(html, hotelId)
{
	var div = document.createElement('div');
	div.innerHTML = html;

	var elements = div.getElementsByTagName('address');
	for(var i=0; i<elements.length; i++) {
		var address = elements[i];
		callAPIFunction(address.innerHTML, hotelId);
	}
}

function getHRSHotelAddress(hotelItem, hotelId)
{
	var url = 'http://www.hrs.de' + hotelItem;

	var xhr = new XMLHttpRequest();
	xhr.open('GET', url, true);
	xhr.onload = function (e) {
		if (xhr.readyState === 4) {
			if (xhr.status === 200) {
				scrapeHRSHotelAddress(xhr.responseText, hotelId);
			}
		}
	};
	xhr.send(null);
}

var hotelsObserver = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		for(var i = 0; i < mutation.addedNodes.length; i++)
		{
			var addedNode = mutation.addedNodes[i];
			if (addedNode.getAttribute("data-hpos"))
			{
				var hotelNode = addedNode;
				var hotelId = hotelNode.getAttribute("id");
//				console.log("Added hotel with id [" + hotelId + "].");

				var hotelItem = hotelNode.getAttribute("data-hotelitemurl");
				getHRSHotelAddress(hotelItem,hotelId);

				distancesObserver.observe(hotelNode, { childList: true });
			}
		}
	})
});

var target = document.getElementById("containerAllHotels");

var config = { childList: true };

hotelsObserver.observe(target, config);
<|endoftext|>


<commit_before>import initDebug from 'debug';

export const retryConfig = {
  retries: 12,
  minTimeout: 1000,
};

export const debug = initDebug('abw');

<commit_msg>test(retry): increase retries<commit_after>import initDebug from 'debug';

export const retryConfig = {
  retries: 20,
  minTimeout: 1000,
};

export const debug = initDebug('abw');

<|endoftext|>


<commit_before>module.exports = function (robot) {
    var client_id = process.env.GITHUB_APP_CLIENT_ID;
    var client_secret = process.env.GITHUB_APP_CLIENT_SECRET;
    var hostUrl = 'http://github.com/login/oauth/authorize';

    // Set the configuration settings
    const credentials = {
        client: {
            id: client_id,
            secret: client_secret
        },
        auth: {
            tokenHost: hostUrl
        }
    };

    // Initialize the OAuth2 Library
    const oauth2 = require('simple-oauth2').create(credentials);

    // Authorization oauth2 URI
    const authorizationUri = oauth2.authorizationCode.authorizeURL({
        redirect_uri: 'https://andreasbot.herokuapp.com/hubot/github-oauth',
        scope: 'repos',
        state: 'state'
    });

    // Redirect example using Express (see http://expressjs.com/api.html#res.redirect)
    robot.logger.info(authorizationUri);

    // Get the access token object (the authorization code is given from the previous step).
    const tokenConfig = {
        code: '<code>',
        redirect_uri: 'https://andreasbot.herokuapp.com/hubot/github-oauth'
    };

    // Callbacks
    // Save the access token
    oauth2.authorizationCode.getToken(tokenConfig, (error, result) => {
        if (error) {
            return robot.logger.error('Access Token Error', error.message);
        }

        const token = oauth2.accessToken.create(result);
        robot.logger.info(token);
    });

}<commit_msg>github oauth<commit_after>module.exports = function (robot) {
    var client_id = process.env.GITHUB_APP_CLIENT_ID;
    var client_secret = process.env.GITHUB_APP_CLIENT_SECRET;
    var hostUrl = 'http://github.com/login/oauth/authorize';

    // Set the configuration settings
    const credentials = {
        client: {
            id: client_id,
            secret: client_secret
        },
        auth: {
            tokenHost: hostUrl
        }
    };

    // Initialize the OAuth2 Library
    const oauth2 = require('simple-oauth2').create(credentials);

    // Authorization oauth2 URI
    const authorizationUri = oauth2.authorizationCode.authorizeURL({
        redirect_uri: 'https://andreasbot.herokuapp.com/hubot/github-oauth',
        scope: 'repos',
        state: 'state'
    });

    // Redirect example using Express (see http://expressjs.com/api.html#res.redirect)
    robot.logger.info(authorizationUri);

    // // Get the access token object (the authorization code is given from the previous step).
    // const tokenConfig = {
    //     code: '<code>',
    //     redirect_uri: 'https://andreasbot.herokuapp.com/hubot/github-oauth'
    // };

    // // Callbacks
    // // Save the access token
    // oauth2.authorizationCode.getToken(tokenConfig, (error, result) => {
    //     if (error) {
    //         return robot.logger.error('Access Token Error', error.message);
    //     }

    //     const token = oauth2.accessToken.create(result);
    //     robot.logger.info(token);
    // });

}<|endoftext|>


<commit_before>var _ = require('underscore'),
    async = require('async'),
    childProcess = require('child_process'),
    path = require('path');

module.exports = function(dir, callback) {
  childProcess.exec('find ' + dir + ' -name ".git"', function(err, stdout) {
    if (err) {
      return callback(err);
    }

    var files = stdout.split(/\n/g).map(path.dirname),
        repos = {};

    async.eachSeries(files, function(file, callback) {
        childProcess.exec('git fetch origin', {cwd: file}, function(err) {
          // Ignoring error for cases where there is no upstream.

          branchInfo(file, function(err, info) {
            if (err) {
              return callback(err);
            }

            if (/github\.com.*[:\/](.+)\/(.*)\.git$/.test(info.remote)) {
              info.name = RegExp.$1 + '/' + RegExp.$2;
            } else {
              info.name = file;
            }

            aheadBehind(info.remote, info.branch, file, function(err, aheadBehind) {
              if (err) {
                return callback(err);
              }

              _.extend(info, aheadBehind);

              localStatus(file, function(err, status) {
                if (err) {
                  return callback(err);
                }

                info.status = status;
                repos[info.name] = info;

                callback();
              });
            });
          });
        });
      },
      function(err) {
        callback(err, repos);
      });
  });
};

function branchInfo(path, callback) {
  childProcess.exec('git remote -v', {cwd: path}, function(err, remote) {
    if (err) {
      return callback(new Error('git.remote: ' + path + ' ' + err.message));
    }

    remote = (/origin\s+(.*) \(fetch\)/.exec(remote) || [])[1];

    childProcess.exec('git branch', {cwd: path}, function(err, branch) {
      if (err) {
        return callback(new Error('git.branch: ' + path + ' ' + err.message));
      }

      branch = (/\* (.*)/.exec(branch) || [])[1];
      if (branch === '(no branch)') {
        branch = undefined;
      }

      callback(undefined, {remote: remote, branch: branch});
    });
  });
}
function aheadBehind(remote, branch, path, callback) {
  if (!branch || !remote) {
    return callback(undefined, {});
  }

  childProcess.exec('git rev-list HEAD..origin/' + branch + ' --', {cwd: path}, function(err, behind) {
    if (err) {
      if (/bad revision/.test(err.message)) {
        return callback(undefined, {localBranch: true});
      } else {
        return callback(new Error('git.behind: ' + path + ' ' + err.message));
      }
    }

    behind = behind.split('\n').length - 1;

    childProcess.exec('git rev-list origin/' + branch + '..HEAD --', {cwd: path}, function(err, ahead) {
      if (err) {
        return callback(new Error('git.ahead: ' + path + ' ' + err.message));
      }

      ahead = ahead.split('\n').length - 1;
      callback(undefined, {ahead: ahead, behind: behind});
    });
  });
}

var STATUS_MAP = {
  'A': 'added',
  'M': 'modified',
  'D': 'deleted',
  'R': 'modified',
  'C': 'modified',
  '?': 'untracked',
  'U': 'modified'
};

function localStatus(path, callback) {
  childProcess.exec('git status --porcelain', {cwd: path}, function(err, stdout) {
    if (err) {
      return callback(new Error('git.status ' + path + ': ' + err.message));
    }

    var lines = stdout.trim().split('\n'),
        counter = {added: 0, modified: 0, deleted: 0, untracked: 0};

    lines = _.filter(lines, function(line) { return line; });
    _.each(lines, function(line) {
      var index = STATUS_MAP[line[0]],
          workDir = STATUS_MAP[line[1]],
          status = [index, workDir].sort();

      if (status[0]) {
        counter[status[0]]++;
      }
    });

    callback(undefined, counter);
  });
}
<commit_msg>Include path in local info<commit_after>var _ = require('underscore'),
    async = require('async'),
    childProcess = require('child_process'),
    path = require('path');

module.exports = function(dir, callback) {
  childProcess.exec('find ' + dir + ' -name ".git"', function(err, stdout) {
    if (err) {
      return callback(err);
    }

    var files = stdout.split(/\n/g).map(path.dirname),
        repos = {};

    async.eachSeries(files, function(file, callback) {
        childProcess.exec('git fetch origin', {cwd: file}, function(err) {
          // Ignoring error for cases where there is no upstream.

          branchInfo(file, function(err, info) {
            if (err) {
              return callback(err);
            }

            if (/github\.com.*[:\/](.+)\/(.*)\.git$/.test(info.remote)) {
              info.name = RegExp.$1 + '/' + RegExp.$2;
            } else {
              info.name = file;
            }

            aheadBehind(info.remote, info.branch, file, function(err, aheadBehind) {
              if (err) {
                return callback(err);
              }

              _.extend(info, aheadBehind);

              localStatus(file, function(err, status) {
                if (err) {
                  return callback(err);
                }

                info.path = file;
                info.status = status;
                repos[info.name] = info;

                callback();
              });
            });
          });
        });
      },
      function(err) {
        callback(err, repos);
      });
  });
};

function branchInfo(path, callback) {
  childProcess.exec('git remote -v', {cwd: path}, function(err, remote) {
    if (err) {
      return callback(new Error('git.remote: ' + path + ' ' + err.message));
    }

    remote = (/origin\s+(.*) \(fetch\)/.exec(remote) || [])[1];

    childProcess.exec('git branch', {cwd: path}, function(err, branch) {
      if (err) {
        return callback(new Error('git.branch: ' + path + ' ' + err.message));
      }

      branch = (/\* (.*)/.exec(branch) || [])[1];
      if (branch === '(no branch)') {
        branch = undefined;
      }

      callback(undefined, {remote: remote, branch: branch});
    });
  });
}
function aheadBehind(remote, branch, path, callback) {
  if (!branch || !remote) {
    return callback(undefined, {});
  }

  childProcess.exec('git rev-list HEAD..origin/' + branch + ' --', {cwd: path}, function(err, behind) {
    if (err) {
      if (/bad revision/.test(err.message)) {
        return callback(undefined, {localBranch: true});
      } else {
        return callback(new Error('git.behind: ' + path + ' ' + err.message));
      }
    }

    behind = behind.split('\n').length - 1;

    childProcess.exec('git rev-list origin/' + branch + '..HEAD --', {cwd: path}, function(err, ahead) {
      if (err) {
        return callback(new Error('git.ahead: ' + path + ' ' + err.message));
      }

      ahead = ahead.split('\n').length - 1;
      callback(undefined, {ahead: ahead, behind: behind});
    });
  });
}

var STATUS_MAP = {
  'A': 'added',
  'M': 'modified',
  'D': 'deleted',
  'R': 'modified',
  'C': 'modified',
  '?': 'untracked',
  'U': 'modified'
};

function localStatus(path, callback) {
  childProcess.exec('git status --porcelain', {cwd: path}, function(err, stdout) {
    if (err) {
      return callback(new Error('git.status ' + path + ': ' + err.message));
    }

    var lines = stdout.trim().split('\n'),
        counter = {added: 0, modified: 0, deleted: 0, untracked: 0};

    lines = _.filter(lines, function(line) { return line; });
    _.each(lines, function(line) {
      var index = STATUS_MAP[line[0]],
          workDir = STATUS_MAP[line[1]],
          status = [index, workDir].sort();

      if (status[0]) {
        counter[status[0]]++;
      }
    });

    callback(undefined, counter);
  });
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

var fs = require('fs');
var exec = require('child_process').exec;
var path = require('path');

// We have a copy of rimraf (v2.2.2), so that people can run this script without `npm install`.
var rimraf = require('./rimraf');

var isWin = !!process.platform.match(/^win/);

var pathTo = function(p) {
  return path.resolve(__dirname + '/../' + p);
};

var scriptPath = pathTo('node_modules/grunt-conventional-changelog/lib/validate-commit-msg.js');
var gitHookPath = pathTo('.git/hooks/commit-msg');

var gitHookSetup = function() {

  if (fs.existsSync(gitHookPath)) {
    fs.unlinkSync(gitHookPath);
    console.log('Existing link removed:', gitHookPath);
  }

  console.log('Adding symbolic link: %s linked to %s', scriptPath, gitHookPath);
  fs.symlinkSync(scriptPath, gitHookPath, 'file');
};

var installGruntCli = function(callback) {

  console.log('Installing grunt-cli...');

  var gcli = exec('npm install -g grunt-cli', function(error) {

    if (error !== null) {
      console.error('error installing grunt-cli: ' + error);
    } else {
      callback();
    }

  });

  gcli.stdout.pipe(process.stdout);
  gcli.stderr.pipe(process.stderr);

};

var checkForGruntCli = function(callback) {

  console.log('Checking for grunt-cli...');

  exec('grunt --version', function(error, stdout) {

    if (error) {
      installGruntCli(callback);
    } else {
      console.log('grunt-cli is already installed:');
      console.log(stdout);
      callback();
    }

  });
};

var installDependencies = function() {

  console.log('Installing dependencies...');

  var install = exec('npm install', function(error) {

    if (error !== null) {
      console.error('Error installing karma dependencies: ' + error);
    }

    // Remove the extra karma in node_modules/karma.
    // This is Karma from NPM, installed because plugins have Karma as a peer dependency and
    // at the same time, Karma uses a local instance if present and therefore running `karma`
    // in the working directory would cause using the Karma from NPM, rather than the Karma from
    // the working space.
    rimraf(pathTo('node_modules/karma'), function(err) {
      if (err) {
        console.error('Can not remove "' + pathTo('node_modules/karma') + '".\n' +
                      'Please remove it manually.');
      } else {
        console.log('YAY, YOUR WORKSPACE IS READY!');
      }
    });
  });

  install.stdout.pipe(process.stdout);
  install.stderr.pipe(process.stderr);

};

var runInit = function() {

  gitHookSetup();
  checkForGruntCli(function cb() {
    installDependencies();
  });

};

if (isWin) {

  exec('whoami /priv', function(err, o) {
    if (err || o.indexOf('SeCreateSymbolicLinkPrivilege') === -1) {
      console.log('You do not appear to have symlink privileges. Exiting init script.');
      console.log('Windows requires admin privileges to create symlinks.');
    } else {
      runInit();
    }
  });

} else {
  runInit();
}
<commit_msg>chore(scripts): init-dev-env.js will create .git/hooks<commit_after>#!/usr/bin/env node
'use strict';

var fs = require('fs');
var exec = require('child_process').exec;
var path = require('path');

// We have a copy of rimraf (v2.2.2), so that people can run this script without `npm install`.
var rimraf = require('./rimraf');

var isWin = !!process.platform.match(/^win/);

var pathTo = function(p) {
  return path.resolve(__dirname + '/../' + p);
};

var scriptPath = pathTo('node_modules/grunt-conventional-changelog/lib/validate-commit-msg.js');
var gitHookPath = pathTo('.git/hooks/commit-msg');

var gitHookSetup = function() {

  if (fs.existsSync(gitHookPath)) {
    fs.unlinkSync(gitHookPath);
    console.log('Existing link removed:', gitHookPath);
  }

  console.log('Adding symbolic link: %s linked to %s', scriptPath, gitHookPath);
  try {
    // "hooks" may not exist
    fs.mkdirSync(path.dirname(gitHookPath));
  } catch (e) {}
  fs.symlinkSync(scriptPath, gitHookPath, 'file');
};

var installGruntCli = function(callback) {

  console.log('Installing grunt-cli...');

  var gcli = exec('npm install -g grunt-cli', function(error) {

    if (error !== null) {
      console.error('error installing grunt-cli: ' + error);
    } else {
      callback();
    }

  });

  gcli.stdout.pipe(process.stdout);
  gcli.stderr.pipe(process.stderr);

};

var checkForGruntCli = function(callback) {

  console.log('Checking for grunt-cli...');

  exec('grunt --version', function(error, stdout) {

    if (error) {
      installGruntCli(callback);
    } else {
      console.log('grunt-cli is already installed:');
      console.log(stdout);
      callback();
    }

  });
};

var installDependencies = function() {

  console.log('Installing dependencies...');

  var install = exec('npm install', function(error) {

    if (error !== null) {
      console.error('Error installing karma dependencies: ' + error);
    }

    // Remove the extra karma in node_modules/karma.
    // This is Karma from NPM, installed because plugins have Karma as a peer dependency and
    // at the same time, Karma uses a local instance if present and therefore running `karma`
    // in the working directory would cause using the Karma from NPM, rather than the Karma from
    // the working space.
    rimraf(pathTo('node_modules/karma'), function(err) {
      if (err) {
        console.error('Can not remove "' + pathTo('node_modules/karma') + '".\n' +
                      'Please remove it manually.');
      } else {
        console.log('YAY, YOUR WORKSPACE IS READY!');
      }
    });
  });

  install.stdout.pipe(process.stdout);
  install.stderr.pipe(process.stderr);

};

var runInit = function() {

  gitHookSetup();
  checkForGruntCli(function cb() {
    installDependencies();
  });

};

if (isWin) {

  exec('whoami /priv', function(err, o) {
    if (err || o.indexOf('SeCreateSymbolicLinkPrivilege') === -1) {
      console.log('You do not appear to have symlink privileges. Exiting init script.');
      console.log('Windows requires admin privileges to create symlinks.');
    } else {
      runInit();
    }
  });

} else {
  runInit();
}
<|endoftext|>


<commit_before>var map = null
var statesLayerGroup = null

function displayShortInfo(unidade) {
  $('#unidade-short-info').text(unidade.nome_unidade)
}

function stripDiacritics(str) {
  // TODO: polyfill normalize? ignore?
  return str.normalize("NFKD").replace(/[\u0300-\u036F]/g, '').toLowerCase()
}

// Compares strings converting them to "canonical" form (replace dicritics)
function unidadeMatchesFilter(unidade, filter) {
  // TODO: add cidade and estado to filter check
  let content = unidade.nome_unidade + " " + unidade.uf + " ";
  content += unidade.municipio + " " + unidade.nome_logradouro + " ";
  content = stripDiacritics(content)
  if (content.indexOf(stripDiacritics(filter)) > -1) return true
  else return false
}

$(window).ready(function(){

  const delimiters = ['[[', ']]']

  Vue.component('perc-bar', {
    delimiters: delimiters,
    template: '#perc-bar-template',
    props: {
      // Percentual value
      'value': Number,
      // Label text
      'label': [String, Number],
      // Bar color
      'color': String,
      // If label should be positioned inside or outside the bar
      // Should be "inside", "outside" or a number
      // if a number, will position label inside if value > number
      // this is usefull for auto position based on bar size
      'labelPosition': {
        type: [String, Number],
        default: 30,
      }
    },
    computed: {
      labelInside: function () {
        if (this.labelPosition === 'inside') return true
        if (this.labelPosition === 'outside') return false
        if (this.value > this.labelPosition) return true
        return false
      }
    }
  })

  Vue.component('age-pyramid', {
    delimiters: delimiters,
    template: '#age-pyramid-template',
    props: ['data'],
  })

  Vue.component('detailed-info', {
    delimiters: delimiters,
    template: '#detailed-info-template',
    props: ['unidade'],
  })

  new Vue({
    delimiters: delimiters,
    el: '#map-vue-app',
    data: {
      // string used in map filtering
      filterStr: '',
      // selected unidade
      unidade: null,
      // if should show complete info about selected unidade
      showCompleteInfo: false,
    },
    methods: {
      createMap: function () {
        map = L.map('map').setView([-15, -50], 4)
	      L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', {
		      maxZoom: 18,
		      attribution: 'Map tiles by Carto, ' +
            'under CC BY 3.0. ' +
            'Data by OpenStreetMap, under ODbL.'
        }).addTo(map)

        statesLayerGroup = L.featureGroup().addTo(map).on('click', (marker) => this.unidade = marker.layer.unidade)

        this.plotMap()
      },
      plotMap: function () {
        var filter = this.filterStr
        var customIcon = L.icon({
          iconUrl: '/static/images/map/marker-icon.png',
          shadowUrl: '/static/images/map/marker-shadow.png',
          iconSize:    [25, 41],
		      iconAnchor:  [12, 41],
		      popupAnchor: [1, -34],
		      tooltipAnchor: [16, -28],
          shadowSize: [41, 41]
        })

        statesLayerGroup.clearLayers()
        $.each(states, function (uf, unidades) {
          var stateLayer = L.markerClusterGroup({
            // showCoverageOnHover: false,
            polygonOptions: {
              fillColor: 'grey',
              color: '#1b2557',
              weight: 0.0,
              opacity: 0,
              fillOpacity: 0.5
            }
          })
          var i = 0
          var markers = []
          for (let unidade of unidades) {
            if (filter && !unidadeMatchesFilter(unidade, filter)) continue
            var marker = L.marker([unidade.lat, unidade.lon], {icon: customIcon})
            marker.unidade = unidade
            markers.push(marker)
          }
          stateLayer.addLayers(markers)
          statesLayerGroup.addLayer(stateLayer)
        })
      },
      // Format used by mailto links
      formatMailto: function (email) {
        return 'mailto:' + email
      },
      // Format phone numbers with DDD
      formatFone: function (fone, ddd) {
        var foneStr = fone.toString()
        return '(' + ddd + ') ' + foneStr.slice(0,4) + ' ' + foneStr.slice(4)
      },
      formatAddress: function (unidade) {
        return unidade.tipo_logradouro +
          ' ' + unidade.nome_logradouro +
          (unidade.numero ? ', ' + unidade.numero : '') +
          (unidade.complemento ? ', ' + unidade.complemento : '') +
          ' - CEP: ' + unidade.cep.slice(0,-3) + '-' + unidade.cep.slice(-3) +
          ' - ' + unidade.municipio +
          ' - ' + unidade.uf
      },
      formatBool: value => value ? '✓' : '✘'
    },
    watch: {
      filterStr: function (a, b) {
        this.plotMap()
      }
    },
    mounted: function () {
      this.createMap()
    }
  })
})
<commit_msg>refac<commit_after>var map = null
var statesLayerGroup = null

function displayShortInfo(unidade) {
  $('#unidade-short-info').text(unidade.nome_unidade)
}

function stripDiacritics(str) {
  // TODO: polyfill normalize? ignore?
  return str.normalize("NFKD").replace(/[\u0300-\u036F]/g, '').toLowerCase()
}

// Compares strings converting them to "canonical" form (replace dicritics)
function unidadeMatchesFilter(unidade, filter) {
  // TODO: add cidade and estado to filter check
  let content = unidade.nome_unidade + " " + unidade.uf + " ";
  content += unidade.municipio + " " + unidade.nome_logradouro + " ";
  content = stripDiacritics(content)
  if (content.indexOf(stripDiacritics(filter)) > -1) return true
  else return false
}

$(window).ready(function(){

  const delimiters = ['[[', ']]']

  Vue.component('perc-bar', {
    delimiters: delimiters,
    template: '#perc-bar-template',
    props: {
      // Percentual value
      'value': Number,
      // Label text
      'label': [String, Number],
      // Bar color
      'color': String,
      // If label should be positioned inside or outside the bar
      // Should be "inside", "outside" or a number
      // if a number, will position label inside if value > number
      // this is usefull for auto position based on bar size
      'labelPosition': {
        type: [String, Number],
        default: 30,
      }
    },
    computed: {
      labelInside: function () {
        if (this.labelPosition === 'inside') return true
        if (this.labelPosition === 'outside') return false
        if (this.value > this.labelPosition) return true
        return false
      }
    }
  })

  Vue.component('age-pyramid', {
    delimiters: delimiters,
    template: '#age-pyramid-template',
    props: ['data'],
  })

  Vue.component('detailed-info', {
    delimiters: delimiters,
    template: '#detailed-info-template',
    props: ['unidade'],
  })

  new Vue({
    delimiters: delimiters,
    el: '#map-vue-app',
    data: {
      // string used in map filtering
      filterStr: '',
      // selected unidade
      unidade: null,
      // if should show complete info about selected unidade
      showCompleteInfo: false,
    },
    methods: {
      createMap: function () {
        map = L.map('map').setView([-15, -50], 4)
	      L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', {
		      maxZoom: 18,
		      attribution: 'Map tiles by Carto, ' +
            'under CC BY 3.0. ' +
            'Data by OpenStreetMap, under ODbL.'
        }).addTo(map)

        statesLayerGroup = L.featureGroup().addTo(map).on('click', (marker) => this.unidade = marker.layer.unidade)

        this.plotMap()
      },
      plotMap: function () {
        var filter = this.filterStr
        var customIcon = L.icon({
          iconUrl: '/static/images/map/marker-icon.png',
          shadowUrl: '/static/images/map/marker-shadow.png',
          iconSize: [25, 41],
          iconAnchor: [12, 41],
          popupAnchor: [1, -34],
          tooltipAnchor: [16, -28],
          shadowSize: [41, 41]
        })

        statesLayerGroup.clearLayers()
        $.each(states, function (uf, unidades) {
          var stateLayer = L.markerClusterGroup({
            // showCoverageOnHover: false,
            polygonOptions: {
              fillColor: 'grey',
              color: '#1b2557',
              weight: 0.0,
              opacity: 0,
              fillOpacity: 0.5
            }
          })
          var i = 0
          var markers = []
          for (let unidade of unidades) {
            if (filter && !unidadeMatchesFilter(unidade, filter)) continue
            var marker = L.marker([unidade.lat, unidade.lon], {icon: customIcon})
            marker.unidade = unidade
            markers.push(marker)
          }
          stateLayer.addLayers(markers)
          statesLayerGroup.addLayer(stateLayer)
        })
      },
      // Format used by mailto links
      formatMailto: function (email) {
        return 'mailto:' + email
      },
      // Format phone numbers with DDD
      formatFone: function (fone, ddd) {
        var foneStr = fone.toString()
        return '(' + ddd + ') ' + foneStr.slice(0,4) + ' ' + foneStr.slice(4)
      },
      formatAddress: function (unidade) {
        return unidade.tipo_logradouro +
          ' ' + unidade.nome_logradouro +
          (unidade.numero ? ', ' + unidade.numero : '') +
          (unidade.complemento ? ', ' + unidade.complemento : '') +
          ' - CEP: ' + unidade.cep.slice(0,-3) + '-' + unidade.cep.slice(-3) +
          ' - ' + unidade.municipio +
          ' - ' + unidade.uf
      },
      formatBool: value => value ? '✓' : '✘'
    },
    watch: {
      filterStr: function (a, b) {
        this.plotMap()
      }
    },
    mounted: function () {
      this.createMap()
    }
  })
})
<|endoftext|>


<commit_before>var msparp = (function() {

	// Character info
	function update_character(data) {
		if (typeof data["search_character"]!= "undefined") {
			$("select[name=search_character_id]").val(data["search_character"]["id"]);
		}
		$("#toggle_with_settings").prop("checked", true);
		$("input[name=name]").val(data["name"]);
		$("input[name=alias]").val(data["alias"]).keyup();
		$("input[name=color]").val("#"+data["color"]).change();
		if (typeof data["text_preview"]!= "undefined") {
			$("#text_preview").text(data["text_preview"]);
		} else if (typeof data["search_character"]!= "undefined") {
			$("#text_preview").text(data["search_character"]["text_preview"]);
		}
		if (data["quirk_prefix"] != "" || data["quirk_suffix"] != "" || data["case"] != "normal" || data["replacements"].length != 0 || data["regexes"].length != 0) {
			$("#toggle_typing_quirks").prop("checked", true);
		}
		$("input[name=quirk_prefix]").val(data["quirk_prefix"]);
		$("input[name=quirk_suffix]").val(data["quirk_suffix"]);
		$("select[name=case]").val(data["case"]);
		clear_replacements();
		if (data["replacements"].length == 0) {
			add_replacement();
		} else {
			data["replacements"].forEach(function(replacement) { add_replacement(null, replacement[0], replacement[1]); });
		}
		clear_regexes();
		if (data["regexes"].length == 0) {
			add_regex();
		} else {
			data["regexes"].forEach(function(regex) { add_regex(null, regex[0], regex[1]); });
		}
	}

	// Replacement list
	function delete_replacement(e) {
		$(this.parentNode).remove();
		return false;
	}
	function add_replacement(e, from, to) {
		new_item = $("
<input type=\"text\" name=\"quirk_from\" size=\"10\"> to <input type=\"text\" name=\"quirk_to\" size=\"10\"> <button type=\"button\" class=\"delete_replacement\">x</button>
");
		if (from && to) {
			var inputs = $(new_item).find('input');
			inputs[0].value = from;
			inputs[1].value = to;
		}
		$(new_item).find('.delete_replacement').click(delete_replacement);
		$(new_item).appendTo('#replacement_list');
		return false;
	}
	function clear_replacements(e) {
		$('#replacement_list').empty();
		return false;
	}

	// Regex list
	function delete_regex(e) {
		$(this.parentNode).remove();
		return false;
	}
	function add_regex(e, from, to) {
		new_item = $("
<input type=\"text\" name=\"regex_from\" size=\"10\"> to <input type=\"text\" name=\"regex_to\" size=\"10\"> <button type=\"button\" class=\"delete_regex\">x</button>
");
		if (from && to) {
			var inputs = $(new_item).find('input');
			inputs[0].value = from;
			inputs[1].value = to;
		}
		$(new_item).find('.delete_regex').click(delete_regex);
		$(new_item).appendTo('#regex_list');
		return false;
	}
	function clear_regexes(e) {
		$('#regex_list').empty();
		return false;
	}

	return {
		// Homepage
		"home": function() {

			// Saved character dropdown
			$("select[name=character_id]").change(function() {
				if (this.value != "") {
					$.get("/characters/"+this.value+".json", {}, update_character);
				}
			});

			// Search character dropdown
			$("select[name=search_character_id]").change(function() {
				$.get("/search_characters/"+this.value+".json", {}, update_character);
			});

			// Text preview
			var text_preview_container = $("#text_preview_container");
			var text_preview_alias = $("#text_preview_alias");
			$("input[name=alias]").keyup(function() {
				if (this.value == "") {
					text_preview_alias.text("");
				} else {
					text_preview_alias.text(this.value + ": ");
				}
			});
			$("input[name=color]").change(function() {
				text_preview_container.css("color", this.value);
			});

			// Replacement list
			$('.delete_replacement').click(delete_replacement);
			$('#add_replacement').click(add_replacement);
			$('#clear_replacements').click(clear_replacements);

			// Regex list
			$('.delete_regex').click(delete_regex);
			$('#add_regex').click(add_regex);
			$('#clear_regexes').click(clear_regexes);

			// Picky checkboxes
			$(".character_list legend input").click(function() {
				var group = $(this).parentsUntil(".toggle_box").last();
				group.find("li input").prop("checked", this.checked);
			});
			$(".character_list ul input").click(function() {
				var group = $(this).parentsUntil(".toggle_box").last();
				var group_input = group.find("legend input");
				var characters = group.find("li input");
				var checked_characters = group.find("li input:checked");
				if (checked_characters.length == 0) {
					group_input.prop("checked", false).prop("indeterminate", false);
				} else if (checked_characters.length == characters.length) {
					group_input.prop("checked", true).prop("indeterminate", false);
				} else {
					group_input.prop("checked", false).prop("indeterminate", true);
				}
			});

		},
		// Character search
		"search": function() {

			var searching = false;
			var searcher_id;

			function start_search() {
				if (!searching) {
					searching = true;
					$(document.body).addClass("searching");
					$.post("/search", {}, function(data) {
						searcher_id = data.id;
						continue_search();
					}).error(function() {
						searching = false;
						$(document.body).removeClass("searching").addClass("search_error");
					});
				}
			}

			function continue_search() {
				if (searching) {
					$.post("/search/continue", { "id": searcher_id }, function(data) {
						console.log(data);
						if (data.status == "matched") {
							searching = false;
							window.location.href = "/" + data.url;
						} else if (data.status == "quit") {
							searching = false;
						} else {
							continue_search();
						}
					}).error(function() {
						window.setTimeout(function() {
							searching = false;
							start_search();
						}, 2000);
					});
				}
			}

			function stop_search() {
				searching = false;
				$.ajax("/search/stop", { "type": "POST", data: { "id": searcher_id }, "async": false });
				$(document.body).removeClass("searching");
			}

			$(window).unload(function () {
				if (searching) {
					stop_search();
				}
			});

			start_search();

		},
		// Chat window
		"chat": function(chat, user, latest_message) {

			console.log(chat);
			console.log(user);
			console.log(latest_message);

			var conversation = $("#conversation");
			var status;
			var user_data = {};

			// Long polling
			function launch_long_poll() {
				$.post("/chat_api/messages", { "chat_id": chat.id, "after": latest_message }, receive_messages).complete(function(jqxhr, text_status) {
					if (status == "chatting") {
						if (jqxhr.status < 400 && text_status == "success") {
							launch_long_poll();
						} else {
							window.setTimeout(launch_long_poll, 2000);
							// XXX display a message if it still doesn't work after several attempts.
						}
					}
				});
			}

			// Ping loop
			function ping() {
				if (status == "chatting") {
					$.post("/chat_api/ping", { "chat_id": chat.id }).complete(function() { window.setTimeout(ping, 10000); });
				}
			}

			// Quitting
			window.onbeforeunload = function(e) {
				if (status == "chatting" && user.meta.confirm_disconnect) {
					if (typeof e != "undefined") { e.preventDefault(); }
					return "";
				}
			}
			$(window).unload(function() {
				if (status == "chatting") {
					status = "disconnected";
					$.ajax("/chat_api/quit", { "type": "POST", data: { "chat_id": chat.id }, "async": false});
				}
			});

			// Parsing and rendering messages
			function receive_messages(data) {
				if (typeof data.messages != "undefined" && data.messages.length != 0) { data.messages.forEach(render_message); }
				if (typeof data.users != "undefined") {
					user_list.html(user_list_template(data));
					user_list.find("li").click(render_action_list);
					// Store user data so we can look it up for action lists.
					for (var i = 0; i < data.users.length; i++) {
						user_data[data.users[i].meta.user_id] = data.users[i];
					}
				}
			}
			function render_message(message) {
				latest_message = message.id;
				var p = $("
").attr("id", "message_" + message.id);
				p.addClass("message_" + message.type + " user_" + message.user.id);
				p.css("color", "#" + message.color);
				if (message.type == "me") {
					p.text("* " + message.name + " " + message.text);
				} else if (message.alias != "") {
					p.text(message.alias + ": " + message.text);
				} else {
					p.text(message.text);
				}
				p.appendTo(conversation);
				conversation.scrollTop(conversation[0].scrollHeight);
			}

			// Sidebars
			$(".close").click(function() { $(this.parentNode).hide(); });

			// User list
			var user_list = $("#user_list");
			var user_list_template = Handlebars.compile($("#user_list_template").html());
			Handlebars.registerHelper("group_description", function(group) {
				return {
					"admin": "God tier moderator - MSPARP staff.",
					"creator": "Chat creator - can silence, kick and ban other users.",
					"mod": "Professional Wet Blanket - can silence, kick and ban other users.",
					"mod2": "Bum's Rusher - can silence and kick other users.",
					"mod3": "Amateur Gavel-Slinger - can silence other users.",
					"user": "",
					"silent": "Silenced.",
				}[group];
			});
			Handlebars.registerHelper("is_you", function() { return this.meta.user_id == user.meta.user_id; });

			// Action list
			var action_user;
			var action_list = $("#action_list");
			var action_list_template = Handlebars.compile($("#action_list_template").html());
			var ranks = { "admin": Infinity, "creator": Infinity, "mod": 4, "mod2": 3, "mod3": 2, "user": 1, "silent": 0 };
			function render_action_list() {
				action_user = user_data[parseInt(this.id.substr(5))];
				action_list.html(action_list_template(action_user));
				$("#action_mod, #action_mod2, #action_mod3, #action_user, #action_silent").click(set_group);
				action_list.find("li").click(function() { action_list.empty(); action_user = null; });
			}
			Handlebars.registerHelper("can_set_group", function(new_group, action_user) {
				console.log(new_group);
				// Don't bother if they're already this group.
				if (ranks[new_group] == ranks[this.meta.group]) { return false; }
				// You can't set groups at all if you're not a mod.
				if (ranks[user.meta.group] < 2) { return false; }
				// You can only set the group to one which is below yours.
				if (ranks[new_group] >= ranks[user.meta.group]) { return false; }
				// You can only set the group of people whose group is below yours.
				if (ranks[this.meta.group] >= ranks[user.meta.group]) { return false; }
				return true;
			});
			Handlebars.registerHelper("set_user_text", function() {
				if (this.meta.group == "silent") { return "Unsilence"; }
				return "Unmod";
			});
			function set_group() {
				$.post("/chat_api/set_group", { "chat_id": chat.id, "user_id": action_user.meta.user_id, "group": this.id.substr(7) });
			}

			// Send form
			var text_input = $("input[name=text]");
			var send_form = $("#send_form").submit(function() {
				var message_text = text_input.val().trim();
				if (message_text == "") { return false; }
				$.post("/chat_api/send", { "chat_id": chat.id, "text": message_text });
				text_input.val("");
				return false;
			});
			conversation.css("bottom", send_form.height() + 10 + "px");

			// Abscond/reconnect button
			var abscond_button = $("#abscond_button").click(function() {
				if (status == "chatting") {
					if (confirm("Are you sure you want to abscond?")) { disconnect(); }
				} else {
					// XXX make this search again in searched chats.
					connect();
				}
			});

			// Other buttons
			$("#chat_info_button").click(function() { $("#chat_info").show(); });

			// Connecting and disconnecting
			function connect() {
				status = "chatting";
				launch_long_poll();
				window.setTimeout(ping, 10000);
				$(document.body).addClass("chatting");
				conversation.scrollTop(conversation[0].scrollHeight);
				abscond_button.text("Abscond");
			}
			function disconnect() {
				status = "disconnected";
				$.ajax("/chat_api/quit", { "type": "POST", data: { "chat_id": chat.id }, "async": false});
				$(document.body).removeClass("chatting");
				abscond_button.text("Join");
			}

			// Now all that's done, let's connect
			connect();

		},
	};
})();
<commit_msg>Update send form to match user data.<commit_after>var msparp = (function() {

	// Character info
	function update_character(data) {
		if (typeof data["search_character"]!= "undefined") {
			$("select[name=search_character_id]").val(data["search_character"]["id"]);
		}
		$("#toggle_with_settings").prop("checked", true);
		$("input[name=name]").val(data["name"]);
		$("input[name=alias]").val(data["alias"]).keyup();
		$("input[name=color]").val("#"+data["color"]).change();
		if (typeof data["text_preview"]!= "undefined") {
			$("#text_preview").text(data["text_preview"]);
		} else if (typeof data["search_character"]!= "undefined") {
			$("#text_preview").text(data["search_character"]["text_preview"]);
		}
		if (data["quirk_prefix"] != "" || data["quirk_suffix"] != "" || data["case"] != "normal" || data["replacements"].length != 0 || data["regexes"].length != 0) {
			$("#toggle_typing_quirks").prop("checked", true);
		}
		$("input[name=quirk_prefix]").val(data["quirk_prefix"]);
		$("input[name=quirk_suffix]").val(data["quirk_suffix"]);
		$("select[name=case]").val(data["case"]);
		clear_replacements();
		if (data["replacements"].length == 0) {
			add_replacement();
		} else {
			data["replacements"].forEach(function(replacement) { add_replacement(null, replacement[0], replacement[1]); });
		}
		clear_regexes();
		if (data["regexes"].length == 0) {
			add_regex();
		} else {
			data["regexes"].forEach(function(regex) { add_regex(null, regex[0], regex[1]); });
		}
	}

	// Replacement list
	function delete_replacement(e) {
		$(this.parentNode).remove();
		return false;
	}
	function add_replacement(e, from, to) {
		new_item = $("
<input type=\"text\" name=\"quirk_from\" size=\"10\"> to <input type=\"text\" name=\"quirk_to\" size=\"10\"> <button type=\"button\" class=\"delete_replacement\">x</button>
");
		if (from && to) {
			var inputs = $(new_item).find('input');
			inputs[0].value = from;
			inputs[1].value = to;
		}
		$(new_item).find('.delete_replacement').click(delete_replacement);
		$(new_item).appendTo('#replacement_list');
		return false;
	}
	function clear_replacements(e) {
		$('#replacement_list').empty();
		return false;
	}

	// Regex list
	function delete_regex(e) {
		$(this.parentNode).remove();
		return false;
	}
	function add_regex(e, from, to) {
		new_item = $("
<input type=\"text\" name=\"regex_from\" size=\"10\"> to <input type=\"text\" name=\"regex_to\" size=\"10\"> <button type=\"button\" class=\"delete_regex\">x</button>
");
		if (from && to) {
			var inputs = $(new_item).find('input');
			inputs[0].value = from;
			inputs[1].value = to;
		}
		$(new_item).find('.delete_regex').click(delete_regex);
		$(new_item).appendTo('#regex_list');
		return false;
	}
	function clear_regexes(e) {
		$('#regex_list').empty();
		return false;
	}

	return {
		// Homepage
		"home": function() {

			// Saved character dropdown
			$("select[name=character_id]").change(function() {
				if (this.value != "") {
					$.get("/characters/"+this.value+".json", {}, update_character);
				}
			});

			// Search character dropdown
			$("select[name=search_character_id]").change(function() {
				$.get("/search_characters/"+this.value+".json", {}, update_character);
			});

			// Text preview
			var text_preview_container = $("#text_preview_container");
			var text_preview_alias = $("#text_preview_alias");
			$("input[name=alias]").keyup(function() {
				if (this.value == "") {
					text_preview_alias.text("");
				} else {
					text_preview_alias.text(this.value + ": ");
				}
			});
			$("input[name=color]").change(function() {
				text_preview_container.css("color", this.value);
			});

			// Replacement list
			$('.delete_replacement').click(delete_replacement);
			$('#add_replacement').click(add_replacement);
			$('#clear_replacements').click(clear_replacements);

			// Regex list
			$('.delete_regex').click(delete_regex);
			$('#add_regex').click(add_regex);
			$('#clear_regexes').click(clear_regexes);

			// Picky checkboxes
			$(".character_list legend input").click(function() {
				var group = $(this).parentsUntil(".toggle_box").last();
				group.find("li input").prop("checked", this.checked);
			});
			$(".character_list ul input").click(function() {
				var group = $(this).parentsUntil(".toggle_box").last();
				var group_input = group.find("legend input");
				var characters = group.find("li input");
				var checked_characters = group.find("li input:checked");
				if (checked_characters.length == 0) {
					group_input.prop("checked", false).prop("indeterminate", false);
				} else if (checked_characters.length == characters.length) {
					group_input.prop("checked", true).prop("indeterminate", false);
				} else {
					group_input.prop("checked", false).prop("indeterminate", true);
				}
			});

		},
		// Character search
		"search": function() {

			var searching = false;
			var searcher_id;

			function start_search() {
				if (!searching) {
					searching = true;
					$(document.body).addClass("searching");
					$.post("/search", {}, function(data) {
						searcher_id = data.id;
						continue_search();
					}).error(function() {
						searching = false;
						$(document.body).removeClass("searching").addClass("search_error");
					});
				}
			}

			function continue_search() {
				if (searching) {
					$.post("/search/continue", { "id": searcher_id }, function(data) {
						console.log(data);
						if (data.status == "matched") {
							searching = false;
							window.location.href = "/" + data.url;
						} else if (data.status == "quit") {
							searching = false;
						} else {
							continue_search();
						}
					}).error(function() {
						window.setTimeout(function() {
							searching = false;
							start_search();
						}, 2000);
					});
				}
			}

			function stop_search() {
				searching = false;
				$.ajax("/search/stop", { "type": "POST", data: { "id": searcher_id }, "async": false });
				$(document.body).removeClass("searching");
			}

			$(window).unload(function () {
				if (searching) {
					stop_search();
				}
			});

			start_search();

		},
		// Chat window
		"chat": function(chat, user, latest_message) {

			console.log(chat);
			console.log(user);
			console.log(latest_message);

			var conversation = $("#conversation");
			var status;
			var user_data = {};

			// Long polling
			function launch_long_poll() {
				$.post("/chat_api/messages", { "chat_id": chat.id, "after": latest_message }, receive_messages).complete(function(jqxhr, text_status) {
					if (status == "chatting") {
						if (jqxhr.status < 400 && text_status == "success") {
							launch_long_poll();
						} else {
							window.setTimeout(launch_long_poll, 2000);
							// XXX display a message if it still doesn't work after several attempts.
						}
					}
				});
			}

			// Ping loop
			function ping() {
				if (status == "chatting") {
					$.post("/chat_api/ping", { "chat_id": chat.id }).complete(function() { window.setTimeout(ping, 10000); });
				}
			}

			// Quitting
			window.onbeforeunload = function(e) {
				if (status == "chatting" && user.meta.confirm_disconnect) {
					if (typeof e != "undefined") { e.preventDefault(); }
					return "";
				}
			}
			$(window).unload(function() {
				if (status == "chatting") {
					status = "disconnected";
					$.ajax("/chat_api/quit", { "type": "POST", data: { "chat_id": chat.id }, "async": false});
				}
			});

			// Parsing and rendering messages
			function receive_messages(data) {
				if (typeof data.messages != "undefined" && data.messages.length != 0) { data.messages.forEach(render_message); }
				if (typeof data.users != "undefined") {
					user_list.html(user_list_template(data));
					user_list.find("li").click(render_action_list);
					// Store user data so we can look it up for action lists.
					// Also update our own user data.
					for (var i = 0; i < data.users.length; i++) {
						user_data[data.users[i].meta.user_id] = data.users[i];
						if (data.users[i].meta.user_id == user.meta.user_id) {
							user = data.users[i];
							text_input.css("color", "#" + user.character.color);
							if (user.meta.group == "silent") {
								text_input.prop("disabled", true);
								send_button.prop("disabled", true);
							} else {
								text_input.prop("disabled", false);
								send_button.prop("disabled", false);
							}
						}
					}
				}
			}
			function render_message(message) {
				latest_message = message.id;
				var p = $("
").attr("id", "message_" + message.id);
				p.addClass("message_" + message.type + " user_" + message.user.id);
				p.css("color", "#" + message.color);
				if (message.type == "me") {
					p.text("* " + message.name + " " + message.text);
				} else if (message.alias != "") {
					p.text(message.alias + ": " + message.text);
				} else {
					p.text(message.text);
				}
				p.appendTo(conversation);
				conversation.scrollTop(conversation[0].scrollHeight);
			}

			// Sidebars
			$(".close").click(function() { $(this.parentNode).hide(); });

			// User list
			var user_list = $("#user_list");
			var user_list_template = Handlebars.compile($("#user_list_template").html());
			Handlebars.registerHelper("group_description", function(group) {
				return {
					"admin": "God tier moderator - MSPARP staff.",
					"creator": "Chat creator - can silence, kick and ban other users.",
					"mod": "Professional Wet Blanket - can silence, kick and ban other users.",
					"mod2": "Bum's Rusher - can silence and kick other users.",
					"mod3": "Amateur Gavel-Slinger - can silence other users.",
					"user": "",
					"silent": "Silenced.",
				}[group];
			});
			Handlebars.registerHelper("is_you", function() { return this.meta.user_id == user.meta.user_id; });

			// Action list
			var action_user;
			var action_list = $("#action_list");
			var action_list_template = Handlebars.compile($("#action_list_template").html());
			var ranks = { "admin": Infinity, "creator": Infinity, "mod": 4, "mod2": 3, "mod3": 2, "user": 1, "silent": 0 };
			function render_action_list() {
				action_user = user_data[parseInt(this.id.substr(5))];
				action_list.html(action_list_template(action_user));
				$("#action_mod, #action_mod2, #action_mod3, #action_user, #action_silent").click(set_group);
				action_list.find("li").click(function() { action_list.empty(); action_user = null; });
			}
			Handlebars.registerHelper("can_set_group", function(new_group, action_user) {
				console.log(new_group);
				// Don't bother if they're already this group.
				if (ranks[new_group] == ranks[this.meta.group]) { return false; }
				// You can't set groups at all if you're not a mod.
				if (ranks[user.meta.group] < 2) { return false; }
				// You can only set the group to one which is below yours.
				if (ranks[new_group] >= ranks[user.meta.group]) { return false; }
				// You can only set the group of people whose group is below yours.
				if (ranks[this.meta.group] >= ranks[user.meta.group]) { return false; }
				return true;
			});
			Handlebars.registerHelper("set_user_text", function() {
				if (this.meta.group == "silent") { return "Unsilence"; }
				return "Unmod";
			});
			function set_group() {
				$.post("/chat_api/set_group", { "chat_id": chat.id, "user_id": action_user.meta.user_id, "group": this.id.substr(7) });
			}

			// Send form
			var text_input = $("input[name=text]");
			var send_form = $("#send_form").submit(function() {
				var message_text = text_input.val().trim();
				if (message_text == "") { return false; }
				$.post("/chat_api/send", { "chat_id": chat.id, "text": message_text });
				text_input.val("");
				return false;
			});
			var send_button = send_form.find("button[type=submit]");
			conversation.css("bottom", send_form.height() + 10 + "px");

			// Abscond/reconnect button
			var abscond_button = $("#abscond_button").click(function() {
				if (status == "chatting") {
					if (confirm("Are you sure you want to abscond?")) { disconnect(); }
				} else {
					// XXX make this search again in searched chats.
					connect();
				}
			});

			// Other buttons
			$("#chat_info_button").click(function() { $("#chat_info").show(); });

			// Connecting and disconnecting
			function connect() {
				status = "chatting";
				launch_long_poll();
				window.setTimeout(ping, 10000);
				$(document.body).addClass("chatting");
				conversation.scrollTop(conversation[0].scrollHeight);
				abscond_button.text("Abscond");
			}
			function disconnect() {
				status = "disconnected";
				$.ajax("/chat_api/quit", { "type": "POST", data: { "chat_id": chat.id }, "async": false});
				$(document.body).removeClass("chatting");
				abscond_button.text("Join");
			}

			// Now all that's done, let's connect
			connect();

		},
	};
})();
<|endoftext|>


<commit_before>/**
 * @fileOverview G2 3.0 最新主题
 */
const DEFAULT_COLOR = '#1890FF';
const COLOR_PLATE_8 = [ '#1890FF', '#2FC25B', '#FACC14', '#223273', '#8543E0', '#13C2C2', '#3436C7', '#F04864' ];
const COLOR_PLATE_16 = [ '#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#E6965C', '#223273', '#7564CC', '#8543E0',
  '#5C8EE6', '#13C2C2', '#5CA3E6', '#3436C7', '#B381E6', '#F04864', '#D598D9' ];
const COLOR_PLATE_24 = [ '#1890FF', '#66B5FF', '#41D9C7', '#2FC25B', '#6EDB8F', '#9AE65C', '#FACC14', '#E6965C',
  '#57AD71', '#223273', '#738AE6', '#7564CC', '#8543E0', '#A877ED', '#5C8EE6', '#13C2C2', '#70E0E0', '#5CA3E6',
  '#3436C7', '#8082FF', '#DD81E6', '#F04864', '#FA7D92', '#D598D9' ];
const COLOR_PIE = [ '#1890FF', '#13C2C2', '#2FC25B', '#FACC14', '#F04864', '#8543E0', '#3436C7', '#223273' ];
const COLOR_PIE_16 = [ '#1890FF', '#73C9E6', '#13C2C2', '#6CD9B3', '#2FC25B', '#9DD96C', '#FACC14', '#E6965C',
  '#F04864', '#D66BCA', '#8543E0', '#8E77ED', '#3436C7', '#737EE6', '#223273', '#7EA2E6' ];

const FONT_FAMILY = '"Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", SimSun, "sans-serif"';
// tooltip 相关 dom 的 css 类名
const TOOLTIP_CONTAINER_CLASS = 'g2-tooltip';
const TOOLTIP_TITLE_CLASS = 'g2-tooltip-title';
const TOOLTIP_LIST_CLASS = 'g2-tooltip-list';
const TOOLTIP_LIST_ITEM_CLASS = 'g2-tooltip-list-item';
const TOOLTIP_MARKER_CLASS = 'g2-tooltip-marker';

const Theme = {
  defaultColor: DEFAULT_COLOR, // 默认主题色
  plotCfg: {
    padding: [ 20, 20, 95, 80 ]
  },
  fontFamily: FONT_FAMILY,
  defaultLegendPosition: 'bottom', // 默认图例的展示位置
  colors: COLOR_PLATE_8,
  colors_16: COLOR_PLATE_16,
  colors_24: COLOR_PLATE_24,
  colors_pie: COLOR_PIE,
  colors_pie_16: COLOR_PIE_16,
  shapes: {
    point: [ 'hollowCircle', 'hollowSquare', 'hollowDiamond', 'hollowBowtie', 'hollowTriangle',
      'hollowHexagon', 'cross', 'tick', 'plus', 'hyphen', 'line' ],
    line: [ 'line', 'dash', 'dot' ],
    area: [ 'area' ]
  },
  markerRadius: 4,
  sizes: [ 1, 10 ],
  opacities: [ 0.1, 0.9 ],
  axis: {
    top: {
      // zIndex: 1, // 默认上下方向的坐标轴位于左右坐标轴的上方
      position: 'top',
      title: null,
      label: {
        offset: 14,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          lineHeight: 20,
          textBaseline: 'middle'
        },
        autoRotate: true
      },
      line: {
        lineWidth: 1,
        stroke: '#BFBFBF'
      },
      tickLine: {
        lineWidth: 1,
        stroke: '#BFBFBF',
        length: 4
      }
    },
    bottom: {
      position: 'bottom',
      title: null,
      label: {
        offset: 22,
        autoRotate: true,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          lineHeight: 20,
          textBaseline: 'middle'
        }
      },
      line: {
        lineWidth: 1,
        stroke: '#BFBFBF'
      },
      tickLine: {
        lineWidth: 1,
        stroke: '#BFBFBF',
        length: 4
      }
    },
    left: {
      position: 'left',
      title: null,
      label: {
        offset: 12,
        autoRotate: true,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          lineHeight: 20,
          textBaseline: 'middle'
        }
      },
      line: null,
      tickLine: null,
      grid: {
        lineStyle: {
          stroke: '#E9E9E9',
          lineWidth: 1,
          lineDash: [ 3, 3 ]
        },
        hideFirstLine: true
      }
    },
    right: {
      position: 'right',
      title: null,
      label: {
        offset: 12,
        autoRotate: true,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          lineHeight: 20,
          textBaseline: 'middle'
        }
      },
      line: null,
      tickLine: null,
      grid: {
        lineStyle: {
          stroke: '#E9E9E9',
          lineWidth: 1,
          lineDash: [ 3, 3 ]
        },
        hideFirstLine: true
      }
    },
    circle: {
      zIndex: 1,
      title: null,
      label: {
        offset: 12,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          lineHeight: 20
        }
      },
      line: {
        lineWidth: 1,
        stroke: '#BFBFBF'
      },
      tickLine: {
        lineWidth: 1,
        stroke: '#BFBFBF',
        length: 4
      },
      grid: {
        lineStyle: {
          stroke: '#E9E9E9',
          lineWidth: 1,
          lineDash: [ 3, 3 ]
        },
        hideFirstLine: true
      }
    },
    radius: {
      zIndex: 0,
      label: {
        offset: 12,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          textBaseline: 'middle',
          lineHeight: 20
        }
      },
      line: {
        lineWidth: 1,
        stroke: '#BFBFBF'
      },
      tickLine: {
        lineWidth: 1,
        stroke: '#BFBFBF',
        length: 4
      },
      grid: {
        lineStyle: {
          stroke: '#E9E9E9',
          lineWidth: 1,
          lineDash: [ 3, 3 ]
        },
        type: 'circle'
      }
    },
    helix: {
      grid: null,
      label: null,
      title: null,
      line: {
        lineWidth: 1,
        stroke: '#BFBFBF'
      },
      tickLine: {
        lineWidth: 1,
        length: 4,
        stroke: '#BFBFBF'
      }
    }
  },
  label: {
    offset: 20,
    textStyle: {
      fill: '#545454',
      fontSize: 12,
      textBaseline: 'middle'
    }
  },
  treemapLabels: {
    offset: 10,
    textStyle: {
      fill: '#fff',
      fontSize: 12,
      textBaseline: 'top',
      fontStyle: 'bold'
    }
  },
  innerLabels: {
    textStyle: {
      fill: '#fff',
      fontSize: 12,
      textBaseline: 'middle'
    }
  },
  // 在theta坐标系下的饼图文本内部的样式
  thetaLabels: {
    labelLine: {
      lineWidth: 1
    },
    labelHeight: 14,
    offset: 30
    // 在theta坐标系下的饼图文本的样式
  },
  legend: {
    right: {
      position: 'right',
      layout: 'vertical',
      itemMarginBottom: 8, // layout 为 vertical 时各个图例项的间距
      width: 16,
      height: 156,
      title: null,
      textStyle: {
        fill: '#8C8C8C',
        fontSize: 12,
        textAlign: 'start',
        textBaseline: 'middle',
        lineHeight: 20
      }, // 图例项文本的样式
      unCheckColor: '#bfbfbf'
    },
    left: {
      position: 'left',
      layout: 'vertical',
      itemMarginBottom: 8,
      width: 16,
      height: 156,
      title: null,
      textStyle: {
        fill: '#8C8C8C',
        fontSize: 12,
        textAlign: 'start',
        textBaseline: 'middle',
        lineHeight: 20
      }, // 图例项文本的样式
      unCheckColor: '#bfbfbf'
    },
    top: {
      position: 'top',
      offset: 6,
      layout: 'horizontal',
      title: null,
      itemGap: 10,
      width: 156,
      height: 16,
      textStyle: {
        fill: '#8C8C8C',
        fontSize: 12,
        textAlign: 'start',
        textBaseline: 'middle',
        lineHeight: 20
      }, // 图例项文本的样式
      unCheckColor: '#bfbfbf'
    },
    bottom: {
      position: 'bottom',
      offset: 58,
      layout: 'horizontal',
      title: null,
      itemGap: 24,
      width: 156,
      height: 16,
      textStyle: {
        fill: '#8C8C8C',
        fontSize: 12,
        textAlign: 'start',
        textBaseline: 'middle',
        lineHeight: 20
      }, // 图例项文本的样式
      unCheckColor: '#bfbfbf'
    }
  },
  tooltip: {
    crosshairs: false,
    offset: 15,
    // css style for tooltip
    [`${TOOLTIP_CONTAINER_CLASS}`]: {
      position: 'absolute',
      visibility: 'hidden',
      whiteSpace: 'nowrap',
      zIndex: 999,
      transition: 'visibility 0.2s cubic-bezier(0.23, 1, 0.32, 1), left 0.4s cubic-bezier(0.23, 1, 0.32, 1), top 0.4s cubic-bezier(0.23, 1, 0.32, 1)',
      backgroundColor: 'rgba(0, 0, 0, 0.65)',
      borderRadius: '4px',
      color: 'rgb(255, 255, 255)',
      fontSize: '12px',
      fontFamily: FONT_FAMILY,
      lineHeight: '20px',
      padding: '10px 10px 6px 10px'
    },
    [`${TOOLTIP_TITLE_CLASS}`]: {
      marginBottom: '4px'
    },
    [`${TOOLTIP_LIST_CLASS}`]: {
      margin: 0,
      listStyleType: 'none',
      padding: 0
    },
    [`${TOOLTIP_LIST_ITEM_CLASS}`]: {
      marginBottom: '4px'
    },
    [`${TOOLTIP_MARKER_CLASS}`]: {
      width: '7px',
      height: '7px',
      borderRadius: '50%',
      border: '1px solid #fff',
      display: 'inline-block',
      marginRight: '8px'
    }
  },
  tooltipMarker: {
    symbol: (x, y, r, ctx, color) => {
      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.arc(x, y, r, 0, Math.PI * 2, false);
      ctx.fill();

      ctx.save();
      ctx.beginPath();
      ctx.fillStyle = '#fff';
      ctx.strokeStyle = color;
      ctx.globalAlpha = 0.3;
      ctx.lineWidth = 4;
      ctx.arc(x, y, 7, 0, Math.PI * 2, false);
      ctx.stroke();
      ctx.restore();
    },
    radius: 4
  }, // 提示信息在折线图、区域图上形成点的样式
  tooltipCrosshairsRect: {
    type: 'rect',
    style: {
      fill: '#CCD6EC',
      opacity: 0.3
    }
  }, // tooltip 辅助背景框样式
  tooltipCrosshairsLine: {
    style: {
      stroke: 'rgba(0, 0, 0, 0.45)',
      lineWidth: 1
    }
  },
  shape: {
    point: {
      lineWidth: 1,
      fill: DEFAULT_COLOR,
      radius: 4,
      fillOpacity: 0.65
    },
    hollowPoint: {
      fill: '#fff',
      lineWidth: 1,
      stroke: DEFAULT_COLOR,
      radius: 3
    },
    interval: {
      lineWidth: 0,
      fill: DEFAULT_COLOR,
      fillOpacity: 0.85
    },
    pie: {
      lineWidth: 1,
      stroke: '#fff'
    },
    hollowInterval: {
      fill: '#fff',
      stroke: DEFAULT_COLOR,
      fillOpacity: 0,
      lineWidth: 1
    },
    area: {
      lineWidth: 0,
      fill: DEFAULT_COLOR,
      fillOpacity: 0.3
    },
    polygon: {
      lineWidth: 0,
      fill: DEFAULT_COLOR,
      fillOpacity: 1
    },
    hollowPolygon: {
      fill: '#fff',
      stroke: DEFAULT_COLOR,
      fillOpacity: 0,
      lineWidth: 1
    },
    hollowArea: {
      fill: '#fff',
      stroke: DEFAULT_COLOR,
      fillOpacity: 0,
      lineWidth: 1
    },
    line: {
      stroke: DEFAULT_COLOR,
      lineWidth: 1,
      fill: null
    }
  },
  guide: {
    line: {
      lineStyle: {
        stroke: DEFAULT_COLOR,
        lineDash: [ 0, 2, 2 ],
        lineWidth: 1
      },
      text: {
        position: 'end',
        autoRotate: true,
        style: {
          fill: '#545454',
          fontSize: 12,
          textAlign: 'center'
        }
      }
    },
    text: {
      style: {
        fill: '#545454',
        fontSize: 12,
        textBaseline: 'middle',
        textAlign: 'start'
      }
    },
    region: {
      style: {
        lineWidth: 0, // 辅助框的边框宽度
        fill: '#000', // 辅助框填充的颜色
        fillOpacity: 0.04 // 辅助框的背景透明度
      } // 辅助框的图形样式属性
    },
    html: {
      alignX: 'middle',
      alignY: 'middle'
    }
  },
  pixelRatio: null
};

module.exports = Theme;
<commit_msg>tooltipMarker 修改<commit_after>/**
 * @fileOverview G2 3.0 最新主题
 */
const DEFAULT_COLOR = '#1890FF';
const COLOR_PLATE_8 = [ '#1890FF', '#2FC25B', '#FACC14', '#223273', '#8543E0', '#13C2C2', '#3436C7', '#F04864' ];
const COLOR_PLATE_16 = [ '#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#E6965C', '#223273', '#7564CC', '#8543E0',
  '#5C8EE6', '#13C2C2', '#5CA3E6', '#3436C7', '#B381E6', '#F04864', '#D598D9' ];
const COLOR_PLATE_24 = [ '#1890FF', '#66B5FF', '#41D9C7', '#2FC25B', '#6EDB8F', '#9AE65C', '#FACC14', '#E6965C',
  '#57AD71', '#223273', '#738AE6', '#7564CC', '#8543E0', '#A877ED', '#5C8EE6', '#13C2C2', '#70E0E0', '#5CA3E6',
  '#3436C7', '#8082FF', '#DD81E6', '#F04864', '#FA7D92', '#D598D9' ];
const COLOR_PIE = [ '#1890FF', '#13C2C2', '#2FC25B', '#FACC14', '#F04864', '#8543E0', '#3436C7', '#223273' ];
const COLOR_PIE_16 = [ '#1890FF', '#73C9E6', '#13C2C2', '#6CD9B3', '#2FC25B', '#9DD96C', '#FACC14', '#E6965C',
  '#F04864', '#D66BCA', '#8543E0', '#8E77ED', '#3436C7', '#737EE6', '#223273', '#7EA2E6' ];

const FONT_FAMILY = '"Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", SimSun, "sans-serif"';
// tooltip 相关 dom 的 css 类名
const TOOLTIP_CONTAINER_CLASS = 'g2-tooltip';
const TOOLTIP_TITLE_CLASS = 'g2-tooltip-title';
const TOOLTIP_LIST_CLASS = 'g2-tooltip-list';
const TOOLTIP_LIST_ITEM_CLASS = 'g2-tooltip-list-item';
const TOOLTIP_MARKER_CLASS = 'g2-tooltip-marker';

const Theme = {
  defaultColor: DEFAULT_COLOR, // 默认主题色
  plotCfg: {
    padding: [ 20, 20, 95, 80 ]
  },
  fontFamily: FONT_FAMILY,
  defaultLegendPosition: 'bottom', // 默认图例的展示位置
  colors: COLOR_PLATE_8,
  colors_16: COLOR_PLATE_16,
  colors_24: COLOR_PLATE_24,
  colors_pie: COLOR_PIE,
  colors_pie_16: COLOR_PIE_16,
  shapes: {
    point: [ 'hollowCircle', 'hollowSquare', 'hollowDiamond', 'hollowBowtie', 'hollowTriangle',
      'hollowHexagon', 'cross', 'tick', 'plus', 'hyphen', 'line' ],
    line: [ 'line', 'dash', 'dot' ],
    area: [ 'area' ]
  },
  markerRadius: 4,
  sizes: [ 1, 10 ],
  opacities: [ 0.1, 0.9 ],
  axis: {
    top: {
      // zIndex: 1, // 默认上下方向的坐标轴位于左右坐标轴的上方
      position: 'top',
      title: null,
      label: {
        offset: 14,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          lineHeight: 20,
          textBaseline: 'middle'
        },
        autoRotate: true
      },
      line: {
        lineWidth: 1,
        stroke: '#BFBFBF'
      },
      tickLine: {
        lineWidth: 1,
        stroke: '#BFBFBF',
        length: 4
      }
    },
    bottom: {
      position: 'bottom',
      title: null,
      label: {
        offset: 22,
        autoRotate: true,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          lineHeight: 20,
          textBaseline: 'middle'
        }
      },
      line: {
        lineWidth: 1,
        stroke: '#BFBFBF'
      },
      tickLine: {
        lineWidth: 1,
        stroke: '#BFBFBF',
        length: 4
      }
    },
    left: {
      position: 'left',
      title: null,
      label: {
        offset: 12,
        autoRotate: true,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          lineHeight: 20,
          textBaseline: 'middle'
        }
      },
      line: null,
      tickLine: null,
      grid: {
        lineStyle: {
          stroke: '#E9E9E9',
          lineWidth: 1,
          lineDash: [ 3, 3 ]
        },
        hideFirstLine: true
      }
    },
    right: {
      position: 'right',
      title: null,
      label: {
        offset: 12,
        autoRotate: true,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          lineHeight: 20,
          textBaseline: 'middle'
        }
      },
      line: null,
      tickLine: null,
      grid: {
        lineStyle: {
          stroke: '#E9E9E9',
          lineWidth: 1,
          lineDash: [ 3, 3 ]
        },
        hideFirstLine: true
      }
    },
    circle: {
      zIndex: 1,
      title: null,
      label: {
        offset: 12,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          lineHeight: 20
        }
      },
      line: {
        lineWidth: 1,
        stroke: '#BFBFBF'
      },
      tickLine: {
        lineWidth: 1,
        stroke: '#BFBFBF',
        length: 4
      },
      grid: {
        lineStyle: {
          stroke: '#E9E9E9',
          lineWidth: 1,
          lineDash: [ 3, 3 ]
        },
        hideFirstLine: true
      }
    },
    radius: {
      zIndex: 0,
      label: {
        offset: 12,
        textStyle: {
          fill: '#545454',
          fontSize: 12,
          textBaseline: 'middle',
          lineHeight: 20
        }
      },
      line: {
        lineWidth: 1,
        stroke: '#BFBFBF'
      },
      tickLine: {
        lineWidth: 1,
        stroke: '#BFBFBF',
        length: 4
      },
      grid: {
        lineStyle: {
          stroke: '#E9E9E9',
          lineWidth: 1,
          lineDash: [ 3, 3 ]
        },
        type: 'circle'
      }
    },
    helix: {
      grid: null,
      label: null,
      title: null,
      line: {
        lineWidth: 1,
        stroke: '#BFBFBF'
      },
      tickLine: {
        lineWidth: 1,
        length: 4,
        stroke: '#BFBFBF'
      }
    }
  },
  label: {
    offset: 20,
    textStyle: {
      fill: '#545454',
      fontSize: 12,
      textBaseline: 'middle'
    }
  },
  treemapLabels: {
    offset: 10,
    textStyle: {
      fill: '#fff',
      fontSize: 12,
      textBaseline: 'top',
      fontStyle: 'bold'
    }
  },
  innerLabels: {
    textStyle: {
      fill: '#fff',
      fontSize: 12,
      textBaseline: 'middle'
    }
  },
  // 在theta坐标系下的饼图文本内部的样式
  thetaLabels: {
    labelLine: {
      lineWidth: 1
    },
    labelHeight: 14,
    offset: 30
    // 在theta坐标系下的饼图文本的样式
  },
  legend: {
    right: {
      position: 'right',
      layout: 'vertical',
      itemMarginBottom: 8, // layout 为 vertical 时各个图例项的间距
      width: 16,
      height: 156,
      title: null,
      textStyle: {
        fill: '#8C8C8C',
        fontSize: 12,
        textAlign: 'start',
        textBaseline: 'middle',
        lineHeight: 20
      }, // 图例项文本的样式
      unCheckColor: '#bfbfbf'
    },
    left: {
      position: 'left',
      layout: 'vertical',
      itemMarginBottom: 8,
      width: 16,
      height: 156,
      title: null,
      textStyle: {
        fill: '#8C8C8C',
        fontSize: 12,
        textAlign: 'start',
        textBaseline: 'middle',
        lineHeight: 20
      }, // 图例项文本的样式
      unCheckColor: '#bfbfbf'
    },
    top: {
      position: 'top',
      offset: 6,
      layout: 'horizontal',
      title: null,
      itemGap: 10,
      width: 156,
      height: 16,
      textStyle: {
        fill: '#8C8C8C',
        fontSize: 12,
        textAlign: 'start',
        textBaseline: 'middle',
        lineHeight: 20
      }, // 图例项文本的样式
      unCheckColor: '#bfbfbf'
    },
    bottom: {
      position: 'bottom',
      offset: 58,
      layout: 'horizontal',
      title: null,
      itemGap: 24,
      width: 156,
      height: 16,
      textStyle: {
        fill: '#8C8C8C',
        fontSize: 12,
        textAlign: 'start',
        textBaseline: 'middle',
        lineHeight: 20
      }, // 图例项文本的样式
      unCheckColor: '#bfbfbf'
    }
  },
  tooltip: {
    crosshairs: false,
    offset: 15,
    // css style for tooltip
    [`${TOOLTIP_CONTAINER_CLASS}`]: {
      position: 'absolute',
      visibility: 'hidden',
      whiteSpace: 'nowrap',
      zIndex: 999,
      transition: 'visibility 0.2s cubic-bezier(0.23, 1, 0.32, 1), left 0.4s cubic-bezier(0.23, 1, 0.32, 1), top 0.4s cubic-bezier(0.23, 1, 0.32, 1)',
      backgroundColor: 'rgba(0, 0, 0, 0.65)',
      borderRadius: '4px',
      color: 'rgb(255, 255, 255)',
      fontSize: '12px',
      fontFamily: FONT_FAMILY,
      lineHeight: '20px',
      padding: '10px 10px 6px 10px'
    },
    [`${TOOLTIP_TITLE_CLASS}`]: {
      marginBottom: '4px'
    },
    [`${TOOLTIP_LIST_CLASS}`]: {
      margin: 0,
      listStyleType: 'none',
      padding: 0
    },
    [`${TOOLTIP_LIST_ITEM_CLASS}`]: {
      marginBottom: '4px'
    },
    [`${TOOLTIP_MARKER_CLASS}`]: {
      width: '7px',
      height: '7px',
      borderRadius: '50%',
      border: '1px solid #fff',
      display: 'inline-block',
      marginRight: '8px'
    }
  },
  tooltipMarker: {
    symbol: (x, y, r, ctx, marker) => {
      const color = marker.get('color');
      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.arc(x, y, r, 0, Math.PI * 2, false);
      ctx.fill();

      ctx.save();
      ctx.beginPath();
      ctx.fillStyle = '#fff';
      ctx.strokeStyle = color;
      ctx.globalAlpha = 0.3;
      ctx.lineWidth = 4;
      ctx.arc(x, y, 7, 0, Math.PI * 2, false);
      ctx.stroke();
      ctx.restore();
    },
    radius: 4
  }, // 提示信息在折线图、区域图上形成点的样式
  tooltipCrosshairsRect: {
    type: 'rect',
    style: {
      fill: '#CCD6EC',
      opacity: 0.3
    }
  }, // tooltip 辅助背景框样式
  tooltipCrosshairsLine: {
    style: {
      stroke: 'rgba(0, 0, 0, 0.45)',
      lineWidth: 1
    }
  },
  shape: {
    point: {
      lineWidth: 1,
      fill: DEFAULT_COLOR,
      radius: 4,
      fillOpacity: 0.65
    },
    hollowPoint: {
      fill: '#fff',
      lineWidth: 1,
      stroke: DEFAULT_COLOR,
      radius: 3
    },
    interval: {
      lineWidth: 0,
      fill: DEFAULT_COLOR,
      fillOpacity: 0.85
    },
    pie: {
      lineWidth: 1,
      stroke: '#fff'
    },
    hollowInterval: {
      fill: '#fff',
      stroke: DEFAULT_COLOR,
      fillOpacity: 0,
      lineWidth: 1
    },
    area: {
      lineWidth: 0,
      fill: DEFAULT_COLOR,
      fillOpacity: 0.3
    },
    polygon: {
      lineWidth: 0,
      fill: DEFAULT_COLOR,
      fillOpacity: 1
    },
    hollowPolygon: {
      fill: '#fff',
      stroke: DEFAULT_COLOR,
      fillOpacity: 0,
      lineWidth: 1
    },
    hollowArea: {
      fill: '#fff',
      stroke: DEFAULT_COLOR,
      fillOpacity: 0,
      lineWidth: 1
    },
    line: {
      stroke: DEFAULT_COLOR,
      lineWidth: 1,
      fill: null
    }
  },
  guide: {
    line: {
      lineStyle: {
        stroke: DEFAULT_COLOR,
        lineDash: [ 0, 2, 2 ],
        lineWidth: 1
      },
      text: {
        position: 'end',
        autoRotate: true,
        style: {
          fill: '#545454',
          fontSize: 12,
          textAlign: 'center'
        }
      }
    },
    text: {
      style: {
        fill: '#545454',
        fontSize: 12,
        textBaseline: 'middle',
        textAlign: 'start'
      }
    },
    region: {
      style: {
        lineWidth: 0, // 辅助框的边框宽度
        fill: '#000', // 辅助框填充的颜色
        fillOpacity: 0.04 // 辅助框的背景透明度
      } // 辅助框的图形样式属性
    },
    html: {
      alignX: 'middle',
      alignY: 'middle'
    }
  },
  pixelRatio: null
};

module.exports = Theme;
<|endoftext|>