@ark-us/chat-manager
Version:
366 lines (352 loc) • 493 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var uint8arrays = require('uint8arrays');
var protons = require('protons');
var taylor = require('@ark-us/taylor');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var protons__default = /*#__PURE__*/_interopDefaultLegacy(protons);
var taylor__default = /*#__PURE__*/_interopDefaultLegacy(taylor);
// we do not include the block number, as this is set after comparing timestamps
// when each party includes it in his chain
const proto = `
message Message {
required string conversationId = 7;
required string sender = 2;
required int32 timestamp = 3;
required string type = 5;
required string data = 6;
}
message ConversationRoot {
required string lastRoot = 1;
required string messageId = 1;
}
message CummulativeRoot {
required string joined = 1;
}
`;
const messages = protons__default['default'](proto);
const EMPTY_ROOT = '0x0000000000000000000000000000000000000000000000000000000000000000';
async function hashFunction(databuf, encoding = 'hex') {
const hashbuf = await crypto.subtle.digest('SHA-256', databuf);
if (encoding === 'arraybuffer')
return hashbuf;
return uint8arrays.toString(new Uint8Array(hashbuf), 'base16');
}
async function messageHash(message, encoding) {
const databuf = messages.Message.encode({
receiver: message.receiver,
sender: message.sender,
timestamp: message.timestamp,
type: message.type,
data: JSON.stringify(message.data),
conversationId: message.conversationId,
});
return hashFunction(databuf, encoding);
}
async function conversationRoot(lastRoot, messageId, encoding) {
const databuf = messages.ConversationRoot.encode({ lastRoot, messageId });
return hashFunction(databuf, encoding);
}
async function chatRoot(roots, encoding) {
// <conversationId>:<root>
const orderedKeys = Object.keys(roots).sort();
const joined = orderedKeys.join('');
const databuf = messages.CummulativeRoot.encode({ joined });
return hashFunction(databuf, encoding);
}
async function getConversationId(identities) {
if (identities.length === 1)
return identities[0];
const joined = identities.sort().join('');
const databuf = messages.CummulativeRoot.encode({ joined });
const hash = await hashFunction(databuf, 'hex');
return hash;
}
async function messageAttachRoot(message, lastRoot) {
const hash = await messageHash(message);
if (!lastRoot) {
lastRoot = EMPTY_ROOT;
}
const root = await conversationRoot(lastRoot, hash);
return { hash, root };
}
// first root is the same
// two chains are ordered by timestamp
// find first root that is different
function highestCommonRoot(chain1, chain2, height = 0, delta = 16, same = true, changed = false, prevHeight = null) {
console.log('highestCommonRoot height, delta, same, changed, prevHeight', height, delta, same, changed, prevHeight);
if (!chain1[height] || !chain2[height]) {
console.debug('out of bounds');
const newHeight = Math.min(chain1.length, chain2.length) - 1;
const prevh = prevHeight ? prevHeight : 0;
const newdelta = Math.abs(newHeight - prevh) / 2;
return highestCommonRoot(chain1, chain2, newHeight, newdelta, false, true, height);
}
let newdelta;
if (changed)
newdelta = Math.ceil(delta / 2);
else
newdelta = delta * 2;
const _same = chain1[height].root === chain2[height].root;
// const sign = same && _same ? 1 : -1;
// const sign = (same ? 1 : -1) * (_same ? 1 : -1);
const getSign = (v) => v ? 1 : -1;
const sign = (same === _same) ? getSign(same) : getSign(!same);
console.log(`old same: ${same} ; new same: ${_same} ; sign: ${sign}`);
if (prevHeight !== null) {
const diff = Math.abs(prevHeight - height);
if (diff <= 1) {
console.debug('return area');
if (diff === 0) {
console.debug('diff 0');
if (_same)
return height;
if (same)
return prevHeight;
}
if (diff === 1) {
console.debug('diff 1');
if (_same)
return height;
if (same)
return prevHeight;
}
return null;
}
}
return highestCommonRoot(chain1, chain2, height + (sign * delta), newdelta, _same, changed, height);
}
function checkRace(orderedChain = [], rejected = {}, mutated = {}) {
for (let i = 0; i < orderedChain.length; i++) {
const item = orderedChain[i];
if (!item.data || !item.data.state)
continue;
if (item.rejected)
continue;
const hasRace = item.data.state.read.filter((state) => {
const key = state.typename + state.item.key;
if (mutated[key] && mutated[key].height > state.item.height)
return true;
return false;
});
item.data.state.mutated.some((state) => {
const key = state.typename + state.item.key;
if (!mutated[key] || mutated[key].height < state.item.height) {
mutated[key] = { height: state.item.height, index: i };
}
});
if (hasRace.length > 0) {
// Reject current block
rejected[i] = {
index: i,
block: item,
staterace: hasRace,
};
orderedChain[i].rejected = true;
// Reject blocks that provoked the race by changing the variable
hasRace.forEach((state) => {
const key = state.typename + state.item.key;
const mutatedBlockIndex = mutated[key].index;
rejected[mutatedBlockIndex] = {
index: mutatedBlockIndex,
block: orderedChain[mutatedBlockIndex],
staterace: [],
};
orderedChain[mutatedBlockIndex].rejected = true;
// dirty mutated for the variables that this block changed
orderedChain[mutatedBlockIndex].data.state.mutated.some((state) => {
const key = state.typename + state.item.key;
// set height as something heigher than possible, so it rejects any block using this variable
mutated[key] = { height: Infinity, index: mutatedBlockIndex };
});
});
// We return from the function!
return checkRace(orderedChain, rejected, mutated);
}
}
return { merged: orderedChain, rejected, mutated };
}
async function mergeChains(chain1, chain2, commonHeight = 0) {
const common = chain1.slice(0, commonHeight + 1);
const rest = chain1.slice(commonHeight + 1)
.concat(chain2.slice(commonHeight + 1))
.sort((a, b) => {
return (a.timestamp - b.timestamp) || (a.hash - b.hash);
});
// Check for state read-write race conditions
const { merged, rejected } = checkRace(rest);
const safeRest = merged.filter((item) => !item.rejected);
let lastRoot = common[commonHeight].root;
for (let item of safeRest) {
item = await messageAttachRoot(item, lastRoot);
lastRoot = item.root;
common.push(item);
}
return { merged: common, rejected: Object.values(rejected) };
}
// timestamp is treated as unique and the real id
function addBlockByTime(block, blocks) {
let isDuplicate = false;
if (!blocks || blocks.length === 0) {
block.id = 1;
return { blocks: [block], isDuplicate };
}
let index = blocks.length - 1;
while (blocks[index] && blocks[index].timestamp >= block.timestamp) {
index -= 1;
}
while (blocks[index] && blocks[index].timestamp == block.timestamp && blocks[index].hash > block.hash) {
index -= 1;
}
let newindex = index + 1;
if (blocks[newindex] && blocks[newindex].hash === block.hash) {
isDuplicate = true;
}
else {
blocks.splice(newindex, 0, block);
for (let i = newindex; i < blocks.length; i++) {
// Blocks start at 1
blocks[i].id = i + 1;
}
}
console.debug('isDuplicate', isDuplicate, block.id, block.timestamp);
return { blocks, isDuplicate };
}
const BASE = 'SIGWEB_messages_';
const MessageHandler = (prefix, persistence) => {
const _prefix = BASE + prefix + '_';
const handler = {
_lastBlocks: {},
_messages: {},
getLastBlock: (conversationId) => {
let block = handler._lastBlocks[conversationId];
if (block)
return block;
const blocks = handler.getAll(conversationId);
block = blocks[blocks.length - 1];
handler._lastBlocks[conversationId] = block;
return block;
},
getLastBlocks: (conversationId, count) => {
const all = handler.getAll(conversationId);
const startIndex = Math.max(0, all.length - count);
return all.slice(startIndex);
},
getAll: (conversationId) => {
let messages = handler._messages[conversationId];
if (!messages) {
messages = JSON.parse(persistence.getItem(_prefix + conversationId) || '[]');
handler._messages[conversationId] = messages;
}
return messages;
},
get: (conversationId, fields) => {
const messages = handler.getAll(conversationId);
return messages.filter((item) => {
return Object.keys(fields).every((key) => item[key] === fields[key]);
});
},
update: (conversationId, fields, update) => {
const messages = handler.getAll(conversationId);
const updated = [];
const newmessages = messages.map((item) => {
const ismatch = Object.keys(fields).every((key) => item[key] === fields[key]);
if (!ismatch)
return item;
const newitem = { ...item, ...update };
updated.push(newitem);
return newitem;
});
handler.setAll(conversationId, newmessages);
return updated;
},
setAll: (conversationId, messages) => {
handler._messages[conversationId] = messages;
persistence.setItem(_prefix + conversationId, JSON.stringify(messages));
},
set: (conversationId, message) => {
const messages = handler.getAll(conversationId);
const { blocks, isDuplicate } = addBlockByTime(message, messages);
if (isDuplicate) {
console.debug('Duplicate message', message.timestamp);
return false;
}
handler.setAll(conversationId, blocks);
handler._lastBlocks[conversationId] = message;
return message;
},
setActive: (conversationId) => persistence.setItem(_prefix + '_active', JSON.stringify(conversationId)),
getActive: () => {
const active = persistence.getItem(_prefix + '_active');
if (active)
return JSON.parse(active);
return active;
},
isDuplicate: (conversationId, message) => {
const messages = handler.getAll(conversationId);
const { isDuplicate } = addBlockByTime(message, messages);
return isDuplicate;
}
};
return handler;
};
var MessageStatus;
(function (MessageStatus) {
MessageStatus[MessageStatus["unsent"] = 0] = "unsent";
MessageStatus[MessageStatus["failed"] = 1] = "failed";
MessageStatus[MessageStatus["sending"] = 2] = "sending";
MessageStatus[MessageStatus["sent"] = 3] = "sent";
MessageStatus[MessageStatus["received"] = 4] = "received";
MessageStatus[MessageStatus["seen"] = 5] = "seen";
MessageStatus[MessageStatus["unknown"] = 16] = "unknown";
})(MessageStatus || (MessageStatus = {}));
var MessageType;
(function (MessageType) {
MessageType["message"] = "message";
MessageType["typing"] = "typing";
MessageType["sent"] = "sent";
MessageType["contact"] = "contact";
MessageType["delivery"] = "delivery";
MessageType["read"] = "read";
MessageType["execute"] = "execute";
MessageType["device"] = "device";
})(MessageType || (MessageType = {}));
// import Long from 'long';
function getTimestamp(timestamp) {
if (timestamp && typeof timestamp === 'number') {
return timestamp;
}
// // Signal
// if (typeof timestamp === 'object' && timestamp.low) {
// const longt = new Long(timestamp.low, timestamp.high, timestamp.unsigned);
// return longt.toNumber();
// }
return new Date().getTime();
}
function buildQuery(obj) {
let queries = [];
for (let key of Object.keys(obj)) {
const value = encodeURIComponent(typeof obj[key] === 'object' ? JSON.stringify(obj[key]) : obj[key]);
queries.push(`${key}=${value}`);
}
return queries.join('&');
}
function trimChars(str, chars = []) {
let result = str.trim();
for (let char of chars) {
result = result.replace(/^[/]*/, '');
result = result.replace(/[/]*$/, '');
}
return result;
}
var index = /*#__PURE__*/Object.freeze({
__proto__: null,
MessageHandler: MessageHandler,
get MessageStatus () { return MessageStatus; },
get MessageType () { return MessageType; },
getTimestamp: getTimestamp,
buildQuery: buildQuery,
trimChars: trimChars
});
var names = ['1959-barbie-pink', '1975-barbie-pink', '1990-barbie-pink', '1999-barbie-pink', '2004-barbie-pink', '2005-barbie-pink', 'absolute-zero', 'acajou', 'acid-green', 'aero', 'aero-blue', 'african-violet', 'raf-air-force-blue', 'usaf-air-force-blue', 'air-superiority-blue', 'alabama-crimson', 'alabaster', 'alice-blue', 'alizarin-crimson', 'alloy-orange', 'almond', 'aloeswood-brown', 'aloewood-color', 'aluminum', 'aluminum-foil', 'amaranth', 'amaranth-deep-purple', 'amaranth-pink', 'amaranth-purple', 'amaranth-red', 'amazon', 'amber', 'american-blue', 'american-bronze', 'american-brown', 'american-gold', 'american-green', 'american-orange', 'american-pink', 'american-purple', 'american-red', 'american-rose', 'american-silver', 'american-violet', 'american-yellow', 'amethyst', 'amur-cork-tree', 'anti-flash-white', 'antique-brass', 'antique-bronze', 'antique-fuchsia', 'antique-ruby', 'antique-white', 'ao', 'apple', 'apple-green', 'apricot', 'aqua-blue-color', 'aquamarine', 'arctic-lime', 'army-green', 'artichoke', 'arylide-yellow', 'asda-green', 'asda-orange', 'ash-gray', 'asparagus', 'ateneo-blue', 'atomic-tangerine', 'aureolin', 'avocado', 'awesome', 'axolotl', 'azure', 'azure-mist', 'azureish-white', 'bedazzled-blue', 'baby-blue', 'baby-blue-eyes', 'baby-pink', 'baby-powder', 'baiko-brown', 'baker-miller-pink', 'ball-blue', 'banana-mania', 'banana-yellow', 'bangladesh-green', 'barbie-pink', 'barn-red', 'battery-charged-blue', 'battleship-grey', 'bayside', 'bazaar', 'beau-blue', 'beaver', 'beer', 'begonia', 'beige', 'bellflower-color', 'betel-nut-dye', 'big-dip-o’ruby', 'big-foot-feet', 'birch-brown', 'bisque', 'bistre', 'bistre-brown', 'bitter-lemon', 'bitter-lime', 'bittersweet', 'bittersweet-shimmer', 'black', 'black-bean', 'black-chestnut-oak', 'black-chocolate', 'black-coffee', 'black-coral', 'black-kite', 'black-leather-jacket', 'black-olive', 'black-shadows', 'blanched-almond', 'blast-off-bronze', 'bleu-de-france', 'blizzard-blue', 'blond', 'blood', 'blood-orange', 'blood-red', 'blue', 'blue-bell', 'blue-black-crayfish', 'blue-bolt', 'blue-cola', 'blue-gray', 'blue-green', 'blue-jeans', 'blue-lagoon', 'blue-magenta-violet', 'blue-raspberry', 'blue-sapphire', 'blue-violet', 'blue-yonder', 'blueberry', 'bluebonnet', 'blush', 'bole', 'bondi-blue', 'bone', 'bored-accent-green', 'boy-red', 'boysenberry', 'brandeis-blue', 'brandy', 'brass', 'brave-orange', 'brewed-mustard-brown', 'brick-red', 'bright-gray', 'bright-green', 'bright-lavender', 'bright-lilac', 'bright-maroon', 'bright-navy-blue', 'bright-pink', 'bright-turquoise', 'bright-ube', 'bright-yellow', 'brilliant-azure', 'brilliant-lavender', 'brilliant-rose', 'brink-pink', 'british-racing-green', 'bronze', 'bronze-yellow', 'brown', 'brown-chocolate', 'brown-coffee', 'brown-nose', 'brown-rat-grey', 'brown-sugar', 'brown-yellow', 'brunswick-green', 'brushwood-dyed', 'bubble-gum', 'bubbles', 'bud-green', 'buff', 'bulgarian-rose', 'burgundy', 'burlywood', 'burnished-brown', 'burnt-orange', 'burnt-sienna', 'burnt-umber', 'button-blue', 'byzantine', 'byzantium', 'cadet', 'cadet-blue', 'cadet-grey', 'cadmium-blue', 'cadmium-green', 'cadmium-orange', 'cadmium-purple', 'cadmium-red', 'cadmium-violet', 'cadmium-yellow', 'café-au-lait', 'café-noir', 'calamansi', 'cambridge-blue', 'cameo-pink', 'camouflage-green', 'canary', 'canary-yellow', 'candy-apple-red', 'candy-pink', 'capri', 'caput-mortuum', 'caramel', 'cardinal', 'caribbean-blue', 'caribbean-green', 'carmine', 'carmine-pink', 'carmine-red', 'carnation-pink', 'carnelian', 'carolina-blue', 'carrot-orange', 'castleton-green', 'cat-blood', 'catalina-blue', 'catawba', 'cattail-color', 'cedar-chest', 'ceil', 'celadon', 'celadon-blue', 'celadon-color', 'celadon-green', 'celeste', 'celestial-blue', 'celtic-blue', 'cerise-pink', 'cerulean', 'cerulean-blue', 'cerulean-frost', 'cetacean-blue', 'cg-blue', 'cg-red', 'chamoisee', 'champagne-pink', 'charcoal', 'charleston-green', 'charm', 'charm-pink', 'chartreuse', 'cheese', 'cherry', 'cherry-blossom-color', 'cherry-blossom-mouse', 'cherry-blossom-pink', 'chestnut', 'chickadee', 'china-pink', 'china-rose', 'chinese-black', 'chinese-blue', 'chinese-bronze', 'chinese-brown', 'chinese-gold', 'chinese-green', 'chinese-orange', 'chinese-pink', 'chinese-purple', 'chinese-red', 'chinese-silver', 'chinese-violet', 'chinese-white', 'chinese-yellow', 'chlorophyll-green', 'chocolate-brown', 'chocolate-cosmos', 'chocolate-kisses', 'chrome-aluminum', 'chrome-yellow', 'cinereous', 'cinnamon', 'cinnamon-satin', 'citrine', 'citrine-brown', 'citron', 'claret', 'classic-rose', 'clove-brown', 'clove-dyed', 'coarse-wool-color', 'cobalt', 'cobalt-blue', 'coconut', 'coconut-white', 'coffee', 'cola', 'columbia-blue', 'conditioner', 'congo-pink', 'cookies-and-cream', 'cool-black', 'cool-grey', 'copper', 'copper-penny', 'copper-red', 'copper-rose', 'coquelicot', 'coral', 'coral-color', 'coral-red', 'coral-reef', 'cordovan', 'corn-colored', 'cornflower', 'cornflower-blue', 'cornsilk', 'cosmic-cobalt', 'cosmic-latte', 'cotton-candy', 'coyote-brown', 'crayola-blue', 'crayola-blue-violet', 'crayola-brown', 'crayola-cadet-blue', 'crayola-copper', 'cream', 'crimson', 'crimson-glory', 'crimson-red', 'crystal', 'crystal-blue', 'cultured', 'cyan-azure', 'cyan-blue-azure', 'cyan-cobalt-blue', 'cyan-cornflower-blue', 'cyan-process', 'cyber-grape', 'cyber-yellow', 'cyclamen', 'cypress-bark-color', 'cypress-bark-red', 'daffodil', 'dandelion', 'dark-blue', 'dark-blue-gray', 'dark-blue-kon', 'dark-bronze', 'dark-brown', 'dark-brown-tangelo', 'dark-byzantium', 'dark-candy-apple-red', 'dark-cerulean', 'dark-charcoal', 'dark-chestnut', 'dark-chocolate', 'dark-coral', 'dark-cornflower-blue', 'dark-cyan', 'dark-electric-blue', 'dark-gold', 'dark-goldenrod', 'dark-gray', 'dark-green', 'dark-gunmetal', 'dark-imperial-blue', 'dark-indigo', 'dark-jungle-green', 'dark-khaki', 'dark-lava', 'dark-lavender', 'dark-lemon-lime', 'dark-liver', 'dark-magenta', 'dark-midnight-blue', 'dark-moss-green', 'dark-navy', 'dark-olive-green', 'dark-orange', 'dark-orchid', 'dark-pastel-blue', 'dark-pastel-green', 'dark-pastel-purple', 'dark-pastel-red', 'dark-pink', 'dark-powder-blue', 'dark-puce', 'dark-purple', 'dark-raspberry', 'dark-red', 'dark-salmon', 'dark-scarlet', 'dark-sea-green', 'dark-sienna', 'dark-silver', 'dark-sky-blue', 'dark-slate-blue', 'dark-slate-gray', 'dark-spring-green', 'dark-tan', 'dark-tangerine', 'dark-terra-cotta', 'dark-turquoise', 'dark-vanilla', 'dark-violet', 'dark-yellow', 'dartmouth-green', 'davys-grey', 'dawn-color', 'daylily-colored', 'debian-red', 'deep-amethyst', 'deep-aquamarine', 'deep-carmine', 'deep-carmine-pink', 'deep-carrot-orange', 'deep-cerise', 'deep-champagne', 'deep-chestnut', 'deep-coffee', 'deep-dumpling', 'deep-fuchsia', 'deep-green', 'deep-jungle-green', 'deep-koamaru', 'deep-lemon', 'deep-lilac', 'deep-magenta', 'deep-maroon', 'deep-mauve', 'deep-moss-green', 'deep-peach', 'deep-pink', 'deep-puce', 'deep-purple', 'deep-red', 'deep-ruby', 'deep-saffron', 'deep-scarlet', 'deep-space-sparkle', 'deep-taupe', 'deep-tuscan-red', 'deep-violet', 'deer', 'delicate-girl-blue', 'denim', 'denim-blue', 'desaturated-cyan', 'desert-sand', 'desire', 'diamond', 'dim-gray', 'dingy-dungeon', 'dirt', 'dirty-brown', 'dirty-white', 'disappearing-purple', 'dodger-blue', 'dodie-yellow', 'dogwood-rose', 'dollar-bill', 'dolphin-gray', 'douban-blue', 'douban-green', 'douban-light-yellow', 'dove-feather-grey', 'drab', 'duke-blue', 'dull-blue', 'durian', 'durian-white', 'durian-yellow', 'dust-storm', 'dutch-white', 'dyestalk-red', 'earth-yellow', 'earthen-yellow', 'earthtone', 'ebicha', 'ebony', 'eerie-black', 'egg-colored', 'eggplant', 'eggshell', 'egyptian-blue', 'elderberry', 'electric-blue', 'electric-brown', 'electric-crimson', 'electric-green', 'electric-indigo', 'electric-lime', 'electric-orange', 'electric-pink', 'electric-purple', 'electric-red', 'electric-ultramarine', 'electric-violet', 'electric-yellow', 'emerald', 'emerald-green', 'eminence', 'english-ao', 'english-lavender', 'english-red', 'english-vermillion', 'english-violet', 'eton-blue', 'eucalyptus', 'facebook-blue', 'fake-purple', 'falu-red', 'fandango', 'fandango-pink', 'fashion-fuchsia', 'fawn', 'feldgrau', 'feldspar', 'fern', 'fern-green', 'ferrari-red', 'field-drab', 'fiery-rose', 'finch-brown', 'fire-engine-red', 'fire-opal', 'firebrick', 'flame', 'flamingo-pink', 'flavescent', 'flax', 'flesh', 'flickr-blue', 'flickr-pink', 'flirt', 'floral-leaf-colored', 'floral-white', 'flower-girl', 'fluorescent-blue', 'folly', 'foreign-crimson', 'forest-green', 'forest-green-crayola', 'forest-green-trad', 'fox-color', 'french-bistre', 'french-blue', 'french-fuchsia', 'french-lilac', 'french-lime', 'french-pink', 'french-plum', 'french-puce', 'french-raspberry', 'french-rose', 'french-sky-blue', 'french-violet', 'french-wine', 'fresh-air', 'fresh-onion', 'frostbite', 'fuchsia-pink', 'fuchsia-purple', 'fuchsia-rose', 'fulvous', 'fuzzy-wuzzy', 'gainsboro', 'gamboge', 'gamboge-orange', 'gargoyle-gas', 'garnet', 'generic-viridian', 'ghost-white', 'giants-club', 'giants-orange', 'gin', 'ginger', 'glaucous', 'glazed-persimmon', 'glitter', 'glossy-grape', 'go-green', 'gold-brown', 'gold-crayola', 'gold-foil', 'gold-fusion', 'golden', 'golden-brown', 'golden-fallen-leaves', 'golden-grey-bamboo', 'golden-oak', 'golden-poppy', 'golden-yellow', 'goldenrod', 'google-chrome-blue', 'google-chrome-green', 'google-chrome-red', 'google-chrome-yellow', 'goryeo-storeroom', 'granite-gray', 'granny-smith-apple', 'grape', 'grape-mouse', 'gray', 'gray-x11', 'green', 'green-bamboo-color', 'green-blue', 'green-cola', 'green-crayola', 'green-cyan', 'green-lizard', 'green-midori', 'green-munsell', 'green-ncs', 'green-pantone', 'green-pigment', 'green-ryb', 'green-sheen', 'green-slime', 'green-tea-colored', 'green-yellow', 'greenfinch-color', 'greyed-red', 'greyish-dark-green', 'grullo', 'gunmetal', 'guppie-green', 'guyabano', 'halaya-ube', 'half-color', 'halloween-orange', 'han-blue', 'han-purple', 'harbor-rat', 'harlequin', 'harlequin-green', 'harmonious-rose', 'harvest-gold', 'hawaii-blue', 'heart-gold', 'heat-wave', 'heliotrope', 'heliotrope-gray', 'heliotrope-magenta', 'honeydew', 'honolulu-blue', 'hookers-green', 'horsetail-color', 'hot-magenta', 'hot-pink', 'huawei-red', 'ibis-wing-color', 'iceberg', 'iced-tea', 'icterine', 'iguana-green', 'illuminating-emerald', 'imperial', 'imperial-blue', 'imperial-purple', 'imperial-red', 'inchworm', 'independence', 'india-green', 'indian-red', 'indian-yellow', 'indigo', 'indigo-dye', 'indigo-ink-brown', 'indigo-rainbow', 'indigo-white', 'infra-red', 'ink-color', 'insect-screen', 'inside-of-a-bottle', 'international-orange', 'iris', 'iris-color', 'iron', 'iron-color', 'iron-storage', 'isabelline', 'islamic-green', 'italian-ice', 'italian-leather', 'italian-roast', 'ivory', 'iwai-brown', 'jacarta', 'jacko-bean', 'jade', 'japanese-carmine', 'japanese-indigo', 'japanese-laurel', 'japanese-violet', 'jasmine', 'jasper', 'jasper-orange', 'jazzberry-jam', 'jelly-bean', 'jelly-bean-blue', 'jet', 'jet-stream', 'jonquil', 'jordy-blue', 'june-bud', 'jungle-green', 'kelly-green', 'kenyan-copper', 'keppel', 'key-lime', 'khaki', 'kimono-storage', 'kiwi', 'kobi', 'kohaku-iro-amber', 'kokushoku-black', 'kombu-green', 'ksu-purple', 'ku-crimson', 'kumquat', 'languid-lavender', 'lanzones', 'lapis-lazuli', 'lapis-lazuli-color', 'laser-lemon', 'laurel-green', 'lava', 'lavender', 'lavender-blue', 'lavender-blush', 'lavender-gray', 'lavender-indigo', 'lavender-magenta', 'lavender-mist', 'lavender-pink', 'lavender-purple', 'lavender-rose', 'lawn-green', 'legal-dye', 'lemon', 'lemon-chiffon', 'lemon-curry', 'lemon-glacier', 'lemon-iced-tea', 'lemon-lime', 'lemon-limey', 'lemon-meringue', 'lemon-yellow', 'lenurple', 'liberty', 'licorice', 'light-blue', 'light-blue-color', 'light-blue-flower', 'light-blue-silk', 'light-brown', 'light-carmine-pink', 'light-cobalt-blue', 'light-coral', 'light-crimson', 'light-cyan', 'light-deep-pink', 'light-french-beige', 'light-fuchsia-pink', 'light-gold', 'light-gray', 'light-green', 'light-hot-pink', 'light-khaki', 'light-magenta', 'light-medium-orchid', 'light-moss-green', 'light-orange', 'light-orchid', 'light-pastel-purple', 'light-periwinkle', 'light-pink', 'light-red', 'light-salmon', 'light-salmon-pink', 'light-sea-green', 'light-silver', 'light-sky-blue', 'light-slate-gray', 'light-steel-blue', 'light-taupe', 'light-yellow', 'lilac', 'lilac-luster', 'lime', 'lime-green', 'lime-pulp', 'limerick', 'lincoln-green', 'linen', 'linkedin-blue', 'lion', 'little-boy-blue', 'little-girl-pink', 'liver', 'liver-chestnut', 'liver-dog', 'long-spring', 'loquat-brown', 'lotion', 'lotion-blue', 'lotion-pink', 'lumber', 'lust', 'lychee', 'lye-colored', 'm&p-carmine', 'macaroni-and-cheese', 'madder-lake', 'magenta', 'magenta-dye', 'magenta-haze', 'magenta-pantone', 'magenta-pink', 'magenta-process', 'magic-mint', 'magic-potion', 'magnolia', 'mahogany', 'maize', 'maize-crayola', 'majorelle-blue', 'malachite', 'manatee', 'mandarin', 'mango', 'mango-green', 'mango-tango', 'manila', 'mantis', 'maple-syrup', 'mardi-gras', 'margarine', 'margarita', 'marigold', 'maroon', 'maroon-x11', 'mauve', 'mauve-taupe', 'mauvelous', 'maximum-blue', 'maximum-blue-green', 'maximum-blue-purple', 'maximum-green', 'maximum-green-yellow', 'maximum-orange', 'maximum-purple', 'maximum-red', 'maximum-red-purple', 'maximum-yellow', 'maximum-yellow-red', 'may-green', 'maya-blue', 'meat-brown', 'meat-color', 'medium-aquamarine', 'medium-blue', 'medium-carmine', 'medium-champagne', 'medium-crimson', 'medium-electric-blue', 'medium-jungle-green', 'medium-orchid', 'medium-persian-blue', 'medium-purple', 'medium-red-violet', 'medium-ruby', 'medium-sea-green', 'medium-sky-blue', 'medium-slate-blue', 'medium-spring-bud', 'medium-spring-green', 'medium-turquoise', 'medium-vermilion', 'medium-violet-red', 'mellow-apricot', 'melon', 'menthol', 'metallic-blue', 'metallic-bronze', 'metallic-brown', 'metallic-gold', 'metallic-green', 'metallic-orange', 'metallic-pink', 'metallic-red', 'metallic-seaweed', 'metallic-sunburst', 'metallic-violet', 'metallic-yellow', 'mexican-pink', 'microsoft-blue', 'microsoft-edge-blue', 'microsoft-green', 'microsoft-red', 'microsoft-yellow', 'middle-blue', 'middle-blue-green', 'middle-blue-purple', 'middle-green', 'middle-green-yellow', 'middle-grey', 'middle-purple', 'middle-red', 'middle-red-purple', 'middle-yellow', 'middle-yellow-red', 'midnight', 'midnight-blue', 'midnight-green', 'mikado-yellow', 'milk', 'milk-chocolate', 'mimi-pink', 'mindaro', 'ming', 'minion-yellow', 'mint', 'mint-cream', 'mint-green', 'misty-moss', 'misty-rose', 'moccasin', 'mocha', 'moonstone', 'moonstone-blue', 'mordant-red', 'morning-blue', 'moss-color', 'moss-green', 'mountain-meadow', 'mountbatten-pink', 'mousy-indigo', 'mousy-wisteria', 'msu-green', 'mud', 'muddy-brown', 'mughal-green', 'mulberry', 'mulberry-dye', 'mulberry-dyed', 'munsell', 'munsell-blue', 'mustard', 'mustard-brown', 'mustard-green', 'mustard-yellow', 'myrtle', 'myrtle-green', 'mystic', 'mystic-maroon', 'mystic-red', 'nadeshiko-pink', 'napier-green', 'naples-yellow', 'navajo-white', 'navy-blue', 'navy-blue-bellflower', 'ncs-blue', 'neon-blue', 'neon-carrot', 'neon-fuchsia', 'neon-green', 'new-bridge', 'new-car', 'new-york-pink', 'nickel', 'nightingale-brown', 'nintendo-red', 'non-photo-blue', 'north-texas-green', 'nyanza', 'ocean-blue', 'ocean-boat-blue', 'ocean-green', 'ochre', 'ogre-odor', 'old-bamboo-color', 'old-burgundy', 'old-gold', 'old-lace', 'old-lavender', 'old-mauve', 'old-moss-green', 'old-rose', 'olive', 'olive-drab-#3', 'olive-green', 'olivine', 'onando-color', 'one-kin', 'onyx', 'opal', 'opera-mauve', 'opera-red', 'orange', 'orange-crayola', 'orange-pantone', 'orange-peel', 'orange-red', 'orange-ryb', 'orange-soda', 'orange-wheel', 'orange-yellow', 'orchid', 'orchid-crayola', 'orchid-pink', 'orioles-orange', 'ou-crimson-red', 'outer-space', 'outrageous-orange', 'oxford-blue', 'oxley', 'pacific-blue', 'painite', 'pakistan-green', 'palatinate-blue', 'palatinate-purple', 'pale-blue', 'pale-brown', 'pale-cerulean', 'pale-chestnut', 'pale-cornflower-blue', 'pale-cyan', 'pale-fallen-leaves', 'pale-goldenrod', 'pale-green', 'pale-green-onion', 'pale-incense', 'pale-lavender', 'pale-magenta', 'pale-magenta-pink', 'pale-oak', 'pale-persimmon', 'pale-pink', 'pale-purple', 'pale-red-violet', 'pale-robin-egg-blue', 'pale-silver', 'pale-spring-bud', 'pale-taupe', 'pale-turquoise', 'pale-violet', 'palm-leaf', 'panasonic-blue', 'pansy-purple', 'pantone-barbie-pink', 'pantone-blue', 'paolo-veronese-green', 'papaya-whip', 'paradise-pink', 'parakeet-blue', 'parrot-pink', 'pastel-blue', 'pastel-brown', 'pastel-gray', 'pastel-green', 'pastel-magenta', 'pastel-orange', 'pastel-pink', 'pastel-purple', 'pastel-red', 'pastel-violet', 'pastel-yellow', 'patina', 'patrinia-flowers', 'peach', 'peach-burst', 'peach-colored', 'peach-orange', 'peach-puff', 'peach-yellow', 'pear', 'pearl', 'pearl-aqua', 'pearly-purple', 'penguin-white', 'peridot', 'periwinkle', 'persian-blue', 'persian-green', 'persian-indigo', 'persian-orange', 'persian-pink', 'persian-plum', 'persian-red', 'persian-rose', 'persimmon', 'peru', 'pewter-blue', 'philippine-blue', 'philippine-bronze', 'philippine-brown', 'philippine-gold', 'philippine-gray', 'philippine-green', 'philippine-orange', 'philippine-pink', 'philippine-red', 'philippine-silver', 'philippine-violet', 'philippine-yellow', 'phlox', 'phthalo-blue', 'phthalo-green', 'picton-blue', 'pictorial-carmine', 'piggy-pink', 'pigment-blue', 'pine-green', 'pine-needle-color', 'pine-tree', 'pineapple', 'pink', 'pink-flamingo', 'pink-lace', 'pink-lavender', 'pink-pantone', 'pink-pearl', 'pink-raspberry', 'pink-sherbet', 'pistachio', 'pixie-powder', 'plain-mouse', 'platinum', 'plum', 'plum-blossom-mouse', 'plum-dyed', 'plum-purple', 'plump-purple', 'poker-green', 'polished-brown', 'polished-pine', 'pomegranate', 'pomelo', 'pomelo-olive', 'pomelo-white', 'poppy-petal', 'popstar', 'porcupine', 'portland-orange', 'powder-blue', 'princess-perfume', 'princeton-orange', 'prussian-blue', 'prussian-blue-color', 'puce', 'puce-red', 'pullman-brown', 'pullman-green', 'pumpkin', 'pure-crimson', 'purple', 'purple-heart', 'purple-kite', 'purple-munsell', 'purple-murasaki', 'purple-navy', 'purple-pizzazz', 'purple-plum', 'purple-taupe', 'purpureus', 'quartz', 'queen-blue', 'queen-pink', 'quick-silver', 'quinacridone-magenta', 'quincy', 'rabbit-ear-iris', 'rackley', 'radical-red', 'raisin-black', 'rajah', 'rambutan', 'rambutan-red', 'rape-blossom-brown', 'rapeseed-oil-colored', 'raspberry', 'raspberry-pink', 'raw-sienna', 'raw-umber', 'razzle-dazzle-rose', 'razzmatazz', 'razzmic-berry', 'rebecca-purple', 'red', 'red-bean-color', 'red-birch', 'red-bronze', 'red-brown', 'red-cns', 'red-cola', 'red-crayola', 'red-devil', 'red-incense-colored', 'red-kite', 'red-munsell', 'red-ochre-color', 'red-orange', 'red-plum-colored', 'red-purple', 'red-ryb', 'red-salsa', 'red-violet', 'red-wisteria', 'redwood', 'refreshed-red-brown', 'regalia', 'resolution-blue', 'rhythm', 'rich-black', 'rich-electric-blue', 'rich-gardenia', 'rich-lavender', 'rich-lilac', 'rifle-green', 'rikan-brown', 'rinsed-out-red', 'ripe-mango', 'robin-egg-blue', 'rocket-metallic', 'roman-silver', 'root-beer', 'rose', 'rose-bonbon', 'rose-dust', 'rose-ebony', 'rose-garnet', 'rose-gold', 'rose-pink', 'rose-quartz-pink', 'rose-red', 'rose-taupe', 'rose-vale', 'rosewood', 'rosso-corsa', 'rosy-brown', 'royal-azure', 'royal-blue', 'royal-brown', 'royal-fuchsia', 'royal-green', 'royal-orange', 'royal-pink', 'royal-purple', 'royal-red', 'ruber', 'rubine-red', 'ruby', 'ruby-red', 'ruddy', 'ruddy-brown', 'ruddy-pink', 'rufous', 'rum', 'russet', 'russian-green', 'russian-violet', 'rust', 'rusted-light-blue', 'rusty-celadon', 'rusty-red', 'rusty-storage', 'rusty-storeroom', 'saddle-brown', 'sae-amber', 'safety-orange', 'safety-yellow', 'safflower-color', 'saffron', 'sage', 'salmon', 'salmon-pink', 'salmon-rose', 'samsung-blue', 'sand', 'sandstorm', 'sandy-brown', 'sandy-tan', 'sangria', 'sap-green', 'sappanwood', 'sappanwood-incense', 'sapphire', 'sasquatch-socks', 'satin-sheen-gold', 'sawtooth-oak', 'scarlet', 'scarlet-blood', 'school-bus-yellow', 'scorched-brown', 'screaming-green', 'sea-blue', 'sea-foam-green', 'sea-green', 'sea-serpent', 'seal-brown', 'seashell', 'seiheki-blue-green', 'selective-yellow', 'sen-no-rikyus-tea', 'sepia', 'sesame-street-green', 'shadow', 'shadow-blue', 'shampoo', 'shamrock', 'shamrock-green', 'shandy', 'sheen-green', 'shimmering-blush', 'shiny-shamrock', 'shocking-pink', 'sienna', 'silk-crepe-brown', 'silver', 'silver-chalice', 'silver-foil', 'silver-grey', 'silver-lake-blue', 'silver-pink', 'silver-sand', 'simmered-seaweed', 'sinopia', 'siskin-sprout-yellow', 'sizzling-red', 'sizzling-sunrise', 'skobeloff', 'sky-blue', 'sky-blue-color', 'sky-magenta', 'slate-blue', 'slate-gray', 'slimy-green', 'smalt', 'smashed-pumpkin', 'smitten', 'smoke', 'smokey-topaz', 'smoky-black', 'smoky-topaz', 'snow', 'soap', 'soldier-green', 'solid-pink', 'sonic-silver', 'sooty-willow-bamboo', 'space-cadet', 'spanish-bistre', 'spanish-blue', 'spanish-carmine', 'spanish-crimson', 'spanish-gray', 'spanish-green', 'spanish-orange', 'spanish-pink', 'spanish-purple', 'spanish-red', 'spanish-violet', 'spanish-viridian', 'spanish-yellow', 'sparrow-brown', 'spartan-crimson', 'spicy-mix', 'spicy-red-brown', 'spiro-disco-ball', 'sponge', 'spring-bud', 'spring-frost', 'sprint-red', 'sprint-yellow', 'st-patricks-blue', 'stained-red', 'star-command-blue', 'steel-blue', 'steel-pink', 'steel-teal', 'stizza', 'stone-terrace', 'stop-red', 'storeroom-brown', 'straw', 'strawberry', 'strawberry-daiquiri', 'strawberry-jam', 'strawberry-red', 'strong-boy-pink', 'stylish-persimmon', 'sugar-plum', 'sumac-dyed', 'sunburnt-cyclops', 'sunglow', 'sunny', 'sunray', 'sunset', 'sunset-orange', 'sunset-yellow', 'super-pink', 'sweet-brown', 'sweet-sixteen', 'tan', 'tangelo', 'tangerine', 'tangerine-yellow', 'taobao-orange', 'tardis-blue', 'tart-orange', 'tatarian-aster-color', 'taupe', 'taupe-gray', 'tawny', 'tea-green', 'teal', 'teal-blue', 'teal-deer', 'teal-green', 'telemagenta', 'temptress', 'tenné', 'terra-cotta', 'thin-color', 'thistle', 'thousand-herb-color', 'thrice-dyed-crimson', 'tickle-me-pink', 'tiffany-blue', 'tigers-eye', 'timberwolf', 'titanium', 'titanium-yellow', 'tomato', 'tomato-sauce', 'toolbox', 'topaz', 'tractor-red', 'trad-brown', 'trad-chartreuse', 'trad-chocolate', 'tree-peony', 'trolley-grey', 'tropical-rain-forest', 'tropical-violet', 'true-blue', 'true-red', 'tufts-blue', 'tulip', 'tumbleweed', 'turkish-rose', 'turmeric-colored', 'turquoise', 'turquoise-blue', 'turquoise-green', 'turquoise-surf', 'tuscan-red', 'tuscany', 'twilight-lavender', 'twitter-blue', 'ua-blue', 'ua-red', 'ube', 'ucla-blue', 'ucla-gold', 'ue-red', 'ufo-green', 'ultra-red', 'ultramarine', 'ultramarine-blue', 'ultramarine-color', 'umber', 'unbleached-silk', 'united-nations-blue', 'up-maroon', 'upsdell-red', 'urobilin', 'usafa-blue', 'utah-crimson', 'vampire-black', 'van-dyke-brown', 'vanilla', 'vanilla-ice', 'vegas-gold', 'velvet', 'venetian-red', 'verdigris', 'verizon-red', 'vermilion', 'veronica', 'verse-green', 'very-light-azure', 'very-light-blue', 'very-light-tangelo', 'very-pale-orange', 'very-pale-yellow', 'vine-grape', 'vine-green', 'violet', 'violet-blue', 'violet-red', 'violets-are-blue', 'violin-brown', 'viridian', 'viridian-green', 'vista-blue', 'vivaldi-red', 'vivid-auburn', 'vivid-burgundy', 'vivid-cerise', 'vivid-cerulean', 'vivid-crimson', 'vivid-gamboge', 'vivid-lime-green', 'vivid-malachite', 'vivid-mulberry', 'vivid-orange', 'vivid-orange-peel', 'vivid-orchid', 'vivid-raspberry', 'vivid-red', 'vivid-red-tangelo', 'vivid-sky-blue', 'vivid-tangelo', 'vivid-tangerine', 'vivid-vermilion', 'vivid-violet', 'vivid-yellow', 'vodka', 'volt', 'wageningen-green', 'walnut-dyed', 'warm-black', 'washed-out-crimson', 'washed-out-persimmon', 'water', 'water-persimmon', 'watermelon-yellow', 'waterspout', 'weathered-bamboo', 'weebly-blue', 'weebly-orange', 'weldon-blue', 'wenge', 'wheat', 'white', 'white-chocolate', 'white-coffee', 'white-mouse', 'white-oak', 'white-tea-colored', 'whitish-green', 'wild-blue-yonder', 'wild-orchid', 'wild-strawberry', 'willow-dye', 'willow-grey', 'willow-tea', 'willpower-orange', 'wilted-brown', 'windsor-tan', 'wine', 'wine-red', 'winter-sky', 'winter-wizard', 'wintergreen-dream', 'wisteria', 'wisteria-color', 'wisteria-purple', 'xanadu', 'xbox-green', 'xiaomi-orange', 'yale-blue', 'yankees-blue', 'yellow', 'yellow-green', 'yellow-orange', 'yellow-red-brown', 'yellow-rose', 'yinmn-blue', 'young-bamboo-color', 'youtube-red', 'zaffre', 'zinnwaldite', 'zinnwaldite-brown', 'zomp'];
var values = ['#e85395', '#d3419d', '#f364a2', '#f7238a', '#ff3988', '#fc419a', '#0048ba', '#4c2f27', '#b0bf1a', '#7cb9e8', '#c9ffe5', '#b284be', '#5d8aa8', '#00308f', '#72a0c1', '#af002a', '#f2f0e6', '#f0f8ff', '#e32636', '#c46210', '#efdecd', '#5a6457', '#6a432d', '#d6d6d6', '#d2d9db', '#e52b50', '#9f2b68', '#f19cbb', '#ab274f', '#d3212d', '#3b7a57', '#ffbf00', '#3b3b6d', '#391802', '#804040', '#d3af37', '#34b334', '#ff8b00', '#ff9899', '#431c53', '#b32134', '#ff033e', '#cfcfcf', '#551b8c', '#f2b400', '#9966cc', '#f3c13a', '#f2f3f4', '#cd9575', '#665d1e', '#915c83', '#841b2d', '#faebd7', '#008000', '#66b447', '#8db600', '#fbceb1', '#86aba5', '#7fffd4', '#d0ff14', '#4b5320', '#8f9779', '#e9d66b', '#32ad61', '#ca7309', '#b2beb5', '#87a96b', '#003a6c', '#ff9966', '#fdee00', '#568203', '#ff2052', '#63775b', '#007fff', '#f0ffff', '#dbe9f4', '#2e5894', '#89cff0', '#a1caf1', '#f4c2c2', '#fefefa', '#857c55', '#ff91af', '#21abcd', '#fae7b5', '#ffe135', '#006a4e', '#e94196', '#7c0a02', '#1dacd6', '#848482', '#5fc9bf', '#98777b', '#bcd4e6', '#9f8170', '#f28e1c', '#fa6e79', '#f5f5dc', '#5d3f6a', '#352925', '#9c2542', '#e88e5a', '#b14a30', '#ffe4c4', '#3d2b1f', '#967117', '#cae00d', '#bfff00', '#fe6f5e', '#bf4f51', '#000000', '#3d0c02', '#252321', '#1b1811', '#3b2f2f', '#54626f', '#351e1c', '#253529', '#3b3c36', '#bfafb2', '#ffebcd', '#a57164', '#318ce7', '#ace5ee', '#faf0be', '#8a0303', '#d1001c', '#f35336', '#0000ff', '#a2a2d0', '#52593b', '#00b9fb', '#0088dc', '#6699cc', '#0d98ba', '#5dadec', '#4cb7a5', '#553592', '#0cbfe9', '#126180', '#8a2be2', '#5072a7', '#4f86f7', '#1c1cf0', '#de5d83', '#79443b', '#0095b6', '#e3dac9', '#dde26a', '#0e9ca5', '#873260', '#0070ff', '#87413f', '#b5a642', '#ff631c', '#e68364', '#cb4154', '#ebecf0', '#66ff00', '#bf94e4', '#d891ef', '#c32148', '#1974d2', '#ff007f', '#08e8de', '#d19fe8', '#ffaa1d', '#3399ff', '#f4bbff', '#ff55a3', '#fb607f', '#004225', '#cd7f32', '#737000', '#a52a2a', '#5f1933', '#4a2c2a', '#6b4423', '#4b3c39', '#af6e4d', '#cc9966', '#1b4d3e', '#8c5939', '#ffc1cc', '#e7feff', '#7bb661', '#f0dc82', '#480607', '#800020', '#deb887', '#a17a74', '#cc5500', '#e97451', '#8a3324', '#24a0ed', '#bd33a4', '#702963', '#536872', '#5f9ea0', '#91a3b0', '#0a1195', '#006b3c', '#ed872d', '#b60c26', '#e30022', '#7f3e98', '#fff600', '#a67b5b', '#4b3621', '#fcffa4', '#a3c1ad', '#efbbcc', '#78866b', '#ffff99', '#ffef00', '#ff0800', '#e4717a', '#00bfff', '#592720', '#ffd59a', '#c41e3a', '#1ac1dd', '#00cc99', '#ff0040', '#eb4c42', '#ff0038', '#ffa6c9', '#b31b1b', '#56a0d3', '#ed9121', '#00563f', '#a41313', '#062a78', '#703642', '#b64925', '#c95a49', '#92a1cf', '#ace1af', '#007ba7', '#819c8b', '#2f847c', '#b2ffff', '#4997d0', '#246bce', '#ec3b83', '#007ba7', '#2a52be', '#6d9bc3', '#001440', '#007aa5', '#e03c31', '#a0785a', '#f1ddcf', '#36454f', '#232b2b', '#d0748b', '#e68fac', '#7fff00', '#ffa600', '#de3163', '#fcc9b9', '#ac8181', '#ffb7c5', '#cd5c5c', '#ffc34d', '#de6fa1', '#a8516e', '#141414', '#365194', '#cd8032', '#ab381f', '#cc9900', '#d0db61', '#f37042', '#de70a1', '#720b98', '#cd071e', '#cccccc', '#856088', '#e2e5de', '#ffb200', '#4aff00', '#3f000f', '#58111a', '#3c1421', '#a8a9ad', '#ffa700', '#98817b', '#d2691e', '#cd607e', '#e4d00a', '#933709', '#9fa91f', '#7f1734', '#fbcce7', '#8f583c', '#a96232', '#181b26', '#0047ab', '#0047ab', '#965a3e', '#e9edf6', '#6f4e37', '#3c3024', '#c4d8e2', '#ffffcc', '#f88379', '#eee0b1', '#002e63', '#8c92ac', '#b87333', '#ad6f69', '#cb6d51', '#996666', '#ff3800', '#ff7f50', '#f8674f', '#ff4040', '#f6a494', '#893f45', '#faa945', '#9aceeb', '#6495ed', '#fff8dc', '#2e2d88', '#fff8e7', '#ffbcd9', '#81613c', '#1f75fe', '#7366bd', '#af593e', '#a9b2c3', '#da8a67', '#fffdd0', '#dc143c', '#be0032', '#990000', '#a7d8de', '#68a0b0', '#f5f5f5', '#4e82b4', '#4682bf', '#28589c', '#188bc2', '#00b7eb', '#58427c', '#ffd300', '#f56fa1', '#752e23', '#6f3028', '#ffff31', '#f0e130', '#00008b', '#666699', '#192236', '#514100', '#654321', '#88654e', '#5d3954', '#a40000', '#08457e', '#333333', '#986960', '#3c1321', '#cd5b45', '#26428b', '#008b8b', '#536878', '#aa6c39', '#b8860b', '#a9a9a9', '#006400', '#1f262a', '#00416a', '#614e6e', '#1a2421', '#bdb76b', '#483c32', '#734f96', '#8bbe1b', '#543d37', '#8b008b', '#003366', '#4a5d23', '#02075d', '#556b2f', '#ff8c00', '#9932cc', '#779ecb', '#03c03c', '#966fd6', '#c23b22', '#e75480', '#003399', '#4f3a3c', '#301934', '#872657', '#23191e', '#e9967a', '#560319', '#8fbc8f', '#3c1414', '#71706e', '#8cbed6', '#483d8b', '#2f4f4f', '#177245', '#918151', '#ffa812', '#cc4e5c', '#00ced1', '#d1bea8', '#9400d3', '#9b870c', '#00703c', '#555555', '#fa7b62', '#ff8936', '#d70a53', '#9c8aa4', '#40826d', '#a9203e', '#ef3038', '#e9692c', '#da3287', '#fad6a5', '#b94e48', '#704241', '#9b351b', '#c154c1', '#056608', '#004b49', '#333366', '#f5c71a', '#9955bb', '#cc00cc', '#820000', '#d473d4', '#355e3b', '#ffcba4', '#ff1493', '#a95c68', '#3a243b', '#850101', '#843f5b', '#ff9933', '#7b3b3a', '#4a646c', '#7e5e60', '#66424d', '#330066', '#ba8759', '#6ab2ca', '#1560bd', '#2243b6', '#669999', '#edc9af', '#ea3c53', '#b9f2ff', '#696969', '#c53151', '#9b7653', '#b5651e', '#e8e4c9', '#3f313a', '#1e90ff', '#fef65b', '#d71868', '#85bb65', '#828e84', '#2496cd', '#2e963d', '#f7c58e', '#755d5b', '#967117', '#00009c', '#4f4944', '#b07939', '#e6d0ab', '#e1bd27', '#e5ccc9', '#efdfbb', '#913225', '#e1a95f', '#be7f51', '#5d3a1a', '#5e2824', '#555d50', '#1b1b1b', '#ffa631', '#614051', '#f0ead6', '#1034a6', '#17182b', '#7df9ff', '#b56257', '#ff003f', '#00ff00', '#6f00ff', '#ccff00', '#ff3503', '#f62681', '#bf00ff', '#e60000', '#3f00ff', '#8f00ff', '#ffff33', '#50c878', '#046307', '#6c3082', '#008000', '#b48395', '#ab4b52', '#cc474b', '#563c5c', '#96c8a2', '#44d7a8', '#39569c', '#43242a', '#801818', '#b53389', '#de5285', '#f400a1', '#e5aa70', '#4d5d53', '#fdd5b1', '#71bc78', '#4f7942', '#ff2800', '#6c541e', '#ff5470', '#957b38', '#ce2029', '#e95c4b', '#b22222', '#e25822', '#fc8eac', '#f7e98e', '#eedc82', '#ffe9d1', '#216bd6', '#fb0081', '#a2006d', '#ffb94e', '#fffaf0', '#f498ad', '#15f4ee', '#ff004f', '#c91f37', '#228b22', '#5fa777', '#014421', '#985629', '#856d4d', '#0072bb', '#fd3f92', '#86608e', '#9efd38', '#fd6c9e', '#811453', '#4e1609', '#c72c48', '#f64a8a', '#77b5fe', '#8806ce', '#ac1e44', '#a6e7ff', '#5b8930', '#e936a7', '#ff77ff', '#cc397b', '#c74375', '#e48400', '#cc6666', '#dcdcdc', '#e49b0f', '#996600', '#ffdf46', '#733635', '#007f66', '#f8f8ff', '#b05c52', '#fe5a1d', '#d8e4bc', '#b06500', '#6082b6', '#d34e36', '#e6e8fa', '#ab92b3', '#00ab66', '#cb7e1f', '#e6be8a', '#bd9b16', '#85754e', '#ffd700', '#c66b27', '#e29c45', '#7d4e2d', '#bb8141', '#fcc200', '#ffa400', '#daa520', '#4c8bf5', '#1aa260', '#de5246', '#ffce44', '#203838', '#676767', '#a8e4a0', '#6f2da8', '#63424b', '#808080', '#bebebe', '#00ff00', '#006442', '#1164b4', '#4c721d', '#1cac78', '#009966', '#a7f432', '#2a603b', '#00a877', '#009f6b', '#00ad43', '#00a550', '#66b032', '#6eaea1', '#65ff00', '#824b35', '#adff2f', '#bda928', '#bc2d29', '#656255', '#a99a86', '#2a3439', '#00ff7f', '#f8f8f8', '#663854', '#8d608c', '#eb6123', '#446ccf', '#5218fa', '#757d75', '#3fff00', '#46cb18', '#f29cb7', '#da9100', '#00c3e3', '#808000', '#ff7a00', '#df73ff', '#aa98a9', '#aa00bb', '#f0fff0', '#006db0', '#49796b', '#3d5d42', '#ff1dce', '#ff69b4', '#ed1c24', '#f58f84', '#71a6d2', '#923c01', '#fcf75e', '#71bc78', '#319177', '#602f6b', '#002395', '#66023c', '#ed2939', '#b2ec5d', '#4c516d', '#138808', '#cd5c5c', '#e3a857', '#4b0082', '#091f92', '#393432', '#233067', '#ebf6f7', '#ff496c', '#27221f', '#2d4436', '#c6c2b6', '#ff4f00', '#5a4fcf', '#763568', '#a19d94', '#2b3733', '#2b3736', '#f4f0ec', '#009000', '#e9f6ef', '#635a52', '#906652', '#fffff0', '#5e5545', '#3d325d', '#413628', '#00a86b', '#9d2933', '#264348', '#2f7532', '#5b3256', '#f8de7e', '#d73b3e', '#de8f4e', '#a50b5e', '#da614e', '#44798e', '#343434', '#bbd0c9', '#fada5e', '#8ab9f1', '#bdda57', '#29ab87', '#4cbb17', '#7c1c05', '#3ab09e', '#e8f48c', '#c3b091', '#3d4c51', '#8ee53f', '#e79fc4', '#ca6924', '#171412', '#354230', '#512888', '#e8000d', '#fb9912', '#d6cadd', '#e0bc5b', '#26619c', '#1f4788', '#ffff66', '#a9ba9d', '#cf1020', '#e6e6fa', '#ccccff', '#fff0f5', '#c4c3d0', '#9457eb', '#ee82ee', '#e6e6fa', '#fbaed2', '#967bb6', '#fba0e3', '#7cfc00', '#2e211b', '#fff700', '#fffacd', '#cca01d', '#fdff00', '#bd3000', '#5cff67', '#e3ff00', '#f6eabe', '#ffff9f', '#ba93d8', '#545aa7', '#1a1110', '#add8e6', '#48929b', '#1d697c', '#044f67', '#b5651d', '#e66771', '#88ace0', '#f08080', '#f56991', '#e0ffff', '#ff5ccd', '#c8ad7f', '#f984ef', '#b29700', '#d3d3d3', '#90ee90', '#ffb3de', '#f0e68c', '#ff80ff', '#d39bcb', '#addfad', '#fed8b1', '#e6a8d7', '#b19cd9', '#c5cbe1', '#ffb6c1', '#ffcccb', '#ffa07a', '#ff9999', '#20b2aa', '#d8d8d8', '#87cefa', '#778899', '#b0c4de', '#b38b6d', '#f7bb7d', '#c8a2c8', '#ae98aa', '#bfff00', '#32cd32', '#d1e189', '#9dc209', '#195905', '#faf0e6', '#0072b1', '#c19a6b', '#6ca0dc', '#f8b9d4', '#534b4f', '#987456', '#b86d29', '#b95754', '#ab6134', '#fefdfa', '#15f2fd', '#eccfcf', '#ffe4cd', '#e62020', '#dc5349', '#7f6b5d', '#d70040', '#ffbd88', '#cc3336', '#ff00ff', '#ca1f7b', '#9f4576', '#d0417e', '#cc338b', '#ff0090', '#aaf0d1', '#ff4466', '#f8f4ff', '#c04000', '#fbec5d', '#f2c649', '#6050dc', '#0bda51', '#979aaa', '#f37a48', '#fdbe02', '#96ff00', '#ff8243', '#e7c9a9', '#74c365', '#bb9351', '#880085', '#f2d930', '#b0c24a', '#eaa221', '#800000', '#b03060', '#e0b0ff', '#915f6d', '#ef98aa', '#47abcc', '#30bfbf', '#acace6', '#5e8c31', '#d9e650', '#ff5b00', '#733380', '#d92121', '#a63a79', '#fafa37', '#f2ba49', '#4c9141', '#73c2fb', '#e5b73b', '#f9906f', '#66ddaa', '#0000cd', '#af4035', '#f3e5ab', '#c93756', '#035096', '#1c352d', '#ba55d3', '#0067a5', '#9370db', '#bb3385', '#aa4069', '#3cb371', '#80daeb', '#7b68ee', '#c9dc87', '#00fa9a', '#48d1cc', '#d9603b', '#c71585', '#f8b878', '#fdbcb4', '#c1f9a2', '#32527b', '#a97142', '#ac4313', '#d4af37', '#296e01', '#da680f', '#eda6c4', '#a62c2b', '#0a7e8c', '#9c7c38', '#5b0a91', '#fdcc0d', '#e4007c', '#00a2ed', '#0078d7', '#7db700', '#f04e1f', '#fdb900', '#7ed4e6', '#8dd9cc', '#8b72be', '#4d8c57', '#acbf60', '#8b8680', '#d982b5', '#e58e73', '#a55353', '#ffeb00', '#ecb176', '#702670', '#191970', '#004953', '#ffc40c', '#fdfff5', '#84563c', '#ffdae9', '#e3f988', '#36747d', '#f5e050', '#3eb489', '#f5fffa', '#98ff98', '#bbb477', '#ffe4e1', '#faebd7', '#bea493', '#3aa8c1', '#73a9c2', '#ae0c00', '#8da399', '#8b7d3a', '#8a9a5b', '#30ba8f', '#997a8d', '#5c544e', '#766980', '#18453b', '#70543e', '#cb6649', '#306030', '#c54b8c', '#59292c', '#c57f2e', '#f2f3f4', '#0093af', '#ffdb58', '#cd7a00', '#6e6e30', '#e1ad01', '#21421e', '#317873', '#d65282', '#ad4379', '#ff5500', '#f6adc6', '#2a8000', '#fada5e', '#ffdead', '#000080', '#191f45', '#0087bd', '#1b03a3', '#ffa343', '#fe4164', '#39ff14', '#006c7f', '#214fc6', '#d7837f', '#727472', '#5c4827', '#e4000f', '#a4dded', '#059033', '#e9ffdb', '#4f42b5', '#0077be', '#48bf91', '#cc7722', '#fd5240', '#5e644f', '#43302e', '#cfb53b', '#fdf5e6', '#796878', '#673147', '#867e36', '#c08081', '#808000', '#6b8e23', '#b5b35c', '#9ab973', '#364141', '#f08f90', '#0f0f0f', '#a8c3bc', '#b784a7', '#ff1b2d', '#ffa500', '#ff7538', '#ff5800', '#ff9f00', '#ff681f', '#fb9902', '#eb593d', '#ff7f00', '#f8d568', '#da70d6', '#e29cd2', '#f2bdcd', '#fb4f14', '#841617', '#2d383a', '#ff6e4a', '#002147', '