#x1f3fd;‍♂️', '👱🏾‍♀️', '👱🏾‍♂️', '👱🏿‍♀️', '👱🏿‍♂️', '👳🏻‍♀️', '👳🏻‍♂️', '👳🏼‍♀️', '👳🏼‍♂️', '👳🏽‍♀️', '👳🏽‍♂️', '👳🏾‍♀️', '👳🏾‍♂️', '👳🏿‍♀️', '👳🏿‍♂️', '👷🏻‍♀️', '👷🏻‍♂️', '👷🏼‍♀️', '👷🏼‍♂️', '👷🏽‍♀️', '👷🏽‍♂️', '👷🏾‍♀️', '👷🏾‍♂️', '👷🏿‍♀️', '👷🏿‍♂️', '💁🏻‍♀️', '💁🏻‍♂️', '💁🏼‍♀️', '💁🏼‍♂️', '💁🏽‍♀️', '💁🏽‍♂️', '💁🏾‍♀️', '💁🏾‍♂️', '💁🏿‍♀️', '💁🏿‍♂️', '💂🏻‍♀️', '💂🏻‍♂️', '💂🏼‍♀️', '💂🏼‍♂️', '💂🏽‍♀️', '💂🏽‍♂️', '💂🏾‍♀️', '💂🏾‍♂️', '💂🏿‍♀️', '💂🏿‍♂️', '💆🏻‍♀️', '💆🏻‍♂️', '💆🏼‍♀️', '💆🏼‍♂️', '💆🏽‍♀️', '💆🏽‍♂️', '💆🏾‍♀️', '💆🏾‍♂️', '💆🏿‍♀️', '💆🏿‍♂️', '💇🏻‍♀️', '💇🏻‍♂️', '💇🏼‍♀️', '💇🏼‍♂️', '💇🏽‍♀️', '💇🏽‍♂️', '💇🏾‍♀️', '💇🏾‍♂️', '💇🏿‍♀️', '💇🏿‍♂️', '🕴🏻‍♀️', '🕴🏻‍♂️', '🕴🏼‍♀️', '🕴🏼‍♂️', '🕴🏽‍♀️', '🕴🏽‍♂️', '🕴🏾‍♀️', '🕴🏾‍♂️', '🕴🏿‍♀️', '🕴🏿‍♂️', '🕵🏻‍♀️', '🕵🏻‍♂️', '🕵🏼‍♀️', '🕵🏼‍♂️', '🕵🏽‍♀️', '🕵🏽‍♂️', '🕵🏾‍♀️', '🕵🏾‍♂️', '🕵🏿‍♀️', '🕵🏿‍♂️', '🙅🏻‍♀️', '🙅🏻‍♂️', '🙅🏼‍♀️', '🙅🏼‍♂️', '🙅🏽‍♀️', '🙅🏽‍♂️', '🙅🏾‍♀️', '🙅🏾‍♂️', '🙅🏿‍♀️', '🙅🏿‍♂️', '🙆🏻‍♀️', '🙆🏻‍♂️', '🙆🏼‍♀️', '🙆🏼‍♂️', '🙆🏽‍♀️', '🙆🏽‍♂️', '🙆🏾‍♀️', '🙆🏾‍♂️', '🙆🏿‍♀️', '🙆🏿‍♂️', '🙇🏻‍♀️', '🙇🏻‍♂️', '🙇🏼‍♀️', '🙇🏼‍♂️', '🙇🏽‍♀️', '🙇🏽‍♂️', '🙇🏾‍♀️', '🙇🏾‍♂️', '🙇🏿‍♀️', '🙇🏿‍♂️', '🙋🏻‍♀️', '🙋🏻‍♂️', '🙋🏼‍♀️', '🙋🏼‍♂️', '🙋🏽‍♀️', '🙋🏽‍♂️', '🙋🏾‍♀️', '🙋🏾‍♂️', '🙋🏿‍♀️', '🙋🏿‍♂️', '🙍🏻‍♀️', '🙍🏻‍♂️', '🙍🏼‍♀️', '🙍🏼‍♂️', '🙍🏽‍♀️', '🙍🏽‍♂️', '🙍🏾‍♀️', '🙍🏾‍♂️', '🙍🏿‍♀️', '🙍🏿‍♂️', '🙎🏻‍♀️', '🙎🏻‍♂️', '🙎🏼‍♀️', '🙎🏼‍♂️', '🙎🏽‍♀️', '🙎🏽‍♂️', '🙎🏾‍♀️', '🙎🏾‍♂️', '🙎🏿‍♀️', '🙎🏿‍♂️', '🚣🏻‍♀️', '🚣🏻‍♂️', '🚣🏼‍♀️', '🚣🏼‍♂️', '🚣🏽‍♀️', '🚣🏽‍♂️', '🚣🏾‍♀️', '🚣🏾‍♂️', '🚣🏿‍♀️', '🚣🏿‍♂️', '🚴🏻‍♀️', '🚴🏻‍♂️', '🚴🏼‍♀️', '🚴🏼‍♂️', '🚴🏽‍♀️', '🚴🏽‍♂️', '🚴🏾‍♀️', '🚴🏾‍♂️', '🚴🏿‍♀️', '🚴🏿‍♂️', '🚵🏻‍♀️', '🚵🏻‍♂️', '🚵🏼‍♀️', '🚵🏼‍♂️', '🚵🏽‍♀️', '🚵🏽‍♂️', '🚵🏾‍♀️', '🚵🏾‍♂️', '🚵🏿‍♀️', '🚵🏿‍♂️', '🚶🏻‍♀️', '🚶🏻‍♂️', '🚶🏼‍♀️', '🚶🏼‍♂️', '🚶🏽‍♀️', '🚶🏽‍♂️', '🚶🏾‍♀️', '🚶🏾‍♂️', '🚶🏿‍♀️', '🚶🏿‍♂️', '🤦🏻‍♀️', '🤦🏻‍♂️', '🤦🏼‍♀️', '🤦🏼‍♂️', '🤦🏽‍♀️', '🤦🏽‍♂️', '🤦🏾‍♀️', '🤦🏾‍♂️', '🤦🏿‍♀️', '🤦🏿‍♂️', '🤵🏻‍♀️', '🤵🏻‍♂️', '🤵🏼‍♀️', '🤵🏼‍♂️', '🤵🏽‍♀️', '🤵🏽‍♂️', '🤵🏾‍♀️', '🤵🏾‍♂️', '🤵🏿‍♀️', '🤵🏿‍♂️', '🤷🏻‍♀️', '🤷🏻‍♂️', '🤷🏼‍♀️', '🤷🏼‍♂️', '🤷🏽‍♀️', '🤷🏽‍♂️', '🤷🏾‍♀️', '🤷🏾‍♂️', '🤷🏿‍♀️', '🤷🏿‍♂️', '🤸🏻‍♀️', '🤸🏻‍♂️', '🤸🏼‍♀️', '🤸🏼‍♂️', '🤸🏽‍♀️', '🤸🏽‍♂️', '🤸🏾‍♀️', '🤸🏾‍♂️', '🤸🏿‍♀️', '🤸🏿‍♂️', '🤹🏻‍♀️', '🤹🏻‍♂️', '🤹🏼‍♀️', '🤹🏼‍♂️', '🤹🏽‍♀️', '🤹🏽‍♂️', '🤹🏾‍♀️', '🤹🏾‍♂️', '🤹🏿‍♀️', '🤹🏿‍♂️', '🤽🏻‍♀️', '🤽🏻‍♂️', '🤽🏼‍♀️', '🤽🏼‍♂️', '🤽🏽‍♀️', '🤽🏽‍♂️', '🤽🏾‍♀️', '🤽🏾‍♂️', '🤽🏿‍♀️', '🤽🏿‍♂️', '🤾🏻‍♀️', '🤾🏻‍♂️', '🤾🏼‍♀️', '🤾🏼‍♂️', '🤾🏽‍♀️', '🤾🏽‍♂️', '🤾🏾‍♀️', '🤾🏾‍♂️', '🤾🏿‍♀️', '🤾🏿‍♂️', '🦸🏻‍♀️', '🦸🏻‍♂️', '🦸🏼‍♀️', '🦸🏼‍♂️', '🦸🏽‍♀️', '🦸🏽‍♂️', '🦸🏾‍♀️', '🦸🏾‍♂️', '🦸🏿‍♀️', '🦸🏿‍♂️', '🦹🏻‍♀️', '🦹🏻‍♂️', '🦹🏼‍♀️', '🦹🏼‍♂️', '🦹🏽‍♀️', '🦹🏽‍♂️', '🦹🏾‍♀️', '🦹🏾‍♂️', '🦹🏿‍♀️', '🦹🏿‍♂️', '🧍🏻‍♀️', '🧍🏻‍♂️', '🧍🏼‍♀️', '🧍🏼‍♂️', '🧍🏽‍♀️', '🧍🏽‍♂️', '🧍🏾‍♀️', '🧍🏾‍♂️', '🧍🏿‍♀️', '🧍🏿‍♂️', '🧎🏻‍♀️', '🧎🏻‍♂️', '🧎🏼‍♀️', '🧎🏼‍♂️', '🧎🏽‍♀️', '🧎🏽‍♂️', '🧎🏾‍♀️', '🧎🏾‍♂️', '🧎🏿‍♀️', '🧎🏿‍♂️', '🧏🏻‍♀️', '🧏🏻‍♂️', '🧏🏼‍♀️', '🧏🏼‍♂️', '🧏🏽‍♀️', '🧏🏽‍♂️', '🧏🏾‍♀️', '🧏🏾‍♂️', '🧏🏿‍♀️', '🧏🏿‍♂️', '🧑🏻‍⚕️', '🧑🏻‍⚖️', '🧑🏻‍✈️', '🧑🏼‍⚕️', '🧑🏼‍⚖️', '🧑🏼‍✈️', '🧑🏽‍⚕️', '🧑🏽‍⚖️', '🧑🏽‍✈️', '🧑🏾‍⚕️', '🧑🏾‍⚖️', '🧑🏾‍✈️', '🧑🏿‍⚕️', '🧑🏿‍⚖️', '🧑🏿‍✈️', '🧔🏻‍♀️', '🧔🏻‍♂️', '🧔🏼‍♀️', '🧔🏼‍♂️', '🧔🏽‍♀️', '🧔🏽‍♂️', '🧔🏾‍♀️', '🧔🏾‍♂️', '🧔🏿‍♀️', '🧔🏿‍♂️', '🧖🏻‍♀️', '🧖🏻‍♂️', '🧖🏼‍♀️', '🧖🏼‍♂️', '🧖🏽‍♀️', '🧖🏽‍♂️', '🧖🏾‍♀️', '🧖🏾‍♂️', '🧖🏿‍♀️', '🧖🏿‍♂️', '🧗🏻‍♀️', '🧗🏻‍♂️', '🧗🏼‍♀️', '🧗🏼‍♂️', '🧗🏽‍♀️', '🧗🏽‍♂️', '🧗🏾‍♀️', '🧗🏾‍♂️', '🧗🏿‍♀️', '🧗🏿‍♂️', '🧘🏻‍♀️', '🧘🏻‍♂️', '🧘🏼‍♀️', '🧘🏼‍♂️', '🧘🏽‍♀️', '🧘🏽‍♂️', '🧘🏾‍♀️', '🧘🏾‍♂️', '🧘🏿‍♀️', '🧘🏿‍♂️', '🧙🏻‍♀️', '🧙🏻‍♂️', '🧙🏼‍♀️', '🧙🏼‍♂️', '🧙🏽‍♀️', '🧙🏽‍♂️', '🧙🏾‍♀️', '🧙🏾‍♂️', '🧙🏿‍♀️', '🧙🏿‍♂️', '🧚🏻‍♀️', '🧚🏻‍♂️', '🧚🏼‍♀️', '🧚🏼‍♂️', '🧚🏽‍♀️', '🧚🏽‍♂️', '🧚🏾‍♀️', '🧚🏾‍♂️', '🧚🏿‍♀️', '🧚🏿‍♂️', '🧛🏻‍♀️', '🧛🏻‍♂️', '🧛🏼‍♀️', '🧛🏼‍♂️', '🧛🏽‍♀️', '🧛🏽‍♂️', '🧛🏾‍♀️', '🧛🏾‍♂️', '🧛🏿‍♀️', '🧛🏿‍♂️', '🧜🏻‍♀️', '🧜🏻‍♂️', '🧜🏼‍♀️', '🧜🏼‍♂️', '🧜🏽‍♀️', '🧜🏽‍♂️', '🧜🏾‍♀️', '🧜🏾‍♂️', '🧜🏿‍♀️', '🧜🏿‍♂️', '🧝🏻‍♀️', '🧝🏻‍♂️', '🧝🏼‍♀️', '🧝🏼‍♂️', '🧝🏽‍♀️', '🧝🏽‍♂️', '🧝🏾‍♀️', '🧝🏾‍♂️', '🧝🏿‍♀️', '🧝🏿‍♂️', '🏋️‍♀️', '🏋️‍♂️', '🏌️‍♀️', '🏌️‍♂️', '🏳️‍⚧️', '🕴️‍♀️', '🕴️‍♂️', '🕵️‍♀️', '🕵️‍♂️', '⛹🏻‍♀️', '⛹🏻‍♂️', '⛹🏼‍♀️', '⛹🏼‍♂️', '⛹🏽‍♀️', '⛹🏽‍♂️', '⛹🏾‍♀️', '⛹🏾‍♂️', '⛹🏿‍♀️', '⛹🏿‍♂️', '⛹️‍♀️', '⛹️‍♂️', '👨🏻‍🌾', '👨🏻‍🍳', '👨🏻‍🍼', '👨🏻‍🎄', '👨🏻‍🎓', '👨🏻‍🎤', '👨🏻‍🎨', '👨🏻‍🏫', '👨🏻‍🏭', '👨🏻‍💻', '👨🏻‍💼', '👨🏻‍🔧', '👨🏻‍🔬', '👨🏻‍🚀', '👨🏻‍🚒', '👨🏻‍🦯', '👨🏻‍🦰', '👨🏻‍🦱', '👨🏻‍🦲', '👨🏻‍🦳', '👨🏻‍🦼', '👨🏻‍🦽', '👨🏼‍🌾', '👨🏼‍🍳', '👨🏼‍🍼', '👨🏼‍🎄', '👨🏼‍🎓', '👨🏼‍🎤', '👨🏼‍🎨', '👨🏼‍🏫', '👨🏼‍🏭', '👨🏼‍💻', '👨🏼‍💼', '👨🏼‍🔧', '👨🏼‍🔬', '👨🏼‍🚀', '👨🏼‍🚒', '👨🏼‍🦯', '👨🏼‍🦰', '👨🏼‍🦱', '👨🏼‍🦲', '👨🏼‍🦳', '👨🏼‍🦼', '👨🏼‍🦽', '👨🏽‍🌾', '👨🏽‍🍳', '👨🏽‍🍼', '👨🏽‍🎄', '👨🏽‍🎓', '👨🏽‍🎤', '👨🏽‍🎨', '👨🏽‍🏫', '👨🏽‍🏭', '👨🏽‍💻', '👨🏽‍💼', '👨🏽‍🔧', '👨🏽‍🔬', '👨🏽‍🚀', '👨🏽‍🚒', '👨🏽‍🦯', '👨🏽‍🦰', '👨🏽‍🦱', '👨🏽‍🦲', '👨🏽‍🦳', '👨🏽‍🦼', '👨🏽‍🦽', '👨🏾‍🌾', '👨🏾‍🍳', '👨🏾‍🍼', '👨🏾‍🎄', '👨🏾‍🎓', '👨🏾‍🎤', '👨🏾‍🎨', '👨🏾‍🏫', '👨🏾‍🏭', '👨🏾‍💻', '👨🏾‍💼', '👨🏾‍🔧', '👨🏾‍🔬', '👨🏾‍🚀', '👨🏾‍🚒', '👨🏾‍🦯', '👨🏾‍🦰', '👨🏾‍🦱', '👨🏾‍🦲', '👨🏾‍🦳', '👨🏾‍🦼', '👨🏾‍🦽', '👨🏿‍🌾', '👨🏿‍🍳', '👨🏿‍🍼', '👨🏿‍🎄', '👨🏿‍🎓', '👨🏿‍🎤', '👨🏿‍🎨', '👨🏿‍🏫', '👨🏿‍🏭', '👨🏿‍💻', '👨🏿‍💼', '👨🏿‍🔧', '👨🏿‍🔬', '👨🏿‍🚀', '👨🏿‍🚒', '👨🏿‍🦯', '👨🏿‍🦰', '👨🏿‍🦱', '👨🏿‍🦲', '👨🏿‍🦳', '👨🏿‍🦼', '👨🏿‍🦽', '👩🏻‍🌾', '👩🏻‍🍳', '👩🏻‍🍼', '👩🏻‍🎄', '👩🏻‍🎓', '👩🏻‍🎤', '👩🏻‍🎨', '👩🏻‍🏫', '👩🏻‍🏭', '👩🏻‍💻', '👩🏻‍💼', '👩🏻‍🔧', '👩🏻‍🔬', '👩🏻‍🚀', '👩🏻‍🚒', '👩🏻‍🦯', '👩🏻‍🦰', '👩🏻‍🦱', '👩🏻‍🦲', '👩🏻‍🦳', '👩🏻‍🦼', '👩🏻‍🦽', '👩🏼‍🌾', '👩🏼‍🍳', '👩🏼‍🍼', '👩🏼‍🎄', '👩🏼‍🎓', '👩🏼‍🎤', '👩🏼‍🎨', '👩🏼‍🏫', '👩🏼‍🏭', '👩🏼‍💻', '👩🏼‍💼', '👩🏼‍🔧', '👩🏼‍🔬', '👩🏼‍🚀', '👩🏼‍🚒', '👩🏼‍🦯', '👩🏼‍🦰', '👩🏼‍🦱', '👩🏼‍🦲', '👩🏼‍🦳', '👩🏼‍🦼', '👩🏼‍🦽', '👩🏽‍🌾', '👩🏽‍🍳', '👩🏽‍🍼', '👩🏽‍🎄', '👩🏽‍🎓', '👩🏽‍🎤', '👩🏽‍🎨', '👩🏽‍🏫', '👩🏽‍🏭', '👩🏽‍💻', '👩🏽‍💼', '👩🏽‍🔧', '👩🏽‍🔬', '👩🏽‍🚀', '👩🏽‍🚒', '👩🏽‍🦯', '👩🏽‍🦰', '👩🏽‍🦱', '👩🏽‍🦲', '👩🏽‍🦳', '👩🏽‍🦼', '👩🏽‍🦽', '👩🏾‍🌾', '👩🏾‍🍳', '👩🏾‍🍼', '👩🏾‍🎄', '👩🏾‍🎓', '👩🏾‍🎤', '👩🏾‍🎨', '👩🏾‍🏫', '👩🏾‍🏭', '👩🏾‍💻', '👩🏾‍💼', '👩🏾‍🔧', '👩🏾‍🔬', '👩🏾‍🚀', '👩🏾‍🚒', '👩🏾‍🦯', '👩🏾‍🦰', '👩🏾‍🦱', '👩🏾‍🦲', '👩🏾‍🦳', '👩🏾‍🦼', '👩🏾‍🦽', '👩🏿‍🌾', '👩🏿‍🍳', '👩🏿‍🍼', '👩🏿‍🎄', '👩🏿‍🎓', '👩🏿‍🎤', '👩🏿‍🎨', '👩🏿‍🏫', '👩🏿‍🏭', '👩🏿‍💻', '👩🏿‍💼', '👩🏿‍🔧', '👩🏿‍🔬', '👩🏿‍🚀', '👩🏿‍🚒', '👩🏿‍🦯', '👩🏿‍🦰', '👩🏿‍🦱', '👩🏿‍🦲', '👩🏿‍🦳', '👩🏿‍🦼', '👩🏿‍🦽', '🧑🏻‍🌾', '🧑🏻‍🍳', '🧑🏻‍🍼', '🧑🏻‍🎄', '🧑🏻‍🎓', '🧑🏻‍🎤', '🧑🏻‍🎨', '🧑🏻‍🏫', '🧑🏻‍🏭', '🧑🏻‍💻', '🧑🏻‍💼', '🧑🏻‍🔧', '🧑🏻‍🔬', '🧑🏻‍🚀', '🧑🏻‍🚒', '🧑🏻‍🦯', '🧑🏻‍🦰', '🧑🏻‍🦱', '🧑🏻‍🦲', '🧑🏻‍🦳', '🧑🏻‍🦼', '🧑🏻‍🦽', '🧑🏼‍🌾', '🧑🏼‍🍳', '🧑🏼‍🍼', '🧑🏼‍🎄', '🧑🏼‍🎓', '🧑🏼‍🎤', '🧑🏼‍🎨', '🧑🏼‍🏫', '🧑🏼‍🏭', '🧑🏼‍💻', '🧑🏼‍💼', '🧑🏼‍🔧', '🧑🏼‍🔬', '🧑🏼‍🚀', '🧑🏼‍🚒', '🧑🏼‍🦯', '🧑🏼‍🦰', '🧑🏼‍🦱', '🧑🏼‍🦲', '🧑🏼‍🦳', '🧑🏼‍🦼', '🧑🏼‍🦽', '🧑🏽‍🌾', '🧑🏽‍🍳', '🧑🏽‍🍼', '🧑🏽‍🎄', '🧑🏽‍🎓', '🧑🏽‍🎤', '🧑🏽‍🎨', '🧑🏽‍🏫', '🧑🏽‍🏭', '🧑🏽‍💻', '🧑🏽‍💼', '🧑🏽‍🔧', '🧑🏽‍🔬', '🧑🏽‍🚀', '🧑🏽‍🚒', '🧑🏽‍🦯', '🧑🏽‍🦰', '🧑🏽‍🦱', '🧑🏽‍🦲', '🧑🏽‍🦳', '🧑🏽‍🦼', '🧑🏽‍🦽', '🧑🏾‍🌾', '🧑🏾‍🍳', '🧑🏾‍🍼', '🧑🏾‍🎄', '🧑🏾‍🎓', '🧑🏾‍🎤', '🧑🏾‍🎨', '🧑🏾‍🏫', '🧑🏾‍🏭', '🧑🏾‍💻', '🧑🏾‍💼', '🧑🏾‍🔧', '🧑🏾‍🔬', '🧑🏾‍🚀', '🧑🏾‍🚒', '🧑🏾‍🦯', '🧑🏾‍🦰', '🧑🏾‍🦱', '🧑🏾‍🦲', '🧑🏾‍🦳', '🧑🏾‍🦼', '🧑🏾‍🦽', '🧑🏿‍🌾', '🧑🏿‍🍳', '🧑🏿‍🍼', '🧑🏿‍🎄', '🧑🏿‍🎓', '🧑🏿‍🎤', '🧑🏿‍🎨', '🧑🏿‍🏫', '🧑🏿‍🏭', '🧑🏿‍💻', '🧑🏿‍💼', '🧑🏿‍🔧', '🧑🏿‍🔬', '🧑🏿‍🚀', '🧑🏿‍🚒', '🧑🏿‍🦯', '🧑🏿‍🦰', '🧑🏿‍🦱', '🧑🏿‍🦲', '🧑🏿‍🦳', '🧑🏿‍🦼', '🧑🏿‍🦽', '🏳️‍🌈', '😶‍🌫️', '🏃‍♀️', '🏃‍♂️', '🏄‍♀️', '🏄‍♂️', '🏊‍♀️', '🏊‍♂️', '🏴‍☠️', '🐻‍❄️', '👨‍⚕️', '👨‍⚖️', '👨‍✈️', '👩‍⚕️', '👩‍⚖️', '👩‍✈️', '👮‍♀️', '👮‍♂️', '👯‍♀️', '👯‍♂️', '👰‍♀️', '👰‍♂️', '👱‍♀️', '👱‍♂️', '👳‍♀️', '👳‍♂️', '👷‍♀️', '👷‍♂️', '💁‍♀️', '💁‍♂️', '💂‍♀️', '💂‍♂️', '💆‍♀️', '💆‍♂️', '💇‍♀️', '💇‍♂️', '🙅‍♀️', '🙅‍♂️', '🙆‍♀️', '🙆‍♂️', '🙇‍♀️', '🙇‍♂️', '🙋‍♀️', '🙋‍♂️', '🙍‍♀️', '🙍‍♂️', '🙎‍♀️', '🙎‍♂️', '🚣‍♀️', '🚣‍♂️', '🚴‍♀️', '🚴‍♂️', '🚵‍♀️', '🚵‍♂️', '🚶‍♀️', '🚶‍♂️', '🤦‍♀️', '🤦‍♂️', '🤵‍♀️', '🤵‍♂️', '🤷‍♀️', '🤷‍♂️', '🤸‍♀️', '🤸‍♂️', '🤹‍♀️', '🤹‍♂️', '🤼‍♀️', '🤼‍♂️', '🤽‍♀️', '🤽‍♂️', '🤾‍♀️', '🤾‍♂️', '🦸‍♀️', '🦸‍♂️', '🦹‍♀️', '🦹‍♂️', '🧍‍♀️', '🧍‍♂️', '🧎‍♀️', '🧎‍♂️', '🧏‍♀️', '🧏‍♂️', '🧑‍⚕️', '🧑‍⚖️', '🧑‍✈️', '🧔‍♀️', '🧔‍♂️', '🧖‍♀️', '🧖‍♂️', '🧗‍♀️', '🧗‍♂️', '🧘‍♀️', '🧘‍♂️', '🧙‍♀️', '🧙‍♂️', '🧚‍♀️', '🧚‍♂️', '🧛‍♀️', '🧛‍♂️', '🧜‍♀️', '🧜‍♂️', '🧝‍♀️', '🧝‍♂️', '🧞‍♀️', '🧞‍♂️', '🧟‍♀️', '🧟‍♂️', '❤️‍🔥', '❤️‍🩹', '🐕‍🦺', '👁‍🗨', '👨‍🌾', '👨‍🍳', '👨‍🍼', '👨‍🎄', '👨‍🎓', '👨‍🎤', '👨‍🎨', '👨‍🏫', '👨‍🏭', '👨‍👦', '👨‍👧', '👨‍💻', '👨‍💼', '👨‍🔧', '👨‍🔬', '👨‍🚀', '👨‍🚒', '👨‍🦯', '👨‍🦰', '👨‍🦱', '👨‍🦲', '👨‍🦳', '👨‍🦼', '👨‍🦽', '👩‍🌾', '👩‍🍳', '👩‍🍼', '👩‍🎄', '👩‍🎓', '👩‍🎤', '👩‍🎨', '👩‍🏫', '👩‍🏭', '👩‍👦', '👩‍👧', '👩‍💻', '👩‍💼', '👩‍🔧', '👩‍🔬', '👩‍🚀', '👩‍🚒', '👩‍🦯', '👩‍🦰', '👩‍🦱', '👩‍🦲', '👩‍🦳', '👩‍🦼', '👩‍🦽', '😮‍💨', '😵‍💫', '🧑‍🌾', '🧑‍🍳', '🧑‍🍼', '🧑‍🎄', '🧑‍🎓', '🧑‍🎤', '🧑‍🎨', '🧑‍🏫', '🧑‍🏭', '🧑‍💻', '🧑‍💼', '🧑‍🔧', '🧑‍🔬', '🧑‍🚀', '🧑‍🚒', '🧑‍🦯', '🧑‍🦰', '🧑‍🦱', '🧑‍🦲', '🧑‍🦳', '🧑‍🦼', '🧑‍🦽', '🐈‍⬛', '🇦🇨', '🇦🇩', '🇦🇪', '🇦🇫', '🇦🇬', '🇦🇮', '🇦🇱', '🇦🇲', '🇦🇴', '🇦🇶', '🇦🇷', '🇦🇸', '🇦🇹', '🇦🇺', '🇦🇼', '🇦🇽', '🇦🇿', '🇧🇦', '🇧🇧', '🇧🇩', '🇧🇪', '🇧🇫', '🇧🇬', '🇧🇭', '🇧🇮', '🇧🇯', '🇧🇱', '🇧🇲', '🇧🇳', '🇧🇴', '🇧🇶', '🇧🇷', '🇧🇸', '🇧🇹', '🇧🇻', '🇧🇼', '🇧🇾', '🇧🇿', '🇨🇦', '🇨🇨', '🇨🇩', '🇨🇫', '🇨🇬', '🇨🇭', '🇨🇮', '🇨🇰', '🇨🇱', '🇨🇲', '🇨🇳', '🇨🇴', '🇨🇵', '🇨🇷', '🇨🇺', '🇨🇻', '🇨🇼', '🇨🇽', '🇨🇾', '🇨🇿', '🇩🇪', '🇩🇬', '🇩🇯', '🇩🇰', '🇩🇲', '🇩🇴', '🇩🇿', '🇪🇦', '🇪🇨', '🇪🇪', '🇪🇬', '🇪🇭', '🇪🇷', '🇪🇸', '🇪🇹', '🇪🇺', '🇫🇮', '🇫🇯', '🇫🇰', '🇫🇲', '🇫🇴', '🇫🇷', '🇬🇦', '🇬🇧', '🇬🇩', '🇬🇪', '🇬🇫', '🇬🇬', '🇬🇭', '🇬🇮', '🇬🇱', '🇬🇲', '🇬🇳', '🇬🇵', '🇬🇶', '🇬🇷', '🇬🇸', '🇬🇹', '🇬🇺', '🇬🇼', '🇬🇾', '🇭🇰', '🇭🇲', '🇭🇳', '🇭🇷', '🇭🇹', '🇭🇺', '🇮🇨', '🇮🇩', '🇮🇪', '🇮🇱', '🇮🇲', '🇮🇳', '🇮🇴', '🇮🇶', '🇮🇷', '🇮🇸', '🇮🇹', '🇯🇪', '🇯🇲', '🇯🇴', '🇯🇵', '🇰🇪', '🇰🇬', '🇰🇭', '🇰🇮', '🇰🇲', '🇰🇳', '🇰🇵', '🇰🇷', '🇰🇼', '🇰🇾', '🇰🇿', '🇱🇦', '🇱🇧', '🇱🇨', '🇱🇮', '🇱🇰', '🇱🇷', '🇱🇸', '🇱🇹', '🇱🇺', '🇱🇻', '🇱🇾', '🇲🇦', '🇲🇨', '🇲🇩', '🇲🇪', '🇲🇫', '🇲🇬', '🇲🇭', '🇲🇰', '🇲🇱', '🇲🇲', '🇲🇳', '🇲🇴', '🇲🇵', '🇲🇶', '🇲🇷', '🇲🇸', '🇲🇹', '🇲🇺', '🇲🇻', '🇲🇼', '🇲🇽', '🇲🇾', '🇲🇿', '🇳🇦', '🇳🇨', '🇳🇪', '🇳🇫', '🇳🇬', '🇳🇮', '🇳🇱', '🇳🇴', '🇳🇵', '🇳🇷', '🇳🇺', '🇳🇿', '🇴🇲', '🇵🇦', '🇵🇪', '🇵🇫', '🇵🇬', '🇵🇭', '🇵🇰', '🇵🇱', '🇵🇲', '🇵🇳', '🇵🇷', '🇵🇸', '🇵🇹', '🇵🇼', '🇵🇾', '🇶🇦', '🇷🇪', '🇷🇴', '🇷🇸', '🇷🇺', '🇷🇼', '🇸🇦', '🇸🇧', '🇸🇨', '🇸🇩', '🇸🇪', '🇸🇬', '🇸🇭', '🇸🇮', '🇸🇯', '🇸🇰', '🇸🇱', '🇸🇲', '🇸🇳', '🇸🇴', '🇸🇷', '🇸🇸', '🇸🇹', '🇸🇻', '🇸🇽', '🇸🇾', '🇸🇿', '🇹🇦', '🇹🇨', '🇹🇩', '🇹🇫', '🇹🇬', '🇹🇭', '🇹🇯', '🇹🇰', '🇹🇱', '🇹🇲', '🇹🇳', '🇹🇴', '🇹🇷', '🇹🇹', '🇹🇻', '🇹🇼', '🇹🇿', '🇺🇦', '🇺🇬', '🇺🇲', '🇺🇳', '🇺🇸', '🇺🇾', '🇺🇿', '🇻🇦', '🇻🇨', '🇻🇪', '🇻🇬', '🇻🇮', '🇻🇳', '🇻🇺', '🇼🇫', '🇼🇸', '🇽🇰', '🇾🇪', '🇾🇹', '🇿🇦', '🇿🇲', '🇿🇼', '🎅🏻', '🎅🏼', '🎅🏽', '🎅🏾', '🎅🏿', '🏂🏻', '🏂🏼', '🏂🏽', '🏂🏾', '🏂🏿', '🏃🏻', '🏃🏼', '🏃🏽', '🏃🏾', '🏃🏿', '🏄🏻', '🏄🏼', '🏄🏽', '🏄🏾', '🏄🏿', '🏇🏻', '🏇🏼', '🏇🏽', '🏇🏾', '🏇🏿', '🏊🏻', '🏊🏼', '🏊🏽', '🏊🏾', '🏊🏿', '🏋🏻', '🏋🏼', '🏋🏽', '🏋🏾', '🏋🏿', '🏌🏻', '🏌🏼', '🏌🏽', '🏌🏾', '🏌🏿', '👂🏻', '👂🏼', '👂🏽', '👂🏾', '👂🏿', '👃🏻', '👃🏼', '👃🏽', '👃🏾', '👃🏿', '👆🏻', '👆🏼', '👆🏽', '👆🏾', '👆🏿', '👇🏻', '👇🏼', '👇🏽', '👇🏾', '👇🏿', '👈🏻', '👈🏼', '👈🏽', '👈🏾', '👈🏿', '👉🏻', '👉🏼', '👉🏽', '👉🏾', '👉🏿', '👊🏻', '👊🏼', '👊🏽', '👊🏾', '👊🏿', '👋🏻', '👋🏼', '👋🏽', '👋🏾', '👋🏿', '👌🏻', '👌🏼', '👌🏽', '👌🏾', '👌🏿', '👍🏻', '👍🏼', '👍🏽', '👍🏾', '👍🏿', '👎🏻', '👎🏼', '👎🏽', '👎🏾', '👎🏿', '👏🏻', '👏🏼', '👏🏽', '👏🏾', '👏🏿', '👐🏻', '👐🏼', '👐🏽', '👐🏾', '👐🏿', '👦🏻', '👦🏼', '👦🏽', '👦🏾', '👦🏿', '👧🏻', '👧🏼', '👧🏽', '👧🏾', '👧🏿', '👨🏻', '👨🏼', '👨🏽', '👨🏾', '👨🏿', '👩🏻', '👩🏼', '👩🏽', '👩🏾', '👩🏿', '👫🏻', '👫🏼', '👫🏽', '👫🏾', '👫🏿', '👬🏻', '👬🏼', '👬🏽', '👬🏾', '👬🏿', '👭🏻', '👭🏼', '👭🏽', '👭🏾', '👭🏿', '👮🏻', '👮🏼', '👮🏽', '👮🏾', '👮🏿', '👰🏻', '👰🏼', '👰🏽', '👰🏾', '👰🏿', '👱🏻', '👱🏼', '👱🏽', '👱🏾', '👱🏿', '👲🏻', '👲🏼', '👲🏽', '👲🏾', '👲🏿', '👳🏻', '👳🏼', '👳🏽', '👳🏾', '👳🏿', '👴🏻', '👴🏼', '👴🏽', '👴🏾', '👴🏿', '👵🏻', '👵🏼', '👵🏽', '👵🏾', '👵🏿', '👶🏻', '👶🏼', '👶🏽', '👶🏾', '👶🏿', '👷🏻', '👷🏼', '👷🏽', '👷🏾', '👷🏿', '👸🏻', '👸🏼', '👸🏽', '👸🏾', '👸🏿', '👼🏻', '👼🏼', '👼🏽', '👼🏾', '👼🏿', '💁🏻', '💁🏼', '💁🏽', '💁🏾', '💁🏿', '💂🏻', '💂🏼', '💂🏽', '💂🏾', '💂🏿', '💃🏻', '💃🏼', '💃🏽', '💃🏾', '💃🏿', '💅🏻', '💅🏼', '💅🏽', '💅🏾', '💅🏿', '💆🏻', '💆🏼', '💆🏽', '💆🏾', '💆🏿', '💇🏻', '💇🏼', '💇🏽', '💇🏾', '💇🏿', '💏🏻', '💏🏼', '💏🏽', '💏🏾', '💏🏿', '💑🏻', '💑🏼', '💑🏽', '💑🏾', '💑🏿', '💪🏻', '💪🏼', '💪🏽', '💪🏾', '💪🏿', '🕴🏻', '🕴🏼', '🕴🏽', '🕴🏾', '🕴🏿', '🕵🏻', '🕵🏼', '🕵🏽', '🕵🏾', '🕵🏿', '🕺🏻', '🕺🏼', '🕺🏽', '🕺🏾', '🕺🏿', '🖐🏻', '🖐🏼', '🖐🏽', '🖐🏾', '🖐🏿', '🖕🏻', '🖕🏼', '🖕🏽', '🖕🏾', '🖕🏿', '🖖🏻', '🖖🏼', '🖖🏽', '🖖🏾', '🖖🏿', '🙅🏻', '🙅🏼', '🙅🏽', '🙅🏾', '🙅🏿', '🙆🏻', '🙆🏼', '🙆🏽', '🙆🏾', '🙆🏿', '🙇🏻', '🙇🏼', '🙇🏽', '🙇🏾', '🙇🏿', '🙋🏻', '🙋🏼', '🙋🏽', '🙋🏾', '🙋🏿', '🙌🏻', '🙌🏼', '🙌🏽', '🙌🏾', '🙌🏿', '🙍🏻', '🙍🏼', '🙍🏽', '🙍🏾', '🙍🏿', '🙎🏻', '🙎🏼', '🙎🏽', '🙎🏾', '🙎🏿', '🙏🏻', '🙏🏼', '🙏🏽', '🙏🏾', '🙏🏿', '🚣🏻', '🚣🏼', '🚣🏽', '🚣🏾', '🚣🏿', '🚴🏻', '🚴🏼', '🚴🏽', '🚴🏾', '🚴🏿', '🚵🏻', '🚵🏼', '🚵🏽', '🚵🏾', '🚵🏿', '🚶🏻', '🚶🏼', '🚶🏽', '🚶🏾', '🚶🏿', '🛀🏻', '🛀🏼', '🛀🏽', '🛀🏾', '🛀🏿', '🛌🏻', '🛌🏼', '🛌🏽', '🛌🏾', '🛌🏿', '🤌🏻', '🤌🏼', '🤌🏽', '🤌🏾', '🤌🏿', '🤏🏻', '🤏🏼', '🤏🏽', '🤏🏾', '🤏🏿', '🤘🏻', '🤘🏼', '🤘🏽', '🤘🏾', '🤘🏿', '🤙🏻', '🤙🏼', '🤙🏽', '🤙🏾', '🤙🏿', '🤚🏻', '🤚🏼', '🤚🏽', '🤚🏾', '🤚🏿', '🤛🏻', '🤛🏼', '🤛🏽', '🤛🏾', '🤛🏿', '🤜🏻', '🤜🏼', '🤜🏽', '🤜🏾', '🤜🏿', '🤝🏻', '🤝🏼', '🤝🏽', '🤝🏾', '🤝🏿', '🤞🏻', '🤞🏼', '🤞🏽', '🤞🏾', '🤞🏿', '🤟🏻', '🤟🏼', '🤟🏽', '🤟🏾', '🤟🏿', '🤦🏻', '🤦🏼', '🤦🏽', '🤦🏾', '🤦🏿', '🤰🏻', '🤰🏼', '🤰🏽', '🤰🏾', '🤰🏿', '🤱🏻', '🤱🏼', '🤱🏽', '🤱🏾', '🤱🏿', '🤲🏻', '🤲🏼', '🤲🏽', '🤲🏾', '🤲🏿', '🤳🏻', '🤳🏼', '🤳🏽', '🤳🏾', '🤳🏿', '🤴🏻', '🤴🏼', '🤴🏽', '🤴🏾', '🤴🏿', '🤵🏻', '🤵🏼', '🤵🏽', '🤵🏾', '🤵🏿', '🤶🏻', '🤶🏼', '🤶🏽', '🤶🏾', '🤶🏿', '🤷🏻', '🤷🏼', '🤷🏽', '🤷🏾', '🤷🏿', '🤸🏻', '🤸🏼', '🤸🏽', '🤸🏾', '🤸🏿', '🤹🏻', '🤹🏼', '🤹🏽', '🤹🏾', '🤹🏿', '🤽🏻', '🤽🏼', '🤽🏽', '🤽🏾', '🤽🏿', '🤾🏻', '🤾🏼', '🤾🏽', '🤾🏾', '🤾🏿', '🥷🏻', '🥷🏼', '🥷🏽', '🥷🏾', '🥷🏿', '🦵🏻', '🦵🏼', '🦵🏽', '🦵🏾', '🦵🏿', '🦶🏻', '🦶🏼', '🦶🏽', '🦶🏾', '🦶🏿', '🦸🏻', '🦸🏼', '🦸🏽', '🦸🏾', '🦸🏿', '🦹🏻', '🦹🏼', '🦹🏽', '🦹🏾', '🦹🏿', '🦻🏻', '🦻🏼', '🦻🏽', '🦻🏾', '🦻🏿', '🧍🏻', '🧍🏼', '🧍🏽', '🧍🏾', '🧍🏿', '🧎🏻', '🧎🏼', '🧎🏽', '🧎🏾', '🧎🏿', '🧏🏻', '🧏🏼', '🧏🏽', '🧏🏾', '🧏🏿', '🧑🏻', '🧑🏼', '🧑🏽', '🧑🏾', '🧑🏿', '🧒🏻', '🧒🏼', '🧒🏽', '🧒🏾', '🧒🏿', '🧓🏻', '🧓🏼', '🧓🏽', '🧓🏾', '🧓🏿', '🧔🏻', '🧔🏼', '🧔🏽', '🧔🏾', '🧔🏿', '🧕🏻', '🧕🏼', '🧕🏽', '🧕🏾', '🧕🏿', '🧖🏻', '🧖🏼', '🧖🏽', '🧖🏾', '🧖🏿', '🧗🏻', '🧗🏼', '🧗🏽', '🧗🏾', '🧗🏿', '🧘🏻', '🧘🏼', '🧘🏽', '🧘🏾', '🧘🏿', '🧙🏻', '🧙🏼', '🧙🏽', '🧙🏾', '🧙🏿', '🧚🏻', '🧚🏼', '🧚🏽', '🧚🏾', '🧚🏿', '🧛🏻', '🧛🏼', '🧛🏽', '🧛🏾', '🧛🏿', '🧜🏻', '🧜🏼', '🧜🏽', '🧜🏾', '🧜🏿', '🧝🏻', '🧝🏼', '🧝🏽', '🧝🏾', '🧝🏿', '🫃🏻', '🫃🏼', '🫃🏽', '🫃🏾', '🫃🏿', '🫄🏻', '🫄🏼', '🫄🏽', '🫄🏾', '🫄🏿', '🫅🏻', '🫅🏼', '🫅🏽', '🫅🏾', '🫅🏿', '🫰🏻', '🫰🏼', '🫰🏽', '🫰🏾', '🫰🏿', '🫱🏻', '🫱🏼', '🫱🏽', '🫱🏾', '🫱🏿', '🫲🏻', '🫲🏼', '🫲🏽', '🫲🏾', '🫲🏿', '🫳🏻', '🫳🏼', '🫳🏽', '🫳🏾', '🫳🏿', '🫴🏻', '🫴🏼', '🫴🏽', '🫴🏾', '🫴🏿', '🫵🏻', '🫵🏼', '🫵🏽', '🫵🏾', '🫵🏿', '🫶🏻', '🫶🏼', '🫶🏽', '🫶🏾', '🫶🏿', '☝🏻', '☝🏼', '☝🏽', '☝🏾', '☝🏿', '⛷🏻', '⛷🏼', '⛷🏽', '⛷🏾', '⛷🏿', '⛹🏻', '⛹🏼', '⛹🏽', '⛹🏾', '⛹🏿', '✊🏻', '✊🏼', '✊🏽', '✊🏾', '✊🏿', '✋🏻', '✋🏼', '✋🏽', '✋🏾', '✋🏿', '✌🏻', '✌🏼', '✌🏽', '✌🏾', '✌🏿', '✍🏻', '✍🏼', '✍🏽', '✍🏾', '✍🏿', '#⃣', '*⃣', '0⃣', '1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '🀄', '🃏', '🅰', '🅱', '🅾', '🅿', '🆎', '🆑', '🆒', '🆓', '🆔', '🆕', '🆖', '🆗', '🆘', '🆙', '🆚', '🇦', '🇧', '🇨', '🇩', '🇪', '🇫', '🇬', '🇭', '🇮', '🇯', '🇰', '🇱', '🇲', '🇳', '🇴', '🇵', '🇶', '🇷', '🇸', '🇹', '🇺', '🇻', '🇼', '🇽', '🇾', '🇿', '🈁', '🈂', '🈚', '🈯', '🈲', '🈳', '🈴', '🈵', '🈶', '🈷', '🈸', '🈹', '🈺', '🉐', '🉑', '🌀', '🌁', '🌂', '🌃', '🌄', '🌅', '🌆', '🌇', '🌈', '🌉', '🌊', '🌋', '🌌', '🌍', '🌎', '🌏', '🌐', '🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘', '🌙', '🌚', '🌛', '🌜', '🌝', '🌞', '🌟', '🌠', '🌡', '🌤', '🌥', '🌦', '🌧', '🌨', '🌩', '🌪', '🌫', '🌬', '🌭', '🌮', '🌯', '🌰', '🌱', '🌲', '🌳', '🌴', '🌵', '🌶', '🌷', '🌸', '🌹', '🌺', '🌻', '🌼', '🌽', '🌾', '🌿', '🍀', '🍁', '🍂', '🍃', '🍄', '🍅', '🍆', '🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🍎', '🍏', '🍐', '🍑', '🍒', '🍓', '🍔', '🍕', '🍖', '🍗', '🍘', '🍙', '🍚', '🍛', '🍜', '🍝', '🍞', '🍟', '🍠', '🍡', '🍢', '🍣', '🍤', '🍥', '🍦', '🍧', '🍨', '🍩', '🍪', '🍫', '🍬', '🍭', '🍮', '🍯', '🍰', '🍱', '🍲', '🍳', '🍴', '🍵', '🍶', '🍷', '🍸', '🍹', '🍺', '🍻', '🍼', '🍽', '🍾', '🍿', '🎀', '🎁', '🎂', '🎃', '🎄', '🎅', '🎆', '🎇', '🎈', '🎉', '🎊', '🎋', '🎌', '🎍', '🎎', '🎏', '🎐', '🎑', '🎒', '🎓', '🎖', '🎗', '🎙', '🎚', '🎛', '🎞', '🎟', '🎠', '🎡', '🎢', '🎣', '🎤', '🎥', '🎦', '🎧', '🎨', '🎩', '🎪', '🎫', '🎬', '🎭', '🎮', '🎯', '🎰', '🎱', '🎲', '🎳', '🎴', '🎵', '🎶', '🎷', '🎸', '🎹', '🎺', '🎻', '🎼', '🎽', '🎾', '🎿', '🏀', '🏁', '🏂', '🏃', '🏄', '🏅', '🏆', '🏇', '🏈', '🏉', '🏊', '🏋', '🏌', '🏍', '🏎', '🏏', '🏐', '🏑', '🏒', '🏓', '🏔', '🏕', '🏖', '🏗', '🏘', '🏙', '🏚', '🏛', '🏜', '🏝', '🏞', '🏟', '🏠', '🏡', '🏢', '🏣', '🏤', '🏥', '🏦', '🏧', '🏨', '🏩', '🏪', '🏫', '🏬', '🏭', '🏮', '🏯', '🏰', '🏳', '🏴', '🏵', '🏷', '🏸', '🏹', '🏺', '🏻', '🏼', '🏽', '🏾', '🏿', '🐀', '🐁', '🐂', '🐃', '🐄', '🐅', '🐆', '🐇', '🐈', '🐉', '🐊', '🐋', '🐌', '🐍', '🐎', '🐏', '🐐', '🐑', '🐒', '🐓', '🐔', '🐕', '🐖', '🐗', '🐘', '🐙', '🐚', '🐛', '🐜', '🐝', '🐞', '🐟', '🐠', '🐡', '🐢', '🐣', '🐤', '🐥', '🐦', '🐧', '🐨', '🐩', '🐪', '🐫', '🐬', '🐭', '🐮', '🐯', '🐰', '🐱', '🐲', '🐳', '🐴', '🐵', '🐶', '🐷', '🐸', '🐹', '🐺', '🐻', '🐼', '🐽', '🐾', '🐿', '👀', '👁', '👂', '👃', '👄', '👅', '👆', '👇', '👈', '👉', '👊', '👋', '👌', '👍', '👎', '👏', '👐', '👑', '👒', '👓', '👔', '👕', '👖', '👗', '👘', '👙', '👚', '👛', '👜', '👝', '👞', '👟', '👠', '👡', '👢', '👣', '👤', '👥', '👦', '👧', '👨', '👩', '👪', '👫', '👬', '👭', '👮', '👯', '👰', '👱', '👲', '👳', '👴', '👵', '👶', '👷', '👸', '👹', '👺', '👻', '👼', '👽', '👾', '👿', '💀', '💁', '💂', '💃', '💄', '💅', '💆', '💇', '💈', '💉', '💊', '💋', '💌', '💍', '💎', '💏', '💐', '💑', '💒', '💓', '💔', '💕', '💖', '💗', '💘', '💙', '💚', '💛', '💜', '💝', '💞', '💟', '💠', '💡', '💢', '💣', '💤', '💥', '💦', '💧', '💨', '💩', '💪', '💫', '💬', '💭', '💮', '💯', '💰', '💱', '💲', '💳', '💴', '💵', '💶', '💷', '💸', '💹', '💺', '💻', '💼', '💽', '💾', '💿', '📀', '📁', '📂', '📃', '📄', '📅', '📆', '📇', '📈', '📉', '📊', '📋', '📌', '📍', '📎', '📏', '📐', '📑', '📒', '📓', '📔', '📕', '📖', '📗', '📘', '📙', '📚', '📛', '📜', '📝', '📞', '📟', '📠', '📡', '📢', '📣', '📤', '📥', '📦', '📧', '📨', '📩', '📪', '📫', '📬', '📭', '📮', '📯', '📰', '📱', '📲', '📳', '📴', '📵', '📶', '📷', '📸', '📹', '📺', '📻', '📼', '📽', '📿', '🔀', '🔁', '🔂', '🔃', '🔄', '🔅', '🔆', '🔇', '🔈', '🔉', '🔊', '🔋', '🔌', '🔍', '🔎', '🔏', '🔐', '🔑', '🔒', '🔓', '🔔', '🔕', '🔖', '🔗', '🔘', '🔙', '🔚', '🔛', '🔜', '🔝', '🔞', '🔟', '🔠', '🔡', '🔢', '🔣', '🔤', '🔥', '🔦', '🔧', '🔨', '🔩', '🔪', '🔫', '🔬', '🔭', '🔮', '🔯', '🔰', '🔱', '🔲', '🔳', '🔴', '🔵', '🔶', '🔷', '🔸', '🔹', '🔺', '🔻', '🔼', '🔽', '🕉', '🕊', '🕋', '🕌', '🕍', '🕎', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛', '🕜', '🕝', '🕞', '🕟', '🕠', '🕡', '🕢', '🕣', '🕤', '🕥', '🕦', '🕧', '🕯', '🕰', '🕳', '🕴', '🕵', '🕶', '🕷', '🕸', '🕹', '🕺', '🖇', '🖊', '🖋', '🖌', '🖍', '🖐', '🖕', '🖖', '🖤', '🖥', '🖨', '🖱', '🖲', '🖼', '🗂', '🗃', '🗄', '🗑', '🗒', '🗓', '🗜', '🗝', '🗞', '🗡', '🗣', '🗨', '🗯', '🗳', '🗺', '🗻', '🗼', '🗽', '🗾', '🗿', '😀', '😁', '😂', '😃', '😄', '😅', '😆', '😇', '😈', '😉', '😊', '😋', '😌', '😍', '😎', '😏', '😐', '😑', '😒', '😓', '😔', '😕', '😖', '😗', '😘', '😙', '😚', '😛', '😜', '😝', '😞', '😟', '😠', '😡', '😢', '😣', '😤', '😥', '😦', '😧', '😨', '😩', '😪', '😫', '😬', '😭', '😮', '😯', '😰', '😱', '😲', '😳', '😴', '😵', '😶', '😷', '😸', '😹', '😺', '😻', '😼', '😽', '😾', '😿', '🙀', '🙁', '🙂', '🙃', '🙄', '🙅', '🙆', '🙇', '🙈', '🙉', '🙊', '🙋', '🙌', '🙍', '🙎', '🙏', '🚀', '🚁', '🚂', '🚃', '🚄', '🚅', '🚆', '🚇', '🚈', '🚉', '🚊', '🚋', '🚌', '🚍', '🚎', '🚏', '🚐', '🚑', '🚒', '🚓', '🚔', '🚕', '🚖', '🚗', '🚘', '🚙', '🚚', '🚛', '🚜', '🚝', '🚞', '🚟', '🚠', '🚡', '🚢', '🚣', '🚤', '🚥', '🚦', '🚧', '🚨', '🚩', '🚪', '🚫', '🚬', '🚭', '🚮', '🚯', '🚰', '🚱', '🚲', '🚳', '🚴', '🚵', '🚶', '🚷', '🚸', '🚹', '🚺', '🚻', '🚼', '🚽', '🚾', '🚿', '🛀', '🛁', '🛂', '🛃', '🛄', '🛅', '🛋', '🛌', '🛍', '🛎', '🛏', '🛐', '🛑', '🛒', '🛕', '🛖', '🛗', '🛝', '🛞', '🛟', '🛠', '🛡', '🛢', '🛣', '🛤', '🛥', '🛩', '🛫', '🛬', '🛰', '🛳', '🛴', '🛵', '🛶', '🛷', '🛸', '🛹', '🛺', '🛻', '🛼', '🟠', '🟡', '🟢', '🟣', '🟤', '🟥', '🟦', '🟧', '🟨', '🟩', '🟪', '🟫', '🟰', '🤌', '🤍', '🤎', '🤏', '🤐', '🤑', '🤒', '🤓', '🤔', '🤕', '🤖', '🤗', '🤘', '🤙', '🤚', '🤛', '🤜', '🤝', '🤞', '🤟', '🤠', '🤡', '🤢', '🤣', '🤤', '🤥', '🤦', '🤧', '🤨', '🤩', '🤪', '🤫', '🤬', '🤭', '🤮', '🤯', '🤰', '🤱', '🤲', '🤳', '🤴', '🤵', '🤶', '🤷', '🤸', '🤹', '🤺', '🤼', '🤽', '🤾', '🤿', '🥀', '🥁', '🥂', '🥃', '🥄', '🥅', '🥇', '🥈', '🥉', '🥊', '🥋', '🥌', '🥍', '🥎', '🥏', '🥐', '🥑', '🥒', '🥓', '🥔', '🥕', '🥖', '🥗', '🥘', '🥙', '🥚', '🥛', '🥜', '🥝', '🥞', '🥟', '🥠', '🥡', '🥢', '🥣', '🥤', '🥥', '🥦', '🥧', '🥨', '🥩', '🥪', '🥫', '🥬', '🥭', '🥮', '🥯', '🥰', '🥱', '🥲', '🥳', '🥴', '🥵', '🥶', '🥷', '🥸', '🥹', '🥺', '🥻', '🥼', '🥽', '🥾', '🥿', '🦀', '🦁', '🦂', '🦃', '🦄', '🦅', '🦆', '🦇', '🦈', '🦉', '🦊', '🦋', '🦌', '🦍', '🦎', '🦏', '🦐', '🦑', '🦒', '🦓', '🦔', '🦕', '🦖', '🦗', '🦘', '🦙', '🦚', '🦛', '🦜', '🦝', '🦞', '🦟', '🦠', '🦡', '🦢', '🦣', '🦤', '🦥', '🦦', '🦧', '🦨', '🦩', '🦪', '🦫', '🦬', '🦭', '🦮', '🦯', '🦰', '🦱', '🦲', '🦳', '🦴', '🦵', '🦶', '🦷', '🦸', '🦹', '🦺', '🦻', '🦼', '🦽', '🦾', '🦿', '🧀', '🧁', '🧂', '🧃', '🧄', '🧅', '🧆', '🧇', '🧈', '🧉', '🧊', '🧋', '🧌', '🧍', '🧎', '🧏', '🧐', '🧑', '🧒', '🧓', '🧔', '🧕', '🧖', '🧗', '🧘', '🧙', '🧚', '🧛', '🧜', '🧝', '🧞', '🧟', '🧠', '🧡', '🧢', '🧣', '🧤', '🧥', '🧦', '🧧', '🧨', '🧩', '🧪', '🧫', '🧬', '🧭', '🧮', '🧯', '🧰', '🧱', '🧲', '🧳', '🧴', '🧵', '🧶', '🧷', '🧸', '🧹', '🧺', '🧻', '🧼', '🧽', '🧾', '🧿', '🩰', '🩱', '🩲', '🩳', '🩴', '🩸', '🩹', '🩺', '🩻', '🩼', '🪀', '🪁', '🪂', '🪃', '🪄', '🪅', '🪆', '🪐', '🪑', '🪒', '🪓', '🪔', '🪕', '🪖', '🪗', '🪘', '🪙', '🪚', '🪛', '🪜', '🪝', '🪞', '🪟', '🪠', '🪡', '🪢', '🪣', '🪤', '🪥', '🪦', '🪧', '🪨', '🪩', '🪪', '🪫', '🪬', '🪰', '🪱', '🪲', '🪳', '🪴', '🪵', '🪶', '🪷', '🪸', '🪹', '🪺', '🫀', '🫁', '🫂', '🫃', '🫄', '🫅', '🫐', '🫑', '🫒', '🫓', '🫔', '🫕', '🫖', '🫗', '🫘', '🫙', '🫠', '🫡', '🫢', '🫣', '🫤', '🫥', '🫦', '🫧', '🫰', '🫱', '🫲', '🫳', '🫴', '🫵', '🫶', '‼', '⁉', '™', 'ℹ', '↔', '↕', '↖', '↗', '↘', '↙', '↩', '↪', '⌚', '⌛', '⌨', '⏏', '⏩', '⏪', '⏫', '⏬', '⏭', '⏮', '⏯', '⏰', '⏱', '⏲', '⏳', '⏸', '⏹', '⏺', 'Ⓜ', '▪', '▫', '▶', '◀', '◻', '◼', '◽', '◾', '☀', '☁', '☂', '☃', '☄', '☎', '☑', '☔', '☕', '☘', '☝', '☠', '☢', '☣', '☦', '☪', '☮', '☯', '☸', '☹', '☺', '♀', '♂', '♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '♟', '♠', '♣', '♥', '♦', '♨', '♻', '♾', '♿', '⚒', '⚓', '⚔', '⚕', '⚖', '⚗', '⚙', '⚛', '⚜', '⚠', '⚡', '⚧', '⚪', '⚫', '⚰', '⚱', '⚽', '⚾', '⛄', '⛅', '⛈', '⛎', '⛏', '⛑', '⛓', '⛔', '⛩', '⛪', '⛰', '⛱', '⛲', '⛳', '⛴', '⛵', '⛷', '⛸', '⛹', '⛺', '⛽', '✂', '✅', '✈', '✉', '✊', '✋', '✌', '✍', '✏', '✒', '✔', '✖', '✝', '✡', '✨', '✳', '✴', '❄', '❇', '❌', '❎', '❓', '❔', '❕', '❗', '❣', '❤', '➕', '➖', '➗', '➡', '➰', '➿', '⤴', '⤵', '⬅', '⬆', '⬇', '⬛', '⬜', '⭐', '⭕', '〰', '〽', '㊗', '㊙', '' ); $partials = array( '🀄', '🃏', '🅰', '🅱', '🅾', '🅿', '🆎', '🆑', '🆒', '🆓', '🆔', '🆕', '🆖', '🆗', '🆘', '🆙', '🆚', '🇦', '🇨', '🇩', '🇪', '🇫', '🇬', '🇮', '🇱', '🇲', '🇴', '🇶', '🇷', '🇸', '🇹', '🇺', '🇼', '🇽', '🇿', '🇧', '🇭', '🇯', '🇳', '🇻', '🇾', '🇰', '🇵', '🈁', '🈂', '🈚', '🈯', '🈲', '🈳', '🈴', '🈵', '🈶', '🈷', '🈸', '🈹', '🈺', '🉐', '🉑', '🌀', '🌁', '🌂', '🌃', '🌄', '🌅', '🌆', '🌇', '🌈', '🌉', '🌊', '🌋', '🌌', '🌍', '🌎', '🌏', '🌐', '🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘', '🌙', '🌚', '🌛', '🌜', '🌝', '🌞', '🌟', '🌠', '🌡', '🌤', '🌥', '🌦', '🌧', '🌨', '🌩', '🌪', '🌫', '🌬', '🌭', '🌮', '🌯', '🌰', '🌱', '🌲', '🌳', '🌴', '🌵', '🌶', '🌷', '🌸', '🌹', '🌺', '🌻', '🌼', '🌽', '🌾', '🌿', '🍀', '🍁', '🍂', '🍃', '🍄', '🍅', '🍆', '🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🍎', '🍏', '🍐', '🍑', '🍒', '🍓', '🍔', '🍕', '🍖', '🍗', '🍘', '🍙', '🍚', '🍛', '🍜', '🍝', '🍞', '🍟', '🍠', '🍡', '🍢', '🍣', '🍤', '🍥', '🍦', '🍧', '🍨', '🍩', '🍪', '🍫', '🍬', '🍭', '🍮', '🍯', '🍰', '🍱', '🍲', '🍳', '🍴', '🍵', '🍶', '🍷', '🍸', '🍹', '🍺', '🍻', '🍼', '🍽', '🍾', '🍿', '🎀', '🎁', '🎂', '🎃', '🎄', '🎅', '🏻', '🏼', '🏽', '🏾', '🏿', '🎆', '🎇', '🎈', '🎉', '🎊', '🎋', '🎌', '🎍', '🎎', '🎏', '🎐', '🎑', '🎒', '🎓', '🎖', '🎗', '🎙', '🎚', '🎛', '🎞', '🎟', '🎠', '🎡', '🎢', '🎣', '🎤', '🎥', '🎦', '🎧', '🎨', '🎩', '🎪', '🎫', '🎬', '🎭', '🎮', '🎯', '🎰', '🎱', '🎲', '🎳', '🎴', '🎵', '🎶', '🎷', '🎸', '🎹', '🎺', '🎻', '🎼', '🎽', '🎾', '🎿', '🏀', '🏁', '🏂', '🏃', '‍', '♀', '️', '♂', '🏄', '🏅', '🏆', '🏇', '🏈', '🏉', '🏊', '🏋', '🏌', '🏍', '🏎', '🏏', '🏐', '🏑', '🏒', '🏓', '🏔', '🏕', '🏖', '🏗', '🏘', '🏙', '🏚', '🏛', '🏜', '🏝', '🏞', '🏟', '🏠', '🏡', '🏢', '🏣', '🏤', '🏥', '🏦', '🏧', '🏨', '🏩', '🏪', '🏫', '🏬', '🏭', '🏮', '🏯', '🏰', '🏳', '⚧', '🏴', '☠', '󠁧', '󠁢', '󠁥', '󠁮', '󠁿', '󠁳', '󠁣', '󠁴', '󠁷', '󠁬', '🏵', '🏷', '🏸', '🏹', '🏺', '🐀', '🐁', '🐂', '🐃', '🐄', '🐅', '🐆', '🐇', '🐈', '⬛', '🐉', '🐊', '🐋', '🐌', '🐍', '🐎', '🐏', '🐐', '🐑', '🐒', '🐓', '🐔', '🐕', '🦺', '🐖', '🐗', '🐘', '🐙', '🐚', '🐛', '🐜', '🐝', '🐞', '🐟', '🐠', '🐡', '🐢', '🐣', '🐤', '🐥', '🐦', '🐧', '🐨', '🐩', '🐪', '🐫', '🐬', '🐭', '🐮', '🐯', '🐰', '🐱', '🐲', '🐳', '🐴', '🐵', '🐶', '🐷', '🐸', '🐹', '🐺', '🐻', '❄', '🐼', '🐽', '🐾', '🐿', '👀', '👁', '🗨', '👂', '👃', '👄', '👅', '👆', '👇', '👈', '👉', '👊', '👋', '👌', '👍', '👎', '👏', '👐', '👑', '👒', '👓', '👔', '👕', '👖', '👗', '👘', '👙', '👚', '👛', '👜', '👝', '👞', '👟', '👠', '👡', '👢', '👣', '👤', '👥', '👦', '👧', '👨', '💻', '💼', '🔧', '🔬', '🚀', '🚒', '🤝', '🦯', '🦰', '🦱', '🦲', '🦳', '🦼', '🦽', '⚕', '⚖', '✈', '❤', '💋', '👩', '👪', '👫', '👬', '👭', '👮', '👯', '👰', '👱', '👲', '👳', '👴', '👵', '👶', '👷', '👸', '👹', '👺', '👻', '👼', '👽', '👾', '👿', '💀', '💁', '💂', '💃', '💄', '💅', '💆', '💇', '💈', '💉', '💊', '💌', '💍', '💎', '💏', '💐', '💑', '💒', '💓', '💔', '💕', '💖', '💗', '💘', '💙', '💚', '💛', '💜', '💝', '💞', '💟', '💠', '💡', '💢', '💣', '💤', '💥', '💦', '💧', '💨', '💩', '💪', '💫', '💬', '💭', '💮', '💯', '💰', '💱', '💲', '💳', '💴', '💵', '💶', '💷', '💸', '💹', '💺', '💽', '💾', '💿', '📀', '📁', '📂', '📃', '📄', '📅', '📆', '📇', '📈', '📉', '📊', '📋', '📌', '📍', '📎', '📏', '📐', '📑', '📒', '📓', '📔', '📕', '📖', '📗', '📘', '📙', '📚', '📛', '📜', '📝', '📞', '📟', '📠', '📡', '📢', '📣', '📤', '📥', '📦', '📧', '📨', '📩', '📪', '📫', '📬', '📭', '📮', '📯', '📰', '📱', '📲', '📳', '📴', '📵', '📶', '📷', '📸', '📹', '📺', '📻', '📼', '📽', '📿', '🔀', '🔁', '🔂', '🔃', '🔄', '🔅', '🔆', '🔇', '🔈', '🔉', '🔊', '🔋', '🔌', '🔍', '🔎', '🔏', '🔐', '🔑', '🔒', '🔓', '🔔', '🔕', '🔖', '🔗', '🔘', '🔙', '🔚', '🔛', '🔜', '🔝', '🔞', '🔟', '🔠', '🔡', '🔢', '🔣', '🔤', '🔥', '🔦', '🔨', '🔩', '🔪', '🔫', '🔭', '🔮', '🔯', '🔰', '🔱', '🔲', '🔳', '🔴', '🔵', '🔶', '🔷', '🔸', '🔹', '🔺', '🔻', '🔼', '🔽', '🕉', '🕊', '🕋', '🕌', '🕍', '🕎', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛', '🕜', '🕝', '🕞', '🕟', '🕠', '🕡', '🕢', '🕣', '🕤', '🕥', '🕦', '🕧', '🕯', '🕰', '🕳', '🕴', '🕵', '🕶', '🕷', '🕸', '🕹', '🕺', '🖇', '🖊', '🖋', '🖌', '🖍', '🖐', '🖕', '🖖', '🖤', '🖥', '🖨', '🖱', '🖲', '🖼', '🗂', '🗃', '🗄', '🗑', '🗒', '🗓', '🗜', '🗝', '🗞', '🗡', '🗣', '🗯', '🗳', '🗺', '🗻', '🗼', '🗽', '🗾', '🗿', '😀', '😁', '😂', '😃', '😄', '😅', '😆', '😇', '😈', '😉', '😊', '😋', '😌', '😍', '😎', '😏', '😐', '😑', '😒', '😓', '😔', '😕', '😖', '😗', '😘', '😙', '😚', '😛', '😜', '😝', '😞', '😟', '😠', '😡', '😢', '😣', '😤', '😥', '😦', '😧', '😨', '😩', '😪', '😫', '😬', '😭', '😮', '😯', '😰', '😱', '😲', '😳', '😴', '😵', '😶', '😷', '😸', '😹', '😺', '😻', '😼', '😽', '😾', '😿', '🙀', '🙁', '🙂', '🙃', '🙄', '🙅', '🙆', '🙇', '🙈', '🙉', '🙊', '🙋', '🙌', '🙍', '🙎', '🙏', '🚁', '🚂', '🚃', '🚄', '🚅', '🚆', '🚇', '🚈', '🚉', '🚊', '🚋', '🚌', '🚍', '🚎', '🚏', '🚐', '🚑', '🚓', '🚔', '🚕', '🚖', '🚗', '🚘', '🚙', '🚚', '🚛', '🚜', '🚝', '🚞', '🚟', '🚠', '🚡', '🚢', '🚣', '🚤', '🚥', '🚦', '🚧', '🚨', '🚩', '🚪', '🚫', '🚬', '🚭', '🚮', '🚯', '🚰', '🚱', '🚲', '🚳', '🚴', '🚵', '🚶', '🚷', '🚸', '🚹', '🚺', '🚻', '🚼', '🚽', '🚾', '🚿', '🛀', '🛁', '🛂', '🛃', '🛄', '🛅', '🛋', '🛌', '🛍', '🛎', '🛏', '🛐', '🛑', '🛒', '🛕', '🛖', '🛗', '🛝', '🛞', '🛟', '🛠', '🛡', '🛢', '🛣', '🛤', '🛥', '🛩', '🛫', '🛬', '🛰', '🛳', '🛴', '🛵', '🛶', '🛷', '🛸', '🛹', '🛺', '🛻', '🛼', '🟠', '🟡', '🟢', '🟣', '🟤', '🟥', '🟦', '🟧', '🟨', '🟩', '🟪', '🟫', '🟰', '🤌', '🤍', '🤎', '🤏', '🤐', '🤑', '🤒', '🤓', '🤔', '🤕', '🤖', '🤗', '🤘', '🤙', '🤚', '🤛', '🤜', '🤞', '🤟', '🤠', '🤡', '🤢', '🤣', '🤤', '🤥', '🤦', '🤧', '🤨', '🤩', '🤪', '🤫', '🤬', '🤭', '🤮', '🤯', '🤰', '🤱', '🤲', '🤳', '🤴', '🤵', '🤶', '🤷', '🤸', '🤹', '🤺', '🤼', '🤽', '🤾', '🤿', '🥀', '🥁', '🥂', '🥃', '🥄', '🥅', '🥇', '🥈', '🥉', '🥊', '🥋', '🥌', '🥍', '🥎', '🥏', '🥐', '🥑', '🥒', '🥓', '🥔', '🥕', '🥖', '🥗', '🥘', '🥙', '🥚', '🥛', '🥜', '🥝', '🥞', '🥟', '🥠', '🥡', '🥢', '🥣', '🥤', '🥥', '🥦', '🥧', '🥨', '🥩', '🥪', '🥫', '🥬', '🥭', '🥮', '🥯', '🥰', '🥱', '🥲', '🥳', '🥴', '🥵', '🥶', '🥷', '🥸', '🥹', '🥺', '🥻', '🥼', '🥽', '🥾', '🥿', '🦀', '🦁', '🦂', '🦃', '🦄', '🦅', '🦆', '🦇', '🦈', '🦉', '🦊', '🦋', '🦌', '🦍', '🦎', '🦏', '🦐', '🦑', '🦒', '🦓', '🦔', '🦕', '🦖', '🦗', '🦘', '🦙', '🦚', '🦛', '🦜', '🦝', '🦞', '🦟', '🦠', '🦡', '🦢', '🦣', '🦤', '🦥', '🦦', '🦧', '🦨', '🦩', '🦪', '🦫', '🦬', '🦭', '🦮', '🦴', '🦵', '🦶', '🦷', '🦸', '🦹', '🦻', '🦾', '🦿', '🧀', '🧁', '🧂', '🧃', '🧄', '🧅', '🧆', '🧇', '🧈', '🧉', '🧊', '🧋', '🧌', '🧍', '🧎', '🧏', '🧐', '🧑', '🧒', '🧓', '🧔', '🧕', '🧖', '🧗', '🧘', '🧙', '🧚', '🧛', '🧜', '🧝', '🧞', '🧟', '🧠', '🧡', '🧢', '🧣', '🧤', '🧥', '🧦', '🧧', '🧨', '🧩', '🧪', '🧫', '🧬', '🧭', '🧮', '🧯', '🧰', '🧱', '🧲', '🧳', '🧴', '🧵', '🧶', '🧷', '🧸', '🧹', '🧺', '🧻', '🧼', '🧽', '🧾', '🧿', '🩰', '🩱', '🩲', '🩳', '🩴', '🩸', '🩹', '🩺', '🩻', '🩼', '🪀', '🪁', '🪂', '🪃', '🪄', '🪅', '🪆', '🪐', '🪑', '🪒', '🪓', '🪔', '🪕', '🪖', '🪗', '🪘', '🪙', '🪚', '🪛', '🪜', '🪝', '🪞', '🪟', '🪠', '🪡', '🪢', '🪣', '🪤', '🪥', '🪦', '🪧', '🪨', '🪩', '🪪', '🪫', '🪬', '🪰', '🪱', '🪲', '🪳', '🪴', '🪵', '🪶', '🪷', '🪸', '🪹', '🪺', '🫀', '🫁', '🫂', '🫃', '🫄', '🫅', '🫐', '🫑', '🫒', '🫓', '🫔', '🫕', '🫖', '🫗', '🫘', '🫙', '🫠', '🫡', '🫢', '🫣', '🫤', '🫥', '🫦', '🫧', '🫰', '🫱', '🫲', '🫳', '🫴', '🫵', '🫶', '‼', '⁉', '™', 'ℹ', '↔', '↕', '↖', '↗', '↘', '↙', '↩', '↪', '⃣', '⌚', '⌛', '⌨', '⏏', '⏩', '⏪', '⏫', '⏬', '⏭', '⏮', '⏯', '⏰', '⏱', '⏲', '⏳', '⏸', '⏹', '⏺', 'Ⓜ', '▪', '▫', '▶', '◀', '◻', '◼', '◽', '◾', '☀', '☁', '☂', '☃', '☄', '☎', '☑', '☔', '☕', '☘', '☝', '☢', '☣', '☦', '☪', '☮', '☯', '☸', '☹', '☺', '♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '♟', '♠', '♣', '♥', '♦', '♨', '♻', '♾', '♿', '⚒', '⚓', '⚔', '⚗', '⚙', '⚛', '⚜', '⚠', '⚡', '⚪', '⚫', '⚰', '⚱', '⚽', '⚾', '⛄', '⛅', '⛈', '⛎', '⛏', '⛑', '⛓', '⛔', '⛩', '⛪', '⛰', '⛱', '⛲', '⛳', '⛴', '⛵', '⛷', '⛸', '⛹', '⛺', '⛽', '✂', '✅', '✉', '✊', '✋', '✌', '✍', '✏', '✒', '✔', '✖', '✝', '✡', '✨', '✳', '✴', '❇', '❌', '❎', '❓', '❔', '❕', '❗', '❣', '➕', '➖', '➗', '➡', '➰', '➿', '⤴', '⤵', '⬅', '⬆', '⬇', '⬜', '⭐', '⭕', '〰', '〽', '㊗', '㊙', '' ); // END: emoji arrays if ( 'entities' === $type ) { return $entities; } return $partials; } /** * Shortens a URL, to be used as link text. * * @since 1.2.0 * @since 4.4.0 Moved to wp-includes/formatting.php from wp-admin/includes/misc.php and added $length param. * * @param string $url URL to shorten. * @param int $length Optional. Maximum length of the shortened URL. Default 35 characters. * @return string Shortened URL. */ function url_shorten( $url, $length = 35 ) { $stripped = str_replace( array( 'https://', 'http://', 'www.' ), '', $url ); $short_url = untrailingslashit( $stripped ); if ( strlen( $short_url ) > $length ) { $short_url = substr( $short_url, 0, $length - 3 ) . '…'; } return $short_url; } /** * Sanitizes a hex color. * * Returns either '', a 3 or 6 digit hex color (with #), or nothing. * For sanitizing values without a #, see sanitize_hex_color_no_hash(). * * @since 3.4.0 * * @param string $color * @return string|void */ function sanitize_hex_color( $color ) { if ( '' === $color ) { return ''; } // 3 or 6 hex digits, or the empty string. if ( preg_match( '|^#([A-Fa-f0-9]{3}){1,2}$|', $color ) ) { return $color; } } /** * Sanitizes a hex color without a hash. Use sanitize_hex_color() when possible. * * Saving hex colors without a hash puts the burden of adding the hash on the * UI, which makes it difficult to use or upgrade to other color types such as * rgba, hsl, rgb, and HTML color names. * * Returns either '', a 3 or 6 digit hex color (without a #), or null. * * @since 3.4.0 * * @param string $color * @return string|null */ function sanitize_hex_color_no_hash( $color ) { $color = ltrim( $color, '#' ); if ( '' === $color ) { return ''; } return sanitize_hex_color( '#' . $color ) ? $color : null; } /** * Ensures that any hex color is properly hashed. * Otherwise, returns value untouched. * * This method should only be necessary if using sanitize_hex_color_no_hash(). * * @since 3.4.0 * * @param string $color * @return string */ function maybe_hash_hex_color( $color ) { $unhashed = sanitize_hex_color_no_hash( $color ); if ( $unhashed ) { return '#' . $unhashed; } return $color; } ); if ( ! $term_info ) { // Skip if a non-existent term ID is passed. if ( is_int( $term ) ) { continue; } } if ( is_wp_error( $term_info ) ) { return $term_info; } $tt_ids[] = $term_info['term_taxonomy_id']; } if ( $tt_ids ) { $in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'"; /** * Fires immediately before an object-term relationship is deleted. * * @since 2.9.0 * @since 4.7.0 Added the `$taxonomy` parameter. * * @param int $object_id Object ID. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. */ do_action( 'delete_term_relationships', $object_id, $tt_ids, $taxonomy ); $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) ); wp_cache_delete( $object_id, $taxonomy . '_relationships' ); wp_cache_set_terms_last_changed(); /** * Fires immediately after an object-term relationship is deleted. * * @since 2.9.0 * @since 4.7.0 Added the `$taxonomy` parameter. * * @param int $object_id Object ID. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. */ do_action( 'deleted_term_relationships', $object_id, $tt_ids, $taxonomy ); wp_update_term_count( $tt_ids, $taxonomy ); return (bool) $deleted; } return false; } /** * Makes term slug unique, if it isn't already. * * The `$slug` has to be unique global to every taxonomy, meaning that one * taxonomy term can't have a matching slug with another taxonomy term. Each * slug has to be globally unique for every taxonomy. * * The way this works is that if the taxonomy that the term belongs to is * hierarchical and has a parent, it will append that parent to the $slug. * * If that still doesn't return a unique slug, then it tries to append a number * until it finds a number that is truly unique. * * The only purpose for `$term` is for appending a parent, if one exists. * * @since 2.3.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $slug The string that will be tried for a unique slug. * @param object $term The term object that the `$slug` will belong to. * @return string Will return a true unique slug. */ function wp_unique_term_slug( $slug, $term ) { global $wpdb; $needs_suffix = true; $original_slug = $slug; // As of 4.1, duplicate slugs are allowed as long as they're in different taxonomies. if ( ! term_exists( $slug ) || get_option( 'db_version' ) >= 30133 && ! get_term_by( 'slug', $slug, $term->taxonomy ) ) { $needs_suffix = false; } /* * If the taxonomy supports hierarchy and the term has a parent, make the slug unique * by incorporating parent slugs. */ $parent_suffix = ''; if ( $needs_suffix && is_taxonomy_hierarchical( $term->taxonomy ) && ! empty( $term->parent ) ) { $the_parent = $term->parent; while ( ! empty( $the_parent ) ) { $parent_term = get_term( $the_parent, $term->taxonomy ); if ( is_wp_error( $parent_term ) || empty( $parent_term ) ) { break; } $parent_suffix .= '-' . $parent_term->slug; if ( ! term_exists( $slug . $parent_suffix ) ) { break; } if ( empty( $parent_term->parent ) ) { break; } $the_parent = $parent_term->parent; } } // If we didn't get a unique slug, try appending a number to make it unique. /** * Filters whether the proposed unique term slug is bad. * * @since 4.3.0 * * @param bool $needs_suffix Whether the slug needs to be made unique with a suffix. * @param string $slug The slug. * @param object $term Term object. */ if ( apply_filters( 'wp_unique_term_slug_is_bad_slug', $needs_suffix, $slug, $term ) ) { if ( $parent_suffix ) { $slug .= $parent_suffix; } if ( ! empty( $term->term_id ) ) { $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id ); } else { $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug ); } if ( $wpdb->get_var( $query ) ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $num = 2; do { $alt_slug = $slug . "-$num"; ++$num; $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) ); } while ( $slug_check ); $slug = $alt_slug; } } /** * Filters the unique term slug. * * @since 4.3.0 * * @param string $slug Unique term slug. * @param object $term Term object. * @param string $original_slug Slug originally passed to the function for testing. */ return apply_filters( 'wp_unique_term_slug', $slug, $term, $original_slug ); } /** * Updates term based on arguments provided. * * The `$args` will indiscriminately override all values with the same field name. * Care must be taken to not override important information need to update or * update will fail (or perhaps create a new term, neither would be acceptable). * * Defaults will set 'alias_of', 'description', 'parent', and 'slug' if not * defined in `$args` already. * * 'alias_of' will create a term group, if it doesn't already exist, and * update it for the `$term`. * * If the 'slug' argument in `$args` is missing, then the 'name' will be used. * If you set 'slug' and it isn't unique, then a WP_Error is returned. * If you don't pass any slug, then a unique one will be created. * * @since 2.3.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $term_id The ID of the term. * @param string $taxonomy The taxonomy of the term. * @param array $args { * Optional. Array of arguments for updating a term. * * @type string $alias_of Slug of the term to make this term an alias of. * Default empty string. Accepts a term slug. * @type string $description The term description. Default empty string. * @type int $parent The id of the parent term. Default 0. * @type string $slug The term slug to use. Default empty string. * } * @return array|WP_Error An array containing the `term_id` and `term_taxonomy_id`, * WP_Error otherwise. */ function wp_update_term( $term_id, $taxonomy, $args = array() ) { global $wpdb; if ( ! taxonomy_exists( $taxonomy ) ) { return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); } $term_id = (int) $term_id; // First, get all of the original args. $term = get_term( $term_id, $taxonomy ); if ( is_wp_error( $term ) ) { return $term; } if ( ! $term ) { return new WP_Error( 'invalid_term', __( 'Empty Term.' ) ); } $term = (array) $term->data; // Escape data pulled from DB. $term = wp_slash( $term ); // Merge old and new args with new args overwriting old ones. $args = array_merge( $term, $args ); $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '', ); $args = wp_parse_args( $args, $defaults ); $args = sanitize_term( $args, $taxonomy, 'db' ); $parsed_args = $args; // expected_slashed ($name) $name = wp_unslash( $args['name'] ); $description = wp_unslash( $args['description'] ); $parsed_args['name'] = $name; $parsed_args['description'] = $description; if ( '' === trim( $name ) ) { return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) ); } if ( (int) $parsed_args['parent'] > 0 && ! term_exists( (int) $parsed_args['parent'] ) ) { return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) ); } $empty_slug = false; if ( empty( $args['slug'] ) ) { $empty_slug = true; $slug = sanitize_title( $name ); } else { $slug = $args['slug']; } $parsed_args['slug'] = $slug; $term_group = isset( $parsed_args['term_group'] ) ? $parsed_args['term_group'] : 0; if ( $args['alias_of'] ) { $alias = get_term_by( 'slug', $args['alias_of'], $taxonomy ); if ( ! empty( $alias->term_group ) ) { // The alias we want is already in a group, so let's use that one. $term_group = $alias->term_group; } elseif ( ! empty( $alias->term_id ) ) { /* * The alias is not in a group, so we create a new one * and add the alias to it. */ $term_group = $wpdb->get_var( "SELECT MAX(term_group) FROM $wpdb->terms" ) + 1; wp_update_term( $alias->term_id, $taxonomy, array( 'term_group' => $term_group, ) ); } $parsed_args['term_group'] = $term_group; } /** * Filters the term parent. * * Hook to this filter to see if it will cause a hierarchy loop. * * @since 3.1.0 * * @param int $parent_term ID of the parent term. * @param int $term_id Term ID. * @param string $taxonomy Taxonomy slug. * @param array $parsed_args An array of potentially altered update arguments for the given term. * @param array $args Arguments passed to wp_update_term(). */ $parent = (int) apply_filters( 'wp_update_term_parent', $args['parent'], $term_id, $taxonomy, $parsed_args, $args ); // Check for duplicate slug. $duplicate = get_term_by( 'slug', $slug, $taxonomy ); if ( $duplicate && $duplicate->term_id !== $term_id ) { /* * If an empty slug was passed or the parent changed, reset the slug to something unique. * Otherwise, bail. */ if ( $empty_slug || ( $parent !== (int) $term['parent'] ) ) { $slug = wp_unique_term_slug( $slug, (object) $args ); } else { /* translators: %s: Taxonomy term slug. */ return new WP_Error( 'duplicate_term_slug', sprintf( __( 'The slug “%s” is already in use by another term.' ), $slug ) ); } } $tt_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) ); // Check whether this is a shared term that needs splitting. $_term_id = _split_shared_term( $term_id, $tt_id ); if ( ! is_wp_error( $_term_id ) ) { $term_id = $_term_id; } /** * Fires immediately before the given terms are edited. * * @since 2.9.0 * @since 6.1.0 The `$args` parameter was added. * * @param int $term_id Term ID. * @param string $taxonomy Taxonomy slug. * @param array $args Arguments passed to wp_update_term(). */ do_action( 'edit_terms', $term_id, $taxonomy, $args ); $data = compact( 'name', 'slug', 'term_group' ); /** * Filters term data before it is updated in the database. * * @since 4.7.0 * * @param array $data Term data to be updated. * @param int $term_id Term ID. * @param string $taxonomy Taxonomy slug. * @param array $args Arguments passed to wp_update_term(). */ $data = apply_filters( 'wp_update_term_data', $data, $term_id, $taxonomy, $args ); $wpdb->update( $wpdb->terms, $data, compact( 'term_id' ) ); if ( empty( $slug ) ) { $slug = sanitize_title( $name, $term_id ); $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) ); } /** * Fires immediately after a term is updated in the database, but before its * term-taxonomy relationship is updated. * * @since 2.9.0 * @since 6.1.0 The `$args` parameter was added. * * @param int $term_id Term ID. * @param string $taxonomy Taxonomy slug. * @param array $args Arguments passed to wp_update_term(). */ do_action( 'edited_terms', $term_id, $taxonomy, $args ); /** * Fires immediate before a term-taxonomy relationship is updated. * * @since 2.9.0 * @since 6.1.0 The `$args` parameter was added. * * @param int $tt_id Term taxonomy ID. * @param string $taxonomy Taxonomy slug. * @param array $args Arguments passed to wp_update_term(). */ do_action( 'edit_term_taxonomy', $tt_id, $taxonomy, $args ); $wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) ); /** * Fires immediately after a term-taxonomy relationship is updated. * * @since 2.9.0 * @since 6.1.0 The `$args` parameter was added. * * @param int $tt_id Term taxonomy ID. * @param string $taxonomy Taxonomy slug. * @param array $args Arguments passed to wp_update_term(). */ do_action( 'edited_term_taxonomy', $tt_id, $taxonomy, $args ); /** * Fires after a term has been updated, but before the term cache has been cleaned. * * The {@see 'edit_$taxonomy'} hook is also available for targeting a specific * taxonomy. * * @since 2.3.0 * @since 6.1.0 The `$args` parameter was added. * * @param int $term_id Term ID. * @param int $tt_id Term taxonomy ID. * @param string $taxonomy Taxonomy slug. * @param array $args Arguments passed to wp_update_term(). */ do_action( 'edit_term', $term_id, $tt_id, $taxonomy, $args ); /** * Fires after a term in a specific taxonomy has been updated, but before the term * cache has been cleaned. * * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. * * Possible hook names include: * * - `edit_category` * - `edit_post_tag` * * @since 2.3.0 * @since 6.1.0 The `$args` parameter was added. * * @param int $term_id Term ID. * @param int $tt_id Term taxonomy ID. * @param array $args Arguments passed to wp_update_term(). */ do_action( "edit_{$taxonomy}", $term_id, $tt_id, $args ); /** This filter is documented in wp-includes/taxonomy.php */ $term_id = apply_filters( 'term_id_filter', $term_id, $tt_id ); clean_term_cache( $term_id, $taxonomy ); /** * Fires after a term has been updated, and the term cache has been cleaned. * * The {@see 'edited_$taxonomy'} hook is also available for targeting a specific * taxonomy. * * @since 2.3.0 * @since 6.1.0 The `$args` parameter was added. * * @param int $term_id Term ID. * @param int $tt_id Term taxonomy ID. * @param string $taxonomy Taxonomy slug. * @param array $args Arguments passed to wp_update_term(). */ do_action( 'edited_term', $term_id, $tt_id, $taxonomy, $args ); /** * Fires after a term for a specific taxonomy has been updated, and the term * cache has been cleaned. * * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. * * Possible hook names include: * * - `edited_category` * - `edited_post_tag` * * @since 2.3.0 * @since 6.1.0 The `$args` parameter was added. * * @param int $term_id Term ID. * @param int $tt_id Term taxonomy ID. * @param array $args Arguments passed to wp_update_term(). */ do_action( "edited_{$taxonomy}", $term_id, $tt_id, $args ); /** This action is documented in wp-includes/taxonomy.php */ do_action( 'saved_term', $term_id, $tt_id, $taxonomy, true, $args ); /** This action is documented in wp-includes/taxonomy.php */ do_action( "saved_{$taxonomy}", $term_id, $tt_id, true, $args ); return array( 'term_id' => $term_id, 'term_taxonomy_id' => $tt_id, ); } /** * Enables or disables term counting. * * @since 2.5.0 * * @param bool $defer Optional. Enable if true, disable if false. * @return bool Whether term counting is enabled or disabled. */ function wp_defer_term_counting( $defer = null ) { static $_defer = false; if ( is_bool( $defer ) ) { $_defer = $defer; // Flush any deferred counts. if ( ! $defer ) { wp_update_term_count( null, null, true ); } } return $_defer; } /** * Updates the amount of terms in taxonomy. * * If there is a taxonomy callback applied, then it will be called for updating * the count. * * The default action is to count what the amount of terms have the relationship * of term ID. Once that is done, then update the database. * * @since 2.3.0 * * @param int|array $terms The term_taxonomy_id of the terms. * @param string $taxonomy The context of the term. * @param bool $do_deferred Whether to flush the deferred term counts too. Default false. * @return bool If no terms will return false, and if successful will return true. */ function wp_update_term_count( $terms, $taxonomy, $do_deferred = false ) { static $_deferred = array(); if ( $do_deferred ) { foreach ( (array) array_keys( $_deferred ) as $tax ) { wp_update_term_count_now( $_deferred[ $tax ], $tax ); unset( $_deferred[ $tax ] ); } } if ( empty( $terms ) ) { return false; } if ( ! is_array( $terms ) ) { $terms = array( $terms ); } if ( wp_defer_term_counting() ) { if ( ! isset( $_deferred[ $taxonomy ] ) ) { $_deferred[ $taxonomy ] = array(); } $_deferred[ $taxonomy ] = array_unique( array_merge( $_deferred[ $taxonomy ], $terms ) ); return true; } return wp_update_term_count_now( $terms, $taxonomy ); } /** * Performs term count update immediately. * * @since 2.5.0 * * @param array $terms The term_taxonomy_id of terms to update. * @param string $taxonomy The context of the term. * @return true Always true when complete. */ function wp_update_term_count_now( $terms, $taxonomy ) { $terms = array_map( 'intval', $terms ); $taxonomy = get_taxonomy( $taxonomy ); if ( ! empty( $taxonomy->update_count_callback ) ) { call_user_func( $taxonomy->update_count_callback, $terms, $taxonomy ); } else { $object_types = (array) $taxonomy->object_type; foreach ( $object_types as &$object_type ) { if ( str_starts_with( $object_type, 'attachment:' ) ) { list( $object_type ) = explode( ':', $object_type ); } } if ( array_filter( $object_types, 'post_type_exists' ) == $object_types ) { // Only post types are attached to this taxonomy. _update_post_term_count( $terms, $taxonomy ); } else { // Default count updater. _update_generic_term_count( $terms, $taxonomy ); } } clean_term_cache( $terms, '', false ); return true; } // // Cache. // /** * Removes the taxonomy relationship to terms from the cache. * * Will remove the entire taxonomy relationship containing term `$object_id`. The * term IDs have to exist within the taxonomy `$object_type` for the deletion to * take place. * * @since 2.3.0 * * @global bool $_wp_suspend_cache_invalidation * * @see get_object_taxonomies() for more on $object_type. * * @param int|array $object_ids Single or list of term object ID(s). * @param array|string $object_type The taxonomy object type. */ function clean_object_term_cache( $object_ids, $object_type ) { global $_wp_suspend_cache_invalidation; if ( ! empty( $_wp_suspend_cache_invalidation ) ) { return; } if ( ! is_array( $object_ids ) ) { $object_ids = array( $object_ids ); } $taxonomies = get_object_taxonomies( $object_type ); foreach ( $taxonomies as $taxonomy ) { wp_cache_delete_multiple( $object_ids, "{$taxonomy}_relationships" ); } wp_cache_set_terms_last_changed(); /** * Fires after the object term cache has been cleaned. * * @since 2.5.0 * * @param array $object_ids An array of object IDs. * @param string $object_type Object type. */ do_action( 'clean_object_term_cache', $object_ids, $object_type ); } /** * Removes all of the term IDs from the cache. * * @since 2.3.0 * * @global wpdb $wpdb WordPress database abstraction object. * @global bool $_wp_suspend_cache_invalidation * * @param int|int[] $ids Single or array of term IDs. * @param string $taxonomy Optional. Taxonomy slug. Can be empty, in which case the taxonomies of the passed * term IDs will be used. Default empty. * @param bool $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual * term object caches (false). Default true. */ function clean_term_cache( $ids, $taxonomy = '', $clean_taxonomy = true ) { global $wpdb, $_wp_suspend_cache_invalidation; if ( ! empty( $_wp_suspend_cache_invalidation ) ) { return; } if ( ! is_array( $ids ) ) { $ids = array( $ids ); } $taxonomies = array(); // If no taxonomy, assume tt_ids. if ( empty( $taxonomy ) ) { $tt_ids = array_map( 'intval', $ids ); $tt_ids = implode( ', ', $tt_ids ); $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)" ); $ids = array(); foreach ( (array) $terms as $term ) { $taxonomies[] = $term->taxonomy; $ids[] = $term->term_id; } wp_cache_delete_multiple( $ids, 'terms' ); $taxonomies = array_unique( $taxonomies ); } else { wp_cache_delete_multiple( $ids, 'terms' ); $taxonomies = array( $taxonomy ); } foreach ( $taxonomies as $taxonomy ) { if ( $clean_taxonomy ) { clean_taxonomy_cache( $taxonomy ); } /** * Fires once after each taxonomy's term cache has been cleaned. * * @since 2.5.0 * @since 4.5.0 Added the `$clean_taxonomy` parameter. * * @param array $ids An array of term IDs. * @param string $taxonomy Taxonomy slug. * @param bool $clean_taxonomy Whether or not to clean taxonomy-wide caches */ do_action( 'clean_term_cache', $ids, $taxonomy, $clean_taxonomy ); } wp_cache_set_terms_last_changed(); } /** * Cleans the caches for a taxonomy. * * @since 4.9.0 * * @param string $taxonomy Taxonomy slug. */ function clean_taxonomy_cache( $taxonomy ) { wp_cache_delete( 'all_ids', $taxonomy ); wp_cache_delete( 'get', $taxonomy ); wp_cache_set_terms_last_changed(); // Regenerate cached hierarchy. delete_option( "{$taxonomy}_children" ); _get_term_hierarchy( $taxonomy ); /** * Fires after a taxonomy's caches have been cleaned. * * @since 4.9.0 * * @param string $taxonomy Taxonomy slug. */ do_action( 'clean_taxonomy_cache', $taxonomy ); } /** * Retrieves the cached term objects for the given object ID. * * Upstream functions (like get_the_terms() and is_object_in_term()) are * responsible for populating the object-term relationship cache. The current * function only fetches relationship data that is already in the cache. * * @since 2.3.0 * @since 4.7.0 Returns a `WP_Error` object if there's an error with * any of the matched terms. * * @param int $id Term object ID, for example a post, comment, or user ID. * @param string $taxonomy Taxonomy name. * @return bool|WP_Term[]|WP_Error Array of `WP_Term` objects, if cached. * False if cache is empty for `$taxonomy` and `$id`. * WP_Error if get_term() returns an error object for any term. */ function get_object_term_cache( $id, $taxonomy ) { $_term_ids = wp_cache_get( $id, "{$taxonomy}_relationships" ); // We leave the priming of relationship caches to upstream functions. if ( false === $_term_ids ) { return false; } // Backward compatibility for if a plugin is putting objects into the cache, rather than IDs. $term_ids = array(); foreach ( $_term_ids as $term_id ) { if ( is_numeric( $term_id ) ) { $term_ids[] = (int) $term_id; } elseif ( isset( $term_id->term_id ) ) { $term_ids[] = (int) $term_id->term_id; } } // Fill the term objects. _prime_term_caches( $term_ids ); $terms = array(); foreach ( $term_ids as $term_id ) { $term = get_term( $term_id, $taxonomy ); if ( is_wp_error( $term ) ) { return $term; } $terms[] = $term; } return $terms; } /** * Updates the cache for the given term object ID(s). * * Note: Due to performance concerns, great care should be taken to only update * term caches when necessary. Processing time can increase exponentially depending * on both the number of passed term IDs and the number of taxonomies those terms * belong to. * * Caches will only be updated for terms not already cached. * * @since 2.3.0 * * @param string|int[] $object_ids Comma-separated list or array of term object IDs. * @param string|string[] $object_type The taxonomy object type or array of the same. * @return void|false Void on success or if the `$object_ids` parameter is empty, * false if all of the terms in `$object_ids` are already cached. */ function update_object_term_cache( $object_ids, $object_type ) { if ( empty( $object_ids ) ) { return; } if ( ! is_array( $object_ids ) ) { $object_ids = explode( ',', $object_ids ); } $object_ids = array_map( 'intval', $object_ids ); $non_cached_ids = array(); $taxonomies = get_object_taxonomies( $object_type ); foreach ( $taxonomies as $taxonomy ) { $cache_values = wp_cache_get_multiple( (array) $object_ids, "{$taxonomy}_relationships" ); foreach ( $cache_values as $id => $value ) { if ( false === $value ) { $non_cached_ids[] = $id; } } } if ( empty( $non_cached_ids ) ) { return false; } $non_cached_ids = array_unique( $non_cached_ids ); $terms = wp_get_object_terms( $non_cached_ids, $taxonomies, array( 'fields' => 'all_with_object_id', 'orderby' => 'name', 'update_term_meta_cache' => false, ) ); $object_terms = array(); foreach ( (array) $terms as $term ) { $object_terms[ $term->object_id ][ $term->taxonomy ][] = $term->term_id; } foreach ( $non_cached_ids as $id ) { foreach ( $taxonomies as $taxonomy ) { if ( ! isset( $object_terms[ $id ][ $taxonomy ] ) ) { if ( ! isset( $object_terms[ $id ] ) ) { $object_terms[ $id ] = array(); } $object_terms[ $id ][ $taxonomy ] = array(); } } } $cache_values = array(); foreach ( $object_terms as $id => $value ) { foreach ( $value as $taxonomy => $terms ) { $cache_values[ $taxonomy ][ $id ] = $terms; } } foreach ( $cache_values as $taxonomy => $data ) { wp_cache_add_multiple( $data, "{$taxonomy}_relationships" ); } } /** * Updates terms in cache. * * @since 2.3.0 * * @param WP_Term[] $terms Array of term objects to change. * @param string $taxonomy Not used. */ function update_term_cache( $terms, $taxonomy = '' ) { $data = array(); foreach ( (array) $terms as $term ) { // Create a copy in case the array was passed by reference. $_term = clone $term; // Object ID should not be cached. unset( $_term->object_id ); $data[ $term->term_id ] = $_term; } wp_cache_add_multiple( $data, 'terms' ); } // // Private. // /** * Retrieves children of taxonomy as term IDs. * * @access private * @since 2.3.0 * * @param string $taxonomy Taxonomy name. * @return array Empty if $taxonomy isn't hierarchical or returns children as term IDs. */ function _get_term_hierarchy( $taxonomy ) { if ( ! is_taxonomy_hierarchical( $taxonomy ) ) { return array(); } $children = get_option( "{$taxonomy}_children" ); if ( is_array( $children ) ) { return $children; } $children = array(); $terms = get_terms( array( 'taxonomy' => $taxonomy, 'get' => 'all', 'orderby' => 'id', 'fields' => 'id=>parent', 'update_term_meta_cache' => false, ) ); foreach ( $terms as $term_id => $parent ) { if ( $parent > 0 ) { $children[ $parent ][] = $term_id; } } update_option( "{$taxonomy}_children", $children ); return $children; } /** * Gets the subset of $terms that are descendants of $term_id. * * If `$terms` is an array of objects, then _get_term_children() returns an array of objects. * If `$terms` is an array of IDs, then _get_term_children() returns an array of IDs. * * @access private * @since 2.3.0 * * @param int $term_id The ancestor term: all returned terms should be descendants of `$term_id`. * @param array $terms The set of terms - either an array of term objects or term IDs - from which those that * are descendants of $term_id will be chosen. * @param string $taxonomy The taxonomy which determines the hierarchy of the terms. * @param array $ancestors Optional. Term ancestors that have already been identified. Passed by reference, to keep * track of found terms when recursing the hierarchy. The array of located ancestors is used * to prevent infinite recursion loops. For performance, `term_ids` are used as array keys, * with 1 as value. Default empty array. * @return array|WP_Error The subset of $terms that are descendants of $term_id. */ function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) { $empty_array = array(); if ( empty( $terms ) ) { return $empty_array; } $term_id = (int) $term_id; $term_list = array(); $has_children = _get_term_hierarchy( $taxonomy ); if ( $term_id && ! isset( $has_children[ $term_id ] ) ) { return $empty_array; } // Include the term itself in the ancestors array, so we can properly detect when a loop has occurred. if ( empty( $ancestors ) ) { $ancestors[ $term_id ] = 1; } foreach ( (array) $terms as $term ) { $use_id = false; if ( ! is_object( $term ) ) { $term = get_term( $term, $taxonomy ); if ( is_wp_error( $term ) ) { return $term; } $use_id = true; } // Don't recurse if we've already identified the term as a child - this indicates a loop. if ( isset( $ancestors[ $term->term_id ] ) ) { continue; } if ( (int) $term->parent === $term_id ) { if ( $use_id ) { $term_list[] = $term->term_id; } else { $term_list[] = $term; } if ( ! isset( $has_children[ $term->term_id ] ) ) { continue; } $ancestors[ $term->term_id ] = 1; $children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors ); if ( $children ) { $term_list = array_merge( $term_list, $children ); } } } return $term_list; } /** * Adds count of children to parent count. * * Recalculates term counts by including items from child terms. Assumes all * relevant children are already in the $terms argument. * * @access private * @since 2.3.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param object[]|WP_Term[] $terms List of term objects (passed by reference). * @param string $taxonomy Term context. */ function _pad_term_counts( &$terms, $taxonomy ) { global $wpdb; // This function only works for hierarchical taxonomies like post categories. if ( ! is_taxonomy_hierarchical( $taxonomy ) ) { return; } $term_hier = _get_term_hierarchy( $taxonomy ); if ( empty( $term_hier ) ) { return; } $term_items = array(); $terms_by_id = array(); $term_ids = array(); foreach ( (array) $terms as $key => $term ) { $terms_by_id[ $term->term_id ] = & $terms[ $key ]; $term_ids[ $term->term_taxonomy_id ] = $term->term_id; } // Get the object and term IDs and stick them in a lookup table. $tax_obj = get_taxonomy( $taxonomy ); $object_types = esc_sql( $tax_obj->object_type ); $results = $wpdb->get_results( "SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode( ',', array_keys( $term_ids ) ) . ") AND post_type IN ('" . implode( "', '", $object_types ) . "') AND post_status = 'publish'" ); foreach ( $results as $row ) { $id = $term_ids[ $row->term_taxonomy_id ]; $term_items[ $id ][ $row->object_id ] = isset( $term_items[ $id ][ $row->object_id ] ) ? ++$term_items[ $id ][ $row->object_id ] : 1; } // Touch every ancestor's lookup row for each post in each term. foreach ( $term_ids as $term_id ) { $child = $term_id; $ancestors = array(); while ( ! empty( $terms_by_id[ $child ] ) && $parent = $terms_by_id[ $child ]->parent ) { $ancestors[] = $child; if ( ! empty( $term_items[ $term_id ] ) ) { foreach ( $term_items[ $term_id ] as $item_id => $touches ) { $term_items[ $parent ][ $item_id ] = isset( $term_items[ $parent ][ $item_id ] ) ? ++$term_items[ $parent ][ $item_id ] : 1; } } $child = $parent; if ( in_array( $parent, $ancestors, true ) ) { break; } } } // Transfer the touched cells. foreach ( (array) $term_items as $id => $items ) { if ( isset( $terms_by_id[ $id ] ) ) { $terms_by_id[ $id ]->count = count( $items ); } } } /** * Adds any terms from the given IDs to the cache that do not already exist in cache. * * @since 4.6.0 * @since 6.1.0 This function is no longer marked as "private". * @since 6.3.0 Use wp_lazyload_term_meta() for lazy-loading of term meta. * * @global wpdb $wpdb WordPress database abstraction object. * * @param array $term_ids Array of term IDs. * @param bool $update_meta_cache Optional. Whether to update the meta cache. Default true. */ function _prime_term_caches( $term_ids, $update_meta_cache = true ) { global $wpdb; $non_cached_ids = _get_non_cached_ids( $term_ids, 'terms' ); if ( ! empty( $non_cached_ids ) ) { $fresh_terms = $wpdb->get_results( sprintf( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE t.term_id IN (%s)", implode( ',', array_map( 'intval', $non_cached_ids ) ) ) ); update_term_cache( $fresh_terms ); } if ( $update_meta_cache ) { wp_lazyload_term_meta( $term_ids ); } } // // Default callbacks. // /** * Updates term count based on object types of the current taxonomy. * * Private function for the default callback for post_tag and category * taxonomies. * * @access private * @since 2.3.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int[] $terms List of term taxonomy IDs. * @param WP_Taxonomy $taxonomy Current taxonomy object of terms. */ function _update_post_term_count( $terms, $taxonomy ) { global $wpdb; $object_types = (array) $taxonomy->object_type; foreach ( $object_types as &$object_type ) { list( $object_type ) = explode( ':', $object_type ); } $object_types = array_unique( $object_types ); $check_attachments = array_search( 'attachment', $object_types, true ); if ( false !== $check_attachments ) { unset( $object_types[ $check_attachments ] ); $check_attachments = true; } if ( $object_types ) { $object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) ); } $post_statuses = array( 'publish' ); /** * Filters the post statuses for updating the term count. * * @since 5.7.0 * * @param string[] $post_statuses List of post statuses to include in the count. Default is 'publish'. * @param WP_Taxonomy $taxonomy Current taxonomy object. */ $post_statuses = esc_sql( apply_filters( 'update_post_term_count_statuses', $post_statuses, $taxonomy ) ); foreach ( (array) $terms as $term ) { $count = 0; // Attachments can be 'inherit' status, we need to base count off the parent's status if so. if ( $check_attachments ) { // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedDynamicPlaceholderGeneration $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status IN ('" . implode( "', '", $post_statuses ) . "') OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) IN ('" . implode( "', '", $post_statuses ) . "') ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) ); } if ( $object_types ) { // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedDynamicPlaceholderGeneration $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status IN ('" . implode( "', '", $post_statuses ) . "') AND post_type IN ('" . implode( "', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) ); } /** This action is documented in wp-includes/taxonomy.php */ do_action( 'edit_term_taxonomy', $term, $taxonomy->name ); $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) ); /** This action is documented in wp-includes/taxonomy.php */ do_action( 'edited_term_taxonomy', $term, $taxonomy->name ); } } /** * Updates term count based on number of objects. * * Default callback for the 'link_category' taxonomy. * * @since 3.3.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int[] $terms List of term taxonomy IDs. * @param WP_Taxonomy $taxonomy Current taxonomy object of terms. */ function _update_generic_term_count( $terms, $taxonomy ) { global $wpdb; foreach ( (array) $terms as $term ) { $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term ) ); /** This action is documented in wp-includes/taxonomy.php */ do_action( 'edit_term_taxonomy', $term, $taxonomy->name ); $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) ); /** This action is documented in wp-includes/taxonomy.php */ do_action( 'edited_term_taxonomy', $term, $taxonomy->name ); } } /** * Creates a new term for a term_taxonomy item that currently shares its term * with another term_taxonomy. * * @ignore * @since 4.2.0 * @since 4.3.0 Introduced `$record` parameter. Also, `$term_id` and * `$term_taxonomy_id` can now accept objects. * * @global wpdb $wpdb WordPress database abstraction object. * * @param int|object $term_id ID of the shared term, or the shared term object. * @param int|object $term_taxonomy_id ID of the term_taxonomy item to receive a new term, or the term_taxonomy object * (corresponding to a row from the term_taxonomy table). * @param bool $record Whether to record data about the split term in the options table. The recording * process has the potential to be resource-intensive, so during batch operations * it can be beneficial to skip inline recording and do it just once, after the * batch is processed. Only set this to `false` if you know what you are doing. * Default: true. * @return int|WP_Error When the current term does not need to be split (or cannot be split on the current * database schema), `$term_id` is returned. When the term is successfully split, the * new term_id is returned. A WP_Error is returned for miscellaneous errors. */ function _split_shared_term( $term_id, $term_taxonomy_id, $record = true ) { global $wpdb; if ( is_object( $term_id ) ) { $shared_term = $term_id; $term_id = (int) $shared_term->term_id; } if ( is_object( $term_taxonomy_id ) ) { $term_taxonomy = $term_taxonomy_id; $term_taxonomy_id = (int) $term_taxonomy->term_taxonomy_id; } // If there are no shared term_taxonomy rows, there's nothing to do here. $shared_tt_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy tt WHERE tt.term_id = %d AND tt.term_taxonomy_id != %d", $term_id, $term_taxonomy_id ) ); if ( ! $shared_tt_count ) { return $term_id; } /* * Verify that the term_taxonomy_id passed to the function is actually associated with the term_id. * If there's a mismatch, it may mean that the term is already split. Return the actual term_id from the db. */ $check_term_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) ); if ( $check_term_id !== $term_id ) { return $check_term_id; } // Pull up data about the currently shared slug, which we'll use to populate the new one. if ( empty( $shared_term ) ) { $shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->terms t WHERE t.term_id = %d", $term_id ) ); } $new_term_data = array( 'name' => $shared_term->name, 'slug' => $shared_term->slug, 'term_group' => $shared_term->term_group, ); if ( false === $wpdb->insert( $wpdb->terms, $new_term_data ) ) { return new WP_Error( 'db_insert_error', __( 'Could not split shared term.' ), $wpdb->last_error ); } $new_term_id = (int) $wpdb->insert_id; // Update the existing term_taxonomy to point to the newly created term. $wpdb->update( $wpdb->term_taxonomy, array( 'term_id' => $new_term_id ), array( 'term_taxonomy_id' => $term_taxonomy_id ) ); // Reassign child terms to the new parent. if ( empty( $term_taxonomy ) ) { $term_taxonomy = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) ); } $children_tt_ids = $wpdb->get_col( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE parent = %d AND taxonomy = %s", $term_id, $term_taxonomy->taxonomy ) ); if ( ! empty( $children_tt_ids ) ) { foreach ( $children_tt_ids as $child_tt_id ) { $wpdb->update( $wpdb->term_taxonomy, array( 'parent' => $new_term_id ), array( 'term_taxonomy_id' => $child_tt_id ) ); clean_term_cache( (int) $child_tt_id, '', false ); } } else { // If the term has no children, we must force its taxonomy cache to be rebuilt separately. clean_term_cache( $new_term_id, $term_taxonomy->taxonomy, false ); } clean_term_cache( $term_id, $term_taxonomy->taxonomy, false ); /* * Taxonomy cache clearing is delayed to avoid race conditions that may occur when * regenerating the taxonomy's hierarchy tree. */ $taxonomies_to_clean = array( $term_taxonomy->taxonomy ); // Clean the cache for term taxonomies formerly shared with the current term. $shared_term_taxonomies = $wpdb->get_col( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) ); $taxonomies_to_clean = array_merge( $taxonomies_to_clean, $shared_term_taxonomies ); foreach ( $taxonomies_to_clean as $taxonomy_to_clean ) { clean_taxonomy_cache( $taxonomy_to_clean ); } // Keep a record of term_ids that have been split, keyed by old term_id. See wp_get_split_term(). if ( $record ) { $split_term_data = get_option( '_split_terms', array() ); if ( ! isset( $split_term_data[ $term_id ] ) ) { $split_term_data[ $term_id ] = array(); } $split_term_data[ $term_id ][ $term_taxonomy->taxonomy ] = $new_term_id; update_option( '_split_terms', $split_term_data ); } // If we've just split the final shared term, set the "finished" flag. $shared_terms_exist = $wpdb->get_results( "SELECT tt.term_id, t.*, count(*) as term_tt_count FROM {$wpdb->term_taxonomy} tt LEFT JOIN {$wpdb->terms} t ON t.term_id = tt.term_id GROUP BY t.term_id HAVING term_tt_count > 1 LIMIT 1" ); if ( ! $shared_terms_exist ) { update_option( 'finished_splitting_shared_terms', true ); } /** * Fires after a previously shared taxonomy term is split into two separate terms. * * @since 4.2.0 * * @param int $term_id ID of the formerly shared term. * @param int $new_term_id ID of the new term created for the $term_taxonomy_id. * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split. * @param string $taxonomy Taxonomy for the split term. */ do_action( 'split_shared_term', $term_id, $new_term_id, $term_taxonomy_id, $term_taxonomy->taxonomy ); return $new_term_id; } /** * Splits a batch of shared taxonomy terms. * * @since 4.3.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function _wp_batch_split_terms() { global $wpdb; $lock_name = 'term_split.lock'; // Try to lock. $lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_name, time() ) ); if ( ! $lock_result ) { $lock_result = get_option( $lock_name ); // Bail if we were unable to create a lock, or if the existing lock is still valid. if ( ! $lock_result || ( $lock_result > ( time() - HOUR_IN_SECONDS ) ) ) { wp_schedule_single_event( time() + ( 5 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' ); return; } } // Update the lock, as by this point we've definitely got a lock, just need to fire the actions. update_option( $lock_name, time() ); // Get a list of shared terms (those with more than one associated row in term_taxonomy). $shared_terms = $wpdb->get_results( "SELECT tt.term_id, t.*, count(*) as term_tt_count FROM {$wpdb->term_taxonomy} tt LEFT JOIN {$wpdb->terms} t ON t.term_id = tt.term_id GROUP BY t.term_id HAVING term_tt_count > 1 LIMIT 10" ); // No more terms, we're done here. if ( ! $shared_terms ) { update_option( 'finished_splitting_shared_terms', true ); delete_option( $lock_name ); return; } // Shared terms found? We'll need to run this script again. wp_schedule_single_event( time() + ( 2 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' ); // Rekey shared term array for faster lookups. $_shared_terms = array(); foreach ( $shared_terms as $shared_term ) { $term_id = (int) $shared_term->term_id; $_shared_terms[ $term_id ] = $shared_term; } $shared_terms = $_shared_terms; // Get term taxonomy data for all shared terms. $shared_term_ids = implode( ',', array_keys( $shared_terms ) ); $shared_tts = $wpdb->get_results( "SELECT * FROM {$wpdb->term_taxonomy} WHERE `term_id` IN ({$shared_term_ids})" ); // Split term data recording is slow, so we do it just once, outside the loop. $split_term_data = get_option( '_split_terms', array() ); $skipped_first_term = array(); $taxonomies = array(); foreach ( $shared_tts as $shared_tt ) { $term_id = (int) $shared_tt->term_id; // Don't split the first tt belonging to a given term_id. if ( ! isset( $skipped_first_term[ $term_id ] ) ) { $skipped_first_term[ $term_id ] = 1; continue; } if ( ! isset( $split_term_data[ $term_id ] ) ) { $split_term_data[ $term_id ] = array(); } // Keep track of taxonomies whose hierarchies need flushing. if ( ! isset( $taxonomies[ $shared_tt->taxonomy ] ) ) { $taxonomies[ $shared_tt->taxonomy ] = 1; } // Split the term. $split_term_data[ $term_id ][ $shared_tt->taxonomy ] = _split_shared_term( $shared_terms[ $term_id ], $shared_tt, false ); } // Rebuild the cached hierarchy for each affected taxonomy. foreach ( array_keys( $taxonomies ) as $tax ) { delete_option( "{$tax}_children" ); _get_term_hierarchy( $tax ); } update_option( '_split_terms', $split_term_data ); delete_option( $lock_name ); } /** * In order to avoid the _wp_batch_split_terms() job being accidentally removed, * checks that it's still scheduled while we haven't finished splitting terms. * * @ignore * @since 4.3.0 */ function _wp_check_for_scheduled_split_terms() { if ( ! get_option( 'finished_splitting_shared_terms' ) && ! wp_next_scheduled( 'wp_split_shared_term_batch' ) ) { wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'wp_split_shared_term_batch' ); } } /** * Checks default categories when a term gets split to see if any of them need to be updated. * * @ignore * @since 4.2.0 * * @param int $term_id ID of the formerly shared term. * @param int $new_term_id ID of the new term created for the $term_taxonomy_id. * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split. * @param string $taxonomy Taxonomy for the split term. */ function _wp_check_split_default_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) { if ( 'category' !== $taxonomy ) { return; } foreach ( array( 'default_category', 'default_link_category', 'default_email_category' ) as $option ) { if ( (int) get_option( $option, -1 ) === $term_id ) { update_option( $option, $new_term_id ); } } } /** * Checks menu items when a term gets split to see if any of them need to be updated. * * @ignore * @since 4.2.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $term_id ID of the formerly shared term. * @param int $new_term_id ID of the new term created for the $term_taxonomy_id. * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split. * @param string $taxonomy Taxonomy for the split term. */ function _wp_check_split_terms_in_menus( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) { global $wpdb; $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT m1.post_id FROM {$wpdb->postmeta} AS m1 INNER JOIN {$wpdb->postmeta} AS m2 ON ( m2.post_id = m1.post_id ) INNER JOIN {$wpdb->postmeta} AS m3 ON ( m3.post_id = m1.post_id ) WHERE ( m1.meta_key = '_menu_item_type' AND m1.meta_value = 'taxonomy' ) AND ( m2.meta_key = '_menu_item_object' AND m2.meta_value = %s ) AND ( m3.meta_key = '_menu_item_object_id' AND m3.meta_value = %d )", $taxonomy, $term_id ) ); if ( $post_ids ) { foreach ( $post_ids as $post_id ) { update_post_meta( $post_id, '_menu_item_object_id', $new_term_id, $term_id ); } } } /** * If the term being split is a nav_menu, changes associations. * * @ignore * @since 4.3.0 * * @param int $term_id ID of the formerly shared term. * @param int $new_term_id ID of the new term created for the $term_taxonomy_id. * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split. * @param string $taxonomy Taxonomy for the split term. */ function _wp_check_split_nav_menu_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) { if ( 'nav_menu' !== $taxonomy ) { return; } // Update menu locations. $locations = get_nav_menu_locations(); foreach ( $locations as $location => $menu_id ) { if ( $term_id === $menu_id ) { $locations[ $location ] = $new_term_id; } } set_theme_mod( 'nav_menu_locations', $locations ); } /** * Gets data about terms that previously shared a single term_id, but have since been split. * * @since 4.2.0 * * @param int $old_term_id Term ID. This is the old, pre-split term ID. * @return array Array of new term IDs, keyed by taxonomy. */ function wp_get_split_terms( $old_term_id ) { $split_terms = get_option( '_split_terms', array() ); $terms = array(); if ( isset( $split_terms[ $old_term_id ] ) ) { $terms = $split_terms[ $old_term_id ]; } return $terms; } /** * Gets the new term ID corresponding to a previously split term. * * @since 4.2.0 * * @param int $old_term_id Term ID. This is the old, pre-split term ID. * @param string $taxonomy Taxonomy that the term belongs to. * @return int|false If a previously split term is found corresponding to the old term_id and taxonomy, * the new term_id will be returned. If no previously split term is found matching * the parameters, returns false. */ function wp_get_split_term( $old_term_id, $taxonomy ) { $split_terms = wp_get_split_terms( $old_term_id ); $term_id = false; if ( isset( $split_terms[ $taxonomy ] ) ) { $term_id = (int) $split_terms[ $taxonomy ]; } return $term_id; } /** * Determines whether a term is shared between multiple taxonomies. * * Shared taxonomy terms began to be split in 4.3, but failed cron tasks or * other delays in upgrade routines may cause shared terms to remain. * * @since 4.4.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $term_id Term ID. * @return bool Returns false if a term is not shared between multiple taxonomies or * if splitting shared taxonomy terms is finished. */ function wp_term_is_shared( $term_id ) { global $wpdb; if ( get_option( 'finished_splitting_shared_terms' ) ) { return false; } $tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) ); return $tt_count > 1; } /** * Generates a permalink for a taxonomy term archive. * * @since 2.5.0 * * @global WP_Rewrite $wp_rewrite WordPress rewrite component. * * @param WP_Term|int|string $term The term object, ID, or slug whose link will be retrieved. * @param string $taxonomy Optional. Taxonomy. Default empty. * @return string|WP_Error URL of the taxonomy term archive on success, WP_Error if term does not exist. */ function get_term_link( $term, $taxonomy = '' ) { global $wp_rewrite; if ( ! is_object( $term ) ) { if ( is_int( $term ) ) { $term = get_term( $term, $taxonomy ); } else { $term = get_term_by( 'slug', $term, $taxonomy ); } } if ( ! is_object( $term ) ) { $term = new WP_Error( 'invalid_term', __( 'Empty Term.' ) ); } if ( is_wp_error( $term ) ) { return $term; } $taxonomy = $term->taxonomy; $termlink = $wp_rewrite->get_extra_permastruct( $taxonomy ); /** * Filters the permalink structure for a term before token replacement occurs. * * @since 4.9.0 * * @param string $termlink The permalink structure for the term's taxonomy. * @param WP_Term $term The term object. */ $termlink = apply_filters( 'pre_term_link', $termlink, $term ); $slug = $term->slug; $t = get_taxonomy( $taxonomy ); if ( empty( $termlink ) ) { if ( 'category' === $taxonomy ) { $termlink = '?cat=' . $term->term_id; } elseif ( $t->query_var ) { $termlink = "?$t->query_var=$slug"; } else { $termlink = "?taxonomy=$taxonomy&term=$slug"; } $termlink = home_url( $termlink ); } else { if ( ! empty( $t->rewrite['hierarchical'] ) ) { $hierarchical_slugs = array(); $ancestors = get_ancestors( $term->term_id, $taxonomy, 'taxonomy' ); foreach ( (array) $ancestors as $ancestor ) { $ancestor_term = get_term( $ancestor, $taxonomy ); $hierarchical_slugs[] = $ancestor_term->slug; } $hierarchical_slugs = array_reverse( $hierarchical_slugs ); $hierarchical_slugs[] = $slug; $termlink = str_replace( "%$taxonomy%", implode( '/', $hierarchical_slugs ), $termlink ); } else { $termlink = str_replace( "%$taxonomy%", $slug, $termlink ); } $termlink = home_url( user_trailingslashit( $termlink, 'category' ) ); } // Back compat filters. if ( 'post_tag' === $taxonomy ) { /** * Filters the tag link. * * @since 2.3.0 * @since 2.5.0 Deprecated in favor of {@see 'term_link'} filter. * @since 5.4.1 Restored (un-deprecated). * * @param string $termlink Tag link URL. * @param int $term_id Term ID. */ $termlink = apply_filters( 'tag_link', $termlink, $term->term_id ); } elseif ( 'category' === $taxonomy ) { /** * Filters the category link. * * @since 1.5.0 * @since 2.5.0 Deprecated in favor of {@see 'term_link'} filter. * @since 5.4.1 Restored (un-deprecated). * * @param string $termlink Category link URL. * @param int $term_id Term ID. */ $termlink = apply_filters( 'category_link', $termlink, $term->term_id ); } /** * Filters the term link. * * @since 2.5.0 * * @param string $termlink Term link URL. * @param WP_Term $term Term object. * @param string $taxonomy Taxonomy slug. */ return apply_filters( 'term_link', $termlink, $term, $taxonomy ); } /** * Displays the taxonomies of a post with available options. * * This function can be used within the loop to display the taxonomies for a * post without specifying the Post ID. You can also use it outside the Loop to * display the taxonomies for a specific post. * * @since 2.5.0 * * @param array $args { * Arguments about which post to use and how to format the output. Shares all of the arguments * supported by get_the_taxonomies(), in addition to the following. * * @type int|WP_Post $post Post ID or object to get taxonomies of. Default current post. * @type string $before Displays before the taxonomies. Default empty string. * @type string $sep Separates each taxonomy. Default is a space. * @type string $after Displays after the taxonomies. Default empty string. * } */ function the_taxonomies( $args = array() ) { $defaults = array( 'post' => 0, 'before' => '', 'sep' => ' ', 'after' => '', ); $parsed_args = wp_parse_args( $args, $defaults ); echo $parsed_args['before'] . implode( $parsed_args['sep'], get_the_taxonomies( $parsed_args['post'], $parsed_args ) ) . $parsed_args['after']; } /** * Retrieves all taxonomies associated with a post. * * This function can be used within the loop. It will also return an array of * the taxonomies with links to the taxonomy and name. * * @since 2.5.0 * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. * @param array $args { * Optional. Arguments about how to format the list of taxonomies. Default empty array. * * @type string $template Template for displaying a taxonomy label and list of terms. * Default is "Label: Terms." * @type string $term_template Template for displaying a single term in the list. Default is the term name * linked to its archive. * } * @return string[] List of taxonomies. */ function get_the_taxonomies( $post = 0, $args = array() ) { $post = get_post( $post ); $args = wp_parse_args( $args, array( /* translators: %s: Taxonomy label, %l: List of terms formatted as per $term_template. */ 'template' => __( '%s: %l.' ), 'term_template' => '%2$s', ) ); $taxonomies = array(); if ( ! $post ) { return $taxonomies; } foreach ( get_object_taxonomies( $post ) as $taxonomy ) { $t = (array) get_taxonomy( $taxonomy ); if ( empty( $t['label'] ) ) { $t['label'] = $taxonomy; } if ( empty( $t['args'] ) ) { $t['args'] = array(); } if ( empty( $t['template'] ) ) { $t['template'] = $args['template']; } if ( empty( $t['term_template'] ) ) { $t['term_template'] = $args['term_template']; } $terms = get_object_term_cache( $post->ID, $taxonomy ); if ( false === $terms ) { $terms = wp_get_object_terms( $post->ID, $taxonomy, $t['args'] ); } $links = array(); foreach ( $terms as $term ) { $links[] = wp_sprintf( $t['term_template'], esc_attr( get_term_link( $term ) ), $term->name ); } if ( $links ) { $taxonomies[ $taxonomy ] = wp_sprintf( $t['template'], $t['label'], $links, $terms ); } } return $taxonomies; } /** * Retrieves all taxonomy names for the given post. * * @since 2.5.0 * * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. * @return string[] An array of all taxonomy names for the given post. */ function get_post_taxonomies( $post = 0 ) { $post = get_post( $post ); return get_object_taxonomies( $post ); } /** * Determines if the given object is associated with any of the given terms. * * The given terms are checked against the object's terms' term_ids, names and slugs. * Terms given as integers will only be checked against the object's terms' term_ids. * If no terms are given, determines if object is associated with any terms in the given taxonomy. * * @since 2.7.0 * * @param int $object_id ID of the object (post ID, link ID, ...). * @param string $taxonomy Single taxonomy name. * @param int|string|int[]|string[] $terms Optional. Term ID, name, slug, or array of such * to check against. Default null. * @return bool|WP_Error WP_Error on input error. */ function is_object_in_term( $object_id, $taxonomy, $terms = null ) { $object_id = (int) $object_id; if ( ! $object_id ) { return new WP_Error( 'invalid_object', __( 'Invalid object ID.' ) ); } $object_terms = get_object_term_cache( $object_id, $taxonomy ); if ( false === $object_terms ) { $object_terms = wp_get_object_terms( $object_id, $taxonomy, array( 'update_term_meta_cache' => false ) ); if ( is_wp_error( $object_terms ) ) { return $object_terms; } wp_cache_set( $object_id, wp_list_pluck( $object_terms, 'term_id' ), "{$taxonomy}_relationships" ); } if ( is_wp_error( $object_terms ) ) { return $object_terms; } if ( empty( $object_terms ) ) { return false; } if ( empty( $terms ) ) { return ( ! empty( $object_terms ) ); } $terms = (array) $terms; $ints = array_filter( $terms, 'is_int' ); if ( $ints ) { $strs = array_diff( $terms, $ints ); } else { $strs =& $terms; } foreach ( $object_terms as $object_term ) { // If term is an int, check against term_ids only. if ( $ints && in_array( $object_term->term_id, $ints, true ) ) { return true; } if ( $strs ) { // Only check numeric strings against term_id, to avoid false matches due to type juggling. $numeric_strs = array_map( 'intval', array_filter( $strs, 'is_numeric' ) ); if ( in_array( $object_term->term_id, $numeric_strs, true ) ) { return true; } if ( in_array( $object_term->name, $strs, true ) ) { return true; } if ( in_array( $object_term->slug, $strs, true ) ) { return true; } } } return false; } /** * Determines if the given object type is associated with the given taxonomy. * * @since 3.0.0 * * @param string $object_type Object type string. * @param string $taxonomy Single taxonomy name. * @return bool True if object is associated with the taxonomy, otherwise false. */ function is_object_in_taxonomy( $object_type, $taxonomy ) { $taxonomies = get_object_taxonomies( $object_type ); if ( empty( $taxonomies ) ) { return false; } return in_array( $taxonomy, $taxonomies, true ); } /** * Gets an array of ancestor IDs for a given object. * * @since 3.1.0 * @since 4.1.0 Introduced the `$resource_type` argument. * * @param int $object_id Optional. The ID of the object. Default 0. * @param string $object_type Optional. The type of object for which we'll be retrieving * ancestors. Accepts a post type or a taxonomy name. Default empty. * @param string $resource_type Optional. Type of resource $object_type is. Accepts 'post_type' * or 'taxonomy'. Default empty. * @return int[] An array of IDs of ancestors from lowest to highest in the hierarchy. */ function get_ancestors( $object_id = 0, $object_type = '', $resource_type = '' ) { $object_id = (int) $object_id; $ancestors = array(); if ( empty( $object_id ) ) { /** This filter is documented in wp-includes/taxonomy.php */ return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type ); } if ( ! $resource_type ) { if ( is_taxonomy_hierarchical( $object_type ) ) { $resource_type = 'taxonomy'; } elseif ( post_type_exists( $object_type ) ) { $resource_type = 'post_type'; } } if ( 'taxonomy' === $resource_type ) { $term = get_term( $object_id, $object_type ); while ( ! is_wp_error( $term ) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors, true ) ) { $ancestors[] = (int) $term->parent; $term = get_term( $term->parent, $object_type ); } } elseif ( 'post_type' === $resource_type ) { $ancestors = get_post_ancestors( $object_id ); } /** * Filters a given object's ancestors. * * @since 3.1.0 * @since 4.1.1 Introduced the `$resource_type` parameter. * * @param int[] $ancestors An array of IDs of object ancestors. * @param int $object_id Object ID. * @param string $object_type Type of object. * @param string $resource_type Type of resource $object_type is. */ return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type ); } /** * Returns the term's parent's term ID. * * @since 3.1.0 * * @param int $term_id Term ID. * @param string $taxonomy Taxonomy name. * @return int|false Parent term ID on success, false on failure. */ function wp_get_term_taxonomy_parent_id( $term_id, $taxonomy ) { $term = get_term( $term_id, $taxonomy ); if ( ! $term || is_wp_error( $term ) ) { return false; } return (int) $term->parent; } /** * Checks the given subset of the term hierarchy for hierarchy loops. * Prevents loops from forming and breaks those that it finds. * * Attached to the {@see 'wp_update_term_parent'} filter. * * @since 3.1.0 * * @param int $parent_term `term_id` of the parent for the term we're checking. * @param int $term_id The term we're checking. * @param string $taxonomy The taxonomy of the term we're checking. * @return int The new parent for the term. */ function wp_check_term_hierarchy_for_loops( $parent_term, $term_id, $taxonomy ) { // Nothing fancy here - bail. if ( ! $parent_term ) { return 0; } // Can't be its own parent. if ( $parent_term === $term_id ) { return 0; } // Now look for larger loops. $loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent_term, array( $taxonomy ) ); if ( ! $loop ) { return $parent_term; // No loop. } // Setting $parent_term to the given value causes a loop. if ( isset( $loop[ $term_id ] ) ) { return 0; } // There's a loop, but it doesn't contain $term_id. Break the loop. foreach ( array_keys( $loop ) as $loop_member ) { wp_update_term( $loop_member, $taxonomy, array( 'parent' => 0 ) ); } return $parent_term; } /** * Determines whether a taxonomy is considered "viewable". * * @since 5.1.0 * * @param string|WP_Taxonomy $taxonomy Taxonomy name or object. * @return bool Whether the taxonomy should be considered viewable. */ function is_taxonomy_viewable( $taxonomy ) { if ( is_scalar( $taxonomy ) ) { $taxonomy = get_taxonomy( $taxonomy ); if ( ! $taxonomy ) { return false; } } return $taxonomy->publicly_queryable; } /** * Determines whether a term is publicly viewable. * * A term is considered publicly viewable if its taxonomy is viewable. * * @since 6.1.0 * * @param int|WP_Term $term Term ID or term object. * @return bool Whether the term is publicly viewable. */ function is_term_publicly_viewable( $term ) { $term = get_term( $term ); if ( ! $term ) { return false; } return is_taxonomy_viewable( $term->taxonomy ); } /** * Sets the last changed time for the 'terms' cache group. * * @since 5.0.0 */ function wp_cache_set_terms_last_changed() { wp_cache_set_last_changed( 'terms' ); } /** * Aborts calls to term meta if it is not supported. * * @since 5.0.0 * * @param mixed $check Skip-value for whether to proceed term meta function execution. * @return mixed Original value of $check, or false if term meta is not supported. */ function wp_check_term_meta_support_prefilter( $check ) { if ( get_option( 'db_version' ) < 34370 ) { return false; } return $check; }
Fatal error: Uncaught Error: Call to undefined function untrailingslashit() in /home/healths/public_html/wp-includes/option.php:231 Stack trace: #0 /home/healths/public_html/wp-includes/default-constants.php(174): get_option() #1 /home/healths/public_html/wp-settings.php(391): wp_plugin_directory_constants() #2 /home/healths/public_html/wp-config.php(99): require_once('/home/healths/p...') #3 /home/healths/public_html/wp-load.php(50): require_once('/home/healths/p...') #4 /home/healths/public_html/wp-blog-header.php(13): require_once('/home/healths/p...') #5 /home/healths/public_html/index.php(17): require('/home/healths/p...') #6 {main} thrown in /home/healths/public_html/wp-includes/option.php on line 231